예제 #1
0
def test_validate_membership_test_mode(event, customer, membership,
                                       requiring_ticket, membership_type):
    with pytest.raises(ValidationError) as excinfo:
        membership.testmode = True
        membership.save()
        validate_memberships_in_order(
            customer,
            [CartPosition(item=requiring_ticket, used_membership=membership)],
            event,
            lock=False,
            ignored_order=None,
            testmode=False,
        )
    assert "test mode" in str(excinfo.value)
    with pytest.raises(ValidationError) as excinfo:
        membership.testmode = False
        membership.save()
        validate_memberships_in_order(
            customer,
            [CartPosition(item=requiring_ticket, used_membership=membership)],
            event,
            lock=False,
            ignored_order=None,
            testmode=True,
        )
    assert "test mode" in str(excinfo.value)
예제 #2
0
def test_validate_membership_max_usages(event, customer, membership,
                                        requiring_ticket, membership_type):
    membership_type.max_usages = 1
    membership_type.allow_parallel_usage = True
    membership_type.save()
    o1 = Order.objects.create(
        status=Order.STATUS_PENDING,
        event=event,
        email='admin@localhost',
        datetime=now() - timedelta(days=3),
        expires=now() + timedelta(days=11),
        total=Decimal("23"),
    )
    OrderPosition.objects.create(order=o1,
                                 item=requiring_ticket,
                                 used_membership=membership,
                                 variation=None,
                                 price=Decimal("23"),
                                 attendee_name_parts={'full_name': "Peter"})

    with pytest.raises(ValidationError) as excinfo:
        validate_memberships_in_order(
            customer,
            [CartPosition(item=requiring_ticket, used_membership=membership)],
            event,
            lock=False,
            ignored_order=None)
    assert "more than 1 time" in str(excinfo.value)
    membership_type.max_usages = 2
    membership_type.save()
    validate_memberships_in_order(
        customer,
        [CartPosition(item=requiring_ticket, used_membership=membership)],
        event,
        lock=False,
        ignored_order=None)

    with pytest.raises(ValidationError) as excinfo:
        validate_memberships_in_order(customer, [
            CartPosition(item=requiring_ticket, used_membership=membership),
            CartPosition(item=requiring_ticket, used_membership=membership),
        ],
                                      event,
                                      lock=False,
                                      ignored_order=None)
    assert "more than 2 times" in str(excinfo.value)
예제 #3
0
파일: cart.py 프로젝트: rahmonov/pretix
    def _perform_operations(self):
        vouchers_ok = self._get_voucher_availability()
        quotas_ok = self._get_quota_availability()
        err = None
        new_cart_positions = []

        self._operations.sort(key=lambda a: self.order[type(a)])

        for op in self._operations:
            if isinstance(op, self.RemoveOperation):
                op.position.delete()

            elif isinstance(op, self.AddOperation) or isinstance(op, self.ExtendOperation):
                # Create a CartPosition for as much items as we can
                requested_count = quota_available_count = voucher_available_count = op.count

                if op.quotas:
                    quota_available_count = min(requested_count, min(quotas_ok[q] for q in op.quotas))

                if op.voucher:
                    voucher_available_count = min(voucher_available_count, vouchers_ok[op.voucher])

                if quota_available_count < 1:
                    err = err or error_messages['unavailable']
                elif quota_available_count < requested_count:
                    err = err or error_messages['in_part']

                if voucher_available_count < 1:
                    err = err or error_messages['voucher_redeemed']
                elif voucher_available_count < requested_count:
                    err = err or error_messages['voucher_redeemed_partial'] % voucher_available_count

                available_count = min(quota_available_count, voucher_available_count)

                for q in op.quotas:
                    quotas_ok[q] -= available_count
                if op.voucher:
                    vouchers_ok[op.voucher] -= available_count

                if isinstance(op, self.AddOperation):
                    for k in range(available_count):
                        new_cart_positions.append(CartPosition(
                            event=self.event, item=op.item, variation=op.variation,
                            price=op.price, expires=self._expiry,
                            cart_id=self.cart_id, voucher=op.voucher
                        ))
                elif isinstance(op, self.ExtendOperation):
                    if available_count == 1:
                        op.position.expires = self._expiry
                        op.position.price = op.price
                        op.position.save()
                    elif available_count == 0:
                        op.position.delete()
                    else:
                        raise AssertionError("ExtendOperation cannot affect more than one item")

        CartPosition.objects.bulk_create(new_cart_positions)
        return err
예제 #4
0
def test_validate_membership_required(event, customer, membership,
                                      requiring_ticket, membership_type):
    with pytest.raises(ValidationError) as excinfo:
        validate_memberships_in_order(customer,
                                      [CartPosition(item=requiring_ticket, )],
                                      event,
                                      lock=False,
                                      ignored_order=None)
    assert "requires an active" in str(excinfo.value)
예제 #5
0
def test_validate_membership_wrong_type(event, customer, membership,
                                        requiring_ticket, membership_type):
    requiring_ticket.require_membership_types.clear()
    with pytest.raises(ValidationError) as excinfo:
        validate_memberships_in_order(
            customer,
            [CartPosition(item=requiring_ticket, used_membership=membership)],
            event,
            lock=False,
            ignored_order=None)
    assert "not allowed for the product" in str(excinfo.value)
예제 #6
0
def test_validate_membership_wrong_customer(event, customer, membership,
                                            requiring_ticket, membership_type):
    customer2 = event.organizer.customers.create(email="*****@*****.**")
    with pytest.raises(ValidationError) as excinfo:
        validate_memberships_in_order(
            customer2,
            [CartPosition(item=requiring_ticket, used_membership=membership)],
            event,
            lock=False,
            ignored_order=None)
    assert "different customer" in str(excinfo.value)
예제 #7
0
def test_validate_membership_wrong_date(event, customer, membership,
                                        requiring_ticket, membership_type):
    membership.date_start -= timedelta(days=100)
    membership.date_end -= timedelta(days=100)
    membership.save()
    with pytest.raises(ValidationError) as excinfo:
        validate_memberships_in_order(
            customer,
            [CartPosition(item=requiring_ticket, used_membership=membership)],
            event,
            lock=False,
            ignored_order=None)
    assert "taking place at" in str(excinfo.value)
예제 #8
0
def test_validate_membership_not_required(event, customer, membership,
                                          granting_ticket, membership_type):
    with pytest.raises(ValidationError) as excinfo:
        validate_memberships_in_order(
            customer,
            [CartPosition(
                item=granting_ticket,
                used_membership=membership,
            )],
            event,
            lock=False,
            ignored_order=None)
    assert "does not require" in str(excinfo.value)
예제 #9
0
def test_validate_membership_ensure_locking(event, customer, membership,
                                            requiring_ticket, membership_type,
                                            django_assert_num_queries):
    with django_assert_num_queries(4) as captured:
        validate_memberships_in_order(customer, [
            CartPosition(
                item=requiring_ticket,
                used_membership=membership,
            )
        ],
                                      event,
                                      lock=True,
                                      ignored_order=None)
    if 'sqlite' not in settings.DATABASES['default']['ENGINE']:
        assert any('FOR UPDATE' in s['sql'] for s in captured)
예제 #10
0
    def create_cart(self, sc, expires):
        with transaction.atomic():
            with self.request.event.lock():
                positions = []
                quotas = Counter()

                for form in self.formset.forms:
                    if '-' in form.cleaned_data['itemvar']:
                        itemid, varid = form.cleaned_data['itemvar'].split('-')
                    else:
                        itemid, varid = form.cleaned_data['itemvar'], None

                    item = Item.objects.get(pk=itemid,
                                            event=self.request.event)
                    variation = ItemVariation.objects.get(
                        pk=varid, item=item) if varid else None
                    price = form.cleaned_data['price']
                    if not price:
                        price = (variation.default_price if variation
                                 and variation.default_price is not None else
                                 item.default_price)

                    for quota in item.quotas.all():
                        quotas[quota] += form.cleaned_data['count']

                    for i in range(form.cleaned_data['count']):
                        positions.append(
                            CartPosition(item=item,
                                         variation=variation,
                                         event=self.request.event,
                                         cart_id=sc.cart_id,
                                         expires=expires,
                                         price=price))

                for quota, diff in quotas.items():
                    avail = quota.availability()
                    if avail[0] != Quota.AVAILABILITY_OK or (
                            avail[1] is not None and avail[1] < diff):
                        raise CartError(self.error_messages['quota'].format(
                            name=quota.name))

                sc.expires = expires
                sc.event = self.request.event
                sc.total = sum([p.price for p in positions])
                sc.save()
                CartPosition.objects.bulk_create(positions)
예제 #11
0
def test_validate_membership_parallel(event, customer, membership, subevent,
                                      requiring_ticket, membership_type):
    se2 = event.subevents.create(
        name='Foo',
        date_from=TZ.localize(datetime(2021, 4, 28, 10, 0, 0, 0)),
    )

    membership_type.allow_parallel_usage = False
    membership_type.save()

    o1 = Order.objects.create(
        status=Order.STATUS_PENDING,
        event=event,
        email='admin@localhost',
        datetime=now() - timedelta(days=3),
        expires=now() + timedelta(days=11),
        total=Decimal("23"),
    )
    OrderPosition.objects.create(order=o1,
                                 item=requiring_ticket,
                                 used_membership=membership,
                                 variation=None,
                                 subevent=subevent,
                                 price=Decimal("23"),
                                 attendee_name_parts={'full_name': "Peter"})

    with pytest.raises(ValidationError) as excinfo:
        validate_memberships_in_order(customer, [
            CartPosition(item=requiring_ticket,
                         used_membership=membership,
                         subevent=subevent)
        ],
                                      event,
                                      lock=False,
                                      ignored_order=None)
    assert "different ticket at the same time" in str(excinfo.value)

    validate_memberships_in_order(customer, [
        CartPosition(
            item=requiring_ticket, used_membership=membership, subevent=se2)
    ],
                                  event,
                                  lock=False,
                                  ignored_order=None)

    with pytest.raises(ValidationError) as excinfo:
        validate_memberships_in_order(customer, [
            CartPosition(item=requiring_ticket,
                         used_membership=membership,
                         subevent=se2),
            CartPosition(item=requiring_ticket,
                         used_membership=membership,
                         subevent=se2)
        ],
                                      event,
                                      lock=False,
                                      ignored_order=None)
    assert "different ticket at the same time" in str(excinfo.value)

    membership_type.allow_parallel_usage = True
    membership_type.save()
    validate_memberships_in_order(customer, [
        CartPosition(item=requiring_ticket,
                     used_membership=membership,
                     subevent=subevent)
    ],
                                  event,
                                  lock=False,
                                  ignored_order=None)
예제 #12
0
파일: cart.py 프로젝트: feitianyiren/pretix
    def _perform_operations(self):
        vouchers_ok = self._get_voucher_availability()
        quotas_ok = self._get_quota_availability()
        err = None
        new_cart_positions = []

        err = err or self._check_min_per_product()

        self._operations.sort(key=lambda a: self.order[type(a)])

        for op in self._operations:
            if isinstance(op, self.RemoveOperation):
                if op.position.expires > self.now_dt:
                    for q in op.position.quotas:
                        quotas_ok[q] += 1
                op.position.addons.all().delete()
                op.position.delete()

            elif isinstance(op, self.AddOperation) or isinstance(
                    op, self.ExtendOperation):
                # Create a CartPosition for as much items as we can
                requested_count = quota_available_count = voucher_available_count = op.count

                if op.quotas:
                    quota_available_count = min(
                        requested_count, min(quotas_ok[q] for q in op.quotas))

                if op.voucher:
                    voucher_available_count = min(voucher_available_count,
                                                  vouchers_ok[op.voucher])

                if quota_available_count < 1:
                    err = err or error_messages['unavailable']
                elif quota_available_count < requested_count:
                    err = err or error_messages['in_part']

                if voucher_available_count < 1:
                    if op.voucher in self._voucher_depend_on_cart:
                        err = err or error_messages[
                            'voucher_redeemed_cart'] % self.event.settings.reservation_time
                    else:
                        err = err or error_messages['voucher_redeemed']
                elif voucher_available_count < requested_count:
                    err = err or error_messages[
                        'voucher_redeemed_partial'] % voucher_available_count

                available_count = min(quota_available_count,
                                      voucher_available_count)

                for q in op.quotas:
                    quotas_ok[q] -= available_count
                if op.voucher:
                    vouchers_ok[op.voucher] -= available_count

                if isinstance(op, self.AddOperation):
                    for k in range(available_count):
                        new_cart_positions.append(
                            CartPosition(
                                event=self.event,
                                item=op.item,
                                variation=op.variation,
                                price=op.price.gross,
                                expires=self._expiry,
                                cart_id=self.cart_id,
                                voucher=op.voucher,
                                addon_to=op.addon_to if op.addon_to else None,
                                subevent=op.subevent,
                                includes_tax=op.includes_tax))
                elif isinstance(op, self.ExtendOperation):
                    if available_count == 1:
                        op.position.expires = self._expiry
                        op.position.price = op.price.gross
                        op.position.save()
                    elif available_count == 0:
                        op.position.delete()
                    else:
                        raise AssertionError(
                            "ExtendOperation cannot affect more than one item")

        CartPosition.objects.bulk_create(new_cart_positions)
        return err
예제 #13
0
파일: cart.py 프로젝트: michaelluk/pretix
    def _perform_operations(self):
        vouchers_ok = self._get_voucher_availability()
        quotas_ok = self._get_quota_availability()
        err = None
        new_cart_positions = []

        err = err or self._check_min_per_product()

        self._operations.sort(key=lambda a: self.order[type(a)])

        for op in self._operations:
            if isinstance(op, self.RemoveOperation):
                if op.position.expires > self.now_dt:
                    for q in op.position.quotas:
                        quotas_ok[q] += 1
                op.position.addons.all().delete()
                op.position.delete()

            elif isinstance(op, self.AddOperation) or isinstance(
                    op, self.ExtendOperation):
                # Create a CartPosition for as much items as we can
                requested_count = quota_available_count = voucher_available_count = op.count

                if op.quotas:
                    quota_available_count = min(
                        requested_count, min(quotas_ok[q] for q in op.quotas))

                if op.voucher:
                    voucher_available_count = min(voucher_available_count,
                                                  vouchers_ok[op.voucher])

                if quota_available_count < 1:
                    err = err or error_messages['unavailable']
                elif quota_available_count < requested_count:
                    err = err or error_messages['in_part']

                if voucher_available_count < 1:
                    if op.voucher in self._voucher_depend_on_cart:
                        err = err or error_messages[
                            'voucher_redeemed_cart'] % self.event.settings.reservation_time
                    else:
                        err = err or error_messages['voucher_redeemed']
                elif voucher_available_count < requested_count:
                    err = err or error_messages[
                        'voucher_redeemed_partial'] % voucher_available_count

                available_count = min(quota_available_count,
                                      voucher_available_count)

                for q in op.quotas:
                    quotas_ok[q] -= available_count
                if op.voucher:
                    vouchers_ok[op.voucher] -= available_count

                if isinstance(op, self.AddOperation):
                    for k in range(available_count):
                        cp = CartPosition(
                            event=self.event,
                            item=op.item,
                            variation=op.variation,
                            price=op.price.gross,
                            expires=self._expiry,
                            cart_id=self.cart_id,
                            voucher=op.voucher,
                            addon_to=op.addon_to if op.addon_to else None,
                            subevent=op.subevent,
                            includes_tax=op.includes_tax)
                        if self.event.settings.attendee_names_asked:
                            scheme = PERSON_NAME_SCHEMES.get(
                                self.event.settings.name_scheme)
                            if 'attendee-name' in self._widget_data:
                                cp.attendee_name_parts = {
                                    '_legacy':
                                    self._widget_data['attendee-name']
                                }
                            if any('attendee-name-{}'.format(
                                    k.replace('_', '-')) in self._widget_data
                                   for k, l, w in scheme['fields']):
                                cp.attendee_name_parts = {
                                    k: self._widget_data.get(
                                        'attendee-name-{}'.format(
                                            k.replace('_', '-')), '')
                                    for k, l, w in scheme['fields']
                                }
                        if self.event.settings.attendee_emails_asked and 'email' in self._widget_data:
                            cp.attendee_email = self._widget_data.get('email')

                        cp._answers = {}
                        for k, v in self._widget_data.items():
                            if not k.startswith('question-'):
                                continue
                            q = cp.item.questions.filter(
                                ask_during_checkin=False,
                                identifier__iexact=k[9:]).first()
                            if q:
                                try:
                                    cp._answers[q] = q.clean_answer(v)
                                except ValidationError:
                                    pass

                        new_cart_positions.append(cp)
                elif isinstance(op, self.ExtendOperation):
                    if available_count == 1:
                        op.position.expires = self._expiry
                        op.position.price = op.price.gross
                        op.position.save()
                    elif available_count == 0:
                        op.position.addons.all().delete()
                        op.position.delete()
                    else:
                        raise AssertionError(
                            "ExtendOperation cannot affect more than one item")

        for p in new_cart_positions:
            if p._answers:
                p.save()
                _save_answers(p, {}, p._answers)
        CartPosition.objects.bulk_create(
            [p for p in new_cart_positions if not p._answers])
        return err