def clean(self): data = super().clean() vouchers = self.instance.event.vouchers.annotate( code_lower=Lower('code') ).filter(code_lower__in=[c.lower() for c in data['codes']]) if vouchers.exists(): raise ValidationError(_('A voucher with one of these codes already exists.')) if data.get('send') and not all([data.get('send_subject'), data.get('send_message'), data.get('send_recipients')]): raise ValidationError(_('If vouchers should be sent by email, subject, message and recipients need to be specified.')) if data.get('codes') and data.get('send'): recp = self.cleaned_data.get('send_recipients', []) code_len = len(data.get('codes')) recp_len = sum(r.number for r in recp) if code_len != recp_len: raise ValidationError(_('You generated {codes} vouchers, but entered recipients for {recp} vouchers.').format(codes=code_len, recp=recp_len)) if data.get('seats'): seatids = [s.strip() for s in data.get('seats').strip().split("\n") if s] if len(seatids) != len(data.get('codes')): raise ValidationError(_('You need to specify as many seats as voucher codes.')) data['seats'] = [] for s in seatids: data['seat'] = s data['seats'].append(Voucher.clean_seat_id( data, self.instance.item, self.instance.quota, self.instance.event, None )) self.instance.seat = data['seats'][0] # Trick model-level validation else: data['seats'] = [] return data
def get_queryset(self): qs = Voucher.annotate_budget_used_orders( self.request.event.vouchers.filter( waitinglistentries__isnull=True).select_related( 'item', 'variation', 'seat')) if self.filter_form.is_valid(): qs = self.filter_form.filter_qs(qs) return qs.distinct()
def get_price(item: Item, variation: ItemVariation = None, voucher: Voucher = None, custom_price: Decimal = None, subevent: SubEvent = None, custom_price_is_net: bool = False, addon_to: AbstractPosition = None, invoice_address: InvoiceAddress = None) -> TaxedPrice: if addon_to: try: iao = addon_to.item.addons.get(addon_category_id=item.category_id) if iao.price_included: return TAXED_ZERO except ItemAddOn.DoesNotExist: pass price = item.default_price if subevent and item.pk in subevent.item_price_overrides: price = subevent.item_price_overrides[item.pk] if variation is not None: if variation.default_price is not None: price = variation.default_price if subevent and variation.pk in subevent.var_price_overrides: price = subevent.var_price_overrides[variation.pk] if voucher: price = voucher.calculate_price(price) if item.tax_rule: tax_rule = item.tax_rule else: tax_rule = TaxRule( name='', rate=Decimal('0.00'), price_includes_tax=True, eu_reverse_charge=False, ) price = tax_rule.tax(price) if item.free_price and custom_price is not None and custom_price != "": if not isinstance(custom_price, Decimal): custom_price = Decimal(str(custom_price).replace(",", ".")) if custom_price > 100000000: raise ValueError('price_too_high') if custom_price_is_net: price = tax_rule.tax(max(custom_price, price.net), base_price_is='net') else: price = tax_rule.tax(max(custom_price, price.gross), base_price_is='gross') if invoice_address and not tax_rule.tax_applicable(invoice_address): price.tax = Decimal('0.00') price.rate = Decimal('0.00') price.gross = price.net price.name = '' price.gross = round_decimal(price.gross, item.event.currency) price.net = round_decimal(price.net, item.event.currency) price.tax = price.gross - price.net return price
def get_form_kwargs(self): kwargs = super().get_form_kwargs() if self.copy_from: i = modelcopy(self.copy_from) i.pk = None kwargs['instance'] = i else: kwargs['instance'] = Voucher(event=self.request.event) return kwargs
def get_price(item: Item, variation: ItemVariation = None, voucher: Voucher = None, custom_price: Decimal = None, subevent: SubEvent = None, custom_price_is_net: bool = False, addon_to: AbstractPosition = None, invoice_address: InvoiceAddress = None) -> TaxedPrice: if addon_to: try: iao = addon_to.item.addons.get(addon_category_id=item.category_id) if iao.price_included: return TAXED_ZERO except ItemAddOn.DoesNotExist: pass price = item.default_price if subevent and item.pk in subevent.item_price_overrides: price = subevent.item_price_overrides[item.pk] if variation is not None: if variation.default_price is not None: price = variation.default_price if subevent and variation.pk in subevent.var_price_overrides: price = subevent.var_price_overrides[variation.pk] if voucher: price = voucher.calculate_price(price) if item.tax_rule: tax_rule = item.tax_rule else: tax_rule = TaxRule( name='', rate=Decimal('0.00'), price_includes_tax=True, eu_reverse_charge=False, ) price = tax_rule.tax(price) if item.free_price and custom_price is not None and custom_price != "": if not isinstance(custom_price, Decimal): custom_price = Decimal(str(custom_price).replace(",", ".")) if custom_price > 100000000: raise ValueError('price_too_high') if custom_price_is_net: price = tax_rule.tax(max(custom_price, price.net), base_price_is='net') else: price = tax_rule.tax(max(custom_price, price.gross), base_price_is='gross') if invoice_address and not tax_rule.tax_applicable(invoice_address): price.tax = Decimal('0.00') price.rate = Decimal('0.00') price.gross = price.net price.name = '' return price
def get_price(item: Item, variation: ItemVariation = None, voucher: Voucher = None, custom_price: Decimal = None, subevent: SubEvent = None, custom_price_is_net: bool = False, addon_to: AbstractPosition = None): if addon_to: try: iao = addon_to.item.addons.get(addon_category_id=item.category_id) if iao.price_included: return Decimal('0.00') except ItemAddOn.DoesNotExist: pass price = item.default_price if subevent and item.pk in subevent.item_price_overrides: price = subevent.item_price_overrides[item.pk] if variation is not None: if variation.default_price is not None: price = variation.default_price if subevent and variation.pk in subevent.var_price_overrides: price = subevent.var_price_overrides[variation.pk] if voucher: price = voucher.calculate_price(price) if item.free_price and custom_price is not None and custom_price != "": if not isinstance(custom_price, Decimal): custom_price = Decimal(str(custom_price).replace(",", ".")) if custom_price > 100000000: raise ValueError('price_too_high') if custom_price_is_net: custom_price = round_decimal(custom_price * (100 + item.tax_rate) / 100) price = max(custom_price, price) return price
def clean(self): data = super().clean() if not self._errors: try: itemid = quotaid = None iv = self.data.get('itemvar', '') if iv.startswith('q-'): quotaid = iv[2:] elif '-' in iv: itemid, varid = iv.split('-') else: itemid, varid = iv, None if itemid: self.instance.item = self.instance.event.items.get( pk=itemid) if varid: self.instance.variation = self.instance.item.variations.get( pk=varid) else: self.instance.variation = None self.instance.quota = None else: self.instance.quota = self.instance.event.quotas.get( pk=quotaid) self.instance.item = None self.instance.variation = None except ObjectDoesNotExist: raise ValidationError(_("Invalid product selected.")) if 'codes' in data: data['codes'] = [ a.strip() for a in data.get('codes', '').strip().split("\n") if a ] cnt = len(data['codes']) * data['max_usages'] else: cnt = data['max_usages'] Voucher.clean_item_properties(data, self.instance.event, self.instance.quota, self.instance.item, self.instance.variation) Voucher.clean_subevent(data, self.instance.event) Voucher.clean_max_usages(data, self.instance.redeemed) check_quota = Voucher.clean_quota_needs_checking( data, self.initial_instance_data, item_changed=data.get('itemvar') != self.initial.get('itemvar'), creating=not self.instance.pk) if check_quota: Voucher.clean_quota_check(data, cnt, self.initial_instance_data, self.instance.event, self.instance.quota, self.instance.item, self.instance.variation) Voucher.clean_voucher_code(data, self.instance.event, self.instance.pk) voucher_form_validation.send(sender=self.instance.event, form=self, data=data) return data
def validate(self, data): data = super().validate(data) full_data = self.to_internal_value( self.to_representation(self.instance)) if self.instance else {} full_data.update(data) Voucher.clean_item_properties(full_data, self.context.get('event'), full_data.get('quota'), full_data.get('item'), full_data.get('variation')) Voucher.clean_subevent(full_data, self.context.get('event')) Voucher.clean_max_usages( full_data, self.instance.redeemed if self.instance else 0) check_quota = Voucher.clean_quota_needs_checking( full_data, self.instance, item_changed=self.instance and (full_data.get('item') != self.instance.item or full_data.get('variation') != self.instance.variation or full_data.get('quota') != self.instance.quota), creating=not self.instance) if check_quota: Voucher.clean_quota_check(full_data, 1, self.instance, self.context.get('event'), full_data.get('quota'), full_data.get('item'), full_data.get('variation')) Voucher.clean_voucher_code(full_data, self.context.get('event'), self.instance.pk if self.instance else None) if full_data.get('seat'): data['seat'] = Voucher.clean_seat_id( full_data, full_data.get('item'), full_data.get('quota'), self.context.get('event'), self.instance.pk if self.instance else None) return data
def get_async_form_kwargs(self, form_kwargs, organizer=None, event=None): if not form_kwargs.get('instance'): form_kwargs['instance'] = Voucher(event=self.request.event, code=None) return form_kwargs
def validate(self, data): data = super().validate(data) full_data = self.to_internal_value(self.to_representation(self.instance)) if self.instance else {} full_data.update(data) Voucher.clean_item_properties( full_data, self.context.get('event'), full_data.get('quota'), full_data.get('item'), full_data.get('variation') ) Voucher.clean_subevent( full_data, self.context.get('event') ) Voucher.clean_max_usages(full_data, self.instance.redeemed if self.instance else 0) check_quota = Voucher.clean_quota_needs_checking( full_data, self.instance, item_changed=self.instance and ( full_data.get('item') != self.instance.item or full_data.get('variation') != self.instance.variation or full_data.get('quota') != self.instance.quota ), creating=not self.instance ) if check_quota: Voucher.clean_quota_check( full_data, 1, self.instance, self.context.get('event'), full_data.get('quota'), full_data.get('item'), full_data.get('variation') ) Voucher.clean_voucher_code(full_data, self.context.get('event'), self.instance.pk if self.instance else None) return data
def clean(self): data = super().clean() if not self._errors: try: itemid = quotaid = None iv = self.data.get('itemvar', '') if iv.startswith('q-'): quotaid = iv[2:] elif '-' in iv: itemid, varid = iv.split('-') else: itemid, varid = iv, None if itemid: self.instance.item = self.instance.event.items.get( pk=itemid) if varid: self.instance.variation = self.instance.item.variations.get( pk=varid) else: self.instance.variation = None self.instance.quota = None else: self.instance.quota = self.instance.event.quotas.get( pk=quotaid) self.instance.item = None self.instance.variation = None except ObjectDoesNotExist: raise ValidationError(_("Invalid product selected.")) if 'codes' in data: data['codes'] = [ a.strip() for a in data.get('codes', '').strip().split("\n") if a ] cnt = len(data['codes']) * data.get('max_usages', 0) else: cnt = data.get('max_usages', 0) Voucher.clean_item_properties(data, self.instance.event, self.instance.quota, self.instance.item, self.instance.variation) if not self.instance.show_hidden_items and ( (self.instance.quota and all(i.hide_without_voucher for i in self.instance.quota.items.all())) or (self.instance.item and self.instance.item.hide_without_voucher)): raise ValidationError({ 'show_hidden_items': [ _('The voucher only matches hidden products but you have not selected that it should show ' 'them.') ] }) Voucher.clean_subevent(data, self.instance.event) Voucher.clean_max_usages(data, self.instance.redeemed) check_quota = Voucher.clean_quota_needs_checking( data, self.initial_instance_data, item_changed=data.get('itemvar') != self.initial.get('itemvar'), creating=not self.instance.pk) if check_quota: Voucher.clean_quota_check(data, cnt, self.initial_instance_data, self.instance.event, self.instance.quota, self.instance.item, self.instance.variation) Voucher.clean_voucher_code(data, self.instance.event, self.instance.pk) voucher_form_validation.send(sender=self.instance.event, form=self, data=data) return data
def test_voucher_specify_variation_for_block_quota(self): with self.assertRaises(ValidationError): v = Voucher(item=self.item2, block_quota=True, event=self.event) v.clean()
def test_voucher_item_does_not_match_variation(self): with self.assertRaises(ValidationError): v = Voucher(item=self.item2, variation=self.var3, event=self.event) v.clean()
def test_voucher_no_item_with_quota(self): with self.assertRaises(ValidationError): v = Voucher(quota=self.quota, item=self.item1, event=self.event) v.clean()
def clean(self): data = super().clean() if not self._errors: try: itemid = quotaid = None iv = self.data.get('itemvar', '') if iv.startswith('q-'): quotaid = iv[2:] elif '-' in iv: itemid, varid = iv.split('-') else: itemid, varid = iv, None if itemid: self.instance.item = self.instance.event.items.get(pk=itemid) if varid: self.instance.variation = self.instance.item.variations.get(pk=varid) else: self.instance.variation = None self.instance.quota = None else: self.instance.quota = self.instance.event.quotas.get(pk=quotaid) self.instance.item = None self.instance.variation = None except ObjectDoesNotExist: raise ValidationError(_("Invalid product selected.")) if 'codes' in data: data['codes'] = [a.strip() for a in data.get('codes', '').strip().split("\n") if a] cnt = len(data['codes']) * data.get('max_usages', 0) else: cnt = data['max_usages'] Voucher.clean_item_properties( data, self.instance.event, self.instance.quota, self.instance.item, self.instance.variation ) Voucher.clean_subevent( data, self.instance.event ) Voucher.clean_max_usages(data, self.instance.redeemed) check_quota = Voucher.clean_quota_needs_checking( data, self.initial_instance_data, item_changed=data.get('itemvar') != self.initial.get('itemvar'), creating=not self.instance.pk ) if check_quota: Voucher.clean_quota_check( data, cnt, self.initial_instance_data, self.instance.event, self.instance.quota, self.instance.item, self.instance.variation ) Voucher.clean_voucher_code(data, self.instance.event, self.instance.pk) voucher_form_validation.send(sender=self.instance.event, form=self, data=data) return data
def get_form_kwargs(self): kwargs = super().get_form_kwargs() kwargs['instance'] = Voucher(event=self.request.event) return kwargs
def test_voucher_no_item_but_variation(self): with self.assertRaises(ValidationError): v = Voucher(variation=self.var1, event=self.event) v.clean()
def get_price(item: Item, variation: ItemVariation = None, voucher: Voucher = None, custom_price: Decimal = None, subevent: SubEvent = None, custom_price_is_net: bool = False, custom_price_is_tax_rate: Decimal=None, addon_to: AbstractPosition = None, invoice_address: InvoiceAddress = None, force_custom_price: bool = False, bundled_sum: Decimal = Decimal('0.00'), max_discount: Decimal = None, tax_rule=None) -> TaxedPrice: if addon_to: try: iao = addon_to.item.addons.get(addon_category_id=item.category_id) if iao.price_included: return TAXED_ZERO except ItemAddOn.DoesNotExist: pass price = item.default_price if subevent and item.pk in subevent.item_price_overrides: price = subevent.item_price_overrides[item.pk] if variation is not None: if variation.default_price is not None: price = variation.default_price if subevent and variation.pk in subevent.var_price_overrides: price = subevent.var_price_overrides[variation.pk] if voucher: price = voucher.calculate_price(price, max_discount=max_discount) if tax_rule is not None: tax_rule = tax_rule elif item.tax_rule: tax_rule = item.tax_rule else: tax_rule = TaxRule( name='', rate=Decimal('0.00'), price_includes_tax=True, eu_reverse_charge=False, ) if force_custom_price and custom_price is not None and custom_price != "": if custom_price_is_net: price = tax_rule.tax(custom_price, base_price_is='net', invoice_address=invoice_address, subtract_from_gross=bundled_sum) else: price = tax_rule.tax(custom_price, base_price_is='gross', invoice_address=invoice_address, subtract_from_gross=bundled_sum) elif item.free_price and custom_price is not None and custom_price != "": if not isinstance(custom_price, Decimal): custom_price = Decimal(str(custom_price).replace(",", ".")) if custom_price > 100000000: raise ValueError('price_too_high') price = tax_rule.tax(price, invoice_address=invoice_address) if custom_price_is_net: price = tax_rule.tax(max(custom_price, price.net), base_price_is='net', invoice_address=invoice_address, subtract_from_gross=bundled_sum) else: price = tax_rule.tax(max(custom_price, price.gross), base_price_is='gross', gross_price_is_tax_rate=custom_price_is_tax_rate, invoice_address=invoice_address, subtract_from_gross=bundled_sum) else: price = tax_rule.tax(price, invoice_address=invoice_address, subtract_from_gross=bundled_sum) price.gross = round_decimal(price.gross, item.event.currency) price.net = round_decimal(price.net, item.event.currency) price.tax = price.gross - price.net return price
def clean(self): data = super().clean() if not self._errors: try: itemid = quotaid = None iv = self.data.get('itemvar', '') if iv.startswith('q-'): quotaid = iv[2:] elif '-' in iv: itemid, varid = iv.split('-') else: itemid, varid = iv, None if itemid: self.instance.item = self.instance.event.items.get(pk=itemid) if varid: self.instance.variation = self.instance.item.variations.get(pk=varid) else: self.instance.variation = None self.instance.quota = None else: self.instance.quota = self.instance.event.quotas.get(pk=quotaid) self.instance.item = None self.instance.variation = None except ObjectDoesNotExist: raise ValidationError(_("Invalid product selected.")) if 'codes' in data: data['codes'] = [a.strip() for a in data.get('codes', '').strip().split("\n") if a] cnt = len(data['codes']) * data.get('max_usages', 0) else: cnt = data.get('max_usages', 0) Voucher.clean_item_properties( data, self.instance.event, self.instance.quota, self.instance.item, self.instance.variation ) if self.instance.quota: if all(i.hide_without_voucher for i in self.instance.quota.items.all()): raise ValidationError({ 'itemvar': [ _('The quota you selected only contains hidden products. Hidden products can currently only be ' 'shown by using vouchers that directly apply to the product, not via a quota.') ] }) Voucher.clean_subevent( data, self.instance.event ) Voucher.clean_max_usages(data, self.instance.redeemed) check_quota = Voucher.clean_quota_needs_checking( data, self.initial_instance_data, item_changed=data.get('itemvar') != self.initial.get('itemvar'), creating=not self.instance.pk ) if check_quota: Voucher.clean_quota_check( data, cnt, self.initial_instance_data, self.instance.event, self.instance.quota, self.instance.item, self.instance.variation ) Voucher.clean_voucher_code(data, self.instance.event, self.instance.pk) voucher_form_validation.send(sender=self.instance.event, form=self, data=data) return data