Пример #1
0
    def tax(self, base_price, base_price_is='auto'):
        if self.rate == Decimal('0.00'):
            return TaxedPrice(net=base_price,
                              gross=base_price,
                              tax=Decimal('0.00'),
                              rate=self.rate,
                              name=self.name)

        if base_price_is == 'auto':
            if self.price_includes_tax:
                base_price_is = 'gross'
            else:
                base_price_is = 'net'

        if base_price_is == 'gross':
            gross = base_price
            net = round_decimal(
                gross - (base_price * (1 - 100 / (100 + self.rate))),
                self.event.currency if self.event else None)
        elif base_price_is == 'net':
            net = base_price
            gross = round_decimal((net * (1 + self.rate / 100)),
                                  self.event.currency if self.event else None)
        else:
            raise ValueError(
                'Unknown base price type: {}'.format(base_price_is))

        return TaxedPrice(net=net,
                          gross=gross,
                          tax=gross - net,
                          rate=self.rate,
                          name=self.name)
Пример #2
0
    def tax(self, base_price, base_price_is='auto', currency=None):
        from .event import Event
        try:
            currency = currency or self.event.currency
        except Event.DoesNotExist:
            pass
        if self.rate == Decimal('0.00'):
            return TaxedPrice(
                net=base_price, gross=base_price, tax=Decimal('0.00'),
                rate=self.rate, name=self.name
            )

        if base_price_is == 'auto':
            if self.price_includes_tax:
                base_price_is = 'gross'
            else:
                base_price_is = 'net'

        if base_price_is == 'gross':
            gross = base_price
            net = round_decimal(gross - (base_price * (1 - 100 / (100 + self.rate))),
                                currency)
        elif base_price_is == 'net':
            net = base_price
            gross = round_decimal((net * (1 + self.rate / 100)),
                                  currency)
        else:
            raise ValueError('Unknown base price type: {}'.format(base_price_is))

        return TaxedPrice(
            net=net, gross=gross, tax=gross - net,
            rate=self.rate, name=self.name
        )
Пример #3
0
    def tax(self, base_price, base_price_is='auto'):
        if self.rate == Decimal('0.00'):
            return TaxedPrice(
                net=base_price, gross=base_price, tax=Decimal('0.00'),
                rate=self.rate, name=self.name
            )

        if base_price_is == 'auto':
            if self.price_includes_tax:
                base_price_is = 'gross'
            else:
                base_price_is = 'net'

        if base_price_is == 'gross':
            gross = base_price
            net = round_decimal(gross - (base_price * (1 - 100 / (100 + self.rate))),
                                self.event.currency if self.event else None)
        elif base_price_is == 'net':
            net = base_price
            gross = round_decimal((net * (1 + self.rate / 100)),
                                  self.event.currency if self.event else None)
        else:
            raise ValueError('Unknown base price type: {}'.format(base_price_is))

        return TaxedPrice(
            net=net, gross=gross, tax=gross - net,
            rate=self.rate, name=self.name
        )
Пример #4
0
    def tax(self, base_price, base_price_is='auto', currency=None):
        from .event import Event
        try:
            currency = currency or self.event.currency
        except Event.DoesNotExist:
            pass
        if self.rate == Decimal('0.00'):
            return TaxedPrice(
                net=base_price, gross=base_price, tax=Decimal('0.00'),
                rate=self.rate, name=self.name
            )

        if base_price_is == 'auto':
            if self.price_includes_tax:
                base_price_is = 'gross'
            else:
                base_price_is = 'net'

        if base_price_is == 'gross':
            gross = base_price
            net = round_decimal(gross - (base_price * (1 - 100 / (100 + self.rate))),
                                currency)
        elif base_price_is == 'net':
            net = base_price
            gross = round_decimal((net * (1 + self.rate / 100)),
                                  currency)
        else:
            raise ValueError('Unknown base price type: {}'.format(base_price_is))

        return TaxedPrice(
            net=net, gross=gross, tax=gross - net,
            rate=self.rate, name=self.name
        )
Пример #5
0
    def tax(self, base_price, base_price_is='auto', currency=None, override_tax_rate=None, invoice_address=None,
            subtract_from_gross=Decimal('0.00'), gross_price_is_tax_rate: Decimal = None):
        from .event import Event
        try:
            currency = currency or self.event.currency
        except Event.DoesNotExist:
            pass

        rate = Decimal(self.rate)
        if override_tax_rate is not None:
            rate = override_tax_rate
        elif invoice_address:
            adjust_rate = self.tax_rate_for(invoice_address)
            if adjust_rate == gross_price_is_tax_rate and base_price_is == 'gross':
                rate = adjust_rate
            elif adjust_rate != rate:
                normal_price = self.tax(base_price, base_price_is, currency, subtract_from_gross=subtract_from_gross)
                base_price = normal_price.net
                base_price_is = 'net'
                subtract_from_gross = Decimal('0.00')
                rate = adjust_rate

        if rate == Decimal('0.00'):
            return TaxedPrice(
                net=base_price - subtract_from_gross, gross=base_price - subtract_from_gross, tax=Decimal('0.00'),
                rate=rate, name=self.name
            )

        if base_price_is == 'auto':
            if self.price_includes_tax:
                base_price_is = 'gross'
            else:
                base_price_is = 'net'

        if base_price_is == 'gross':
            if base_price >= Decimal('0.00'):
                # For positive prices, make sure they don't go negative because of bundles
                gross = max(Decimal('0.00'), base_price - subtract_from_gross)
            else:
                # If the price is already negative, we don't really care any more
                gross = base_price - subtract_from_gross
            net = round_decimal(gross - (gross * (1 - 100 / (100 + rate))),
                                currency)
        elif base_price_is == 'net':
            net = base_price
            gross = round_decimal((net * (1 + rate / 100)), currency)
            if subtract_from_gross:
                gross -= subtract_from_gross
                net = round_decimal(gross - (gross * (1 - 100 / (100 + rate))),
                                    currency)
        else:
            raise ValueError('Unknown base price type: {}'.format(base_price_is))

        return TaxedPrice(
            net=net, gross=gross, tax=gross - net,
            rate=rate, name=self.name
        )
Пример #6
0
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
Пример #7
0
def parse(file):
    data = file.read()
    try:
        import chardet

        charset = chardet.detect(data)['encoding']
    except ImportError:
        charset = file.charset
    data = data.decode(charset or 'utf-8')
    mt = mt940.parse(io.StringIO(data.strip()))
    result = []
    for t in mt:
        td = t.data.get('transaction_details', '')
        if len(td) >= 4 and td[3] == '?':
            # SEPA content
            transaction_details = parse_transaction_details(
                td.replace("\n", ""))

            payer = {
                'name': transaction_details.get('accountholder', ''),
                'iban': transaction_details.get('accountnumber', ''),
            }
            reference, eref = join_reference(
                transaction_details.get('reference', '').split('\n'), payer)
            if not eref:
                eref = transaction_details.get('eref', '')

            result.append({
                'amount':
                str(round_decimal(t.data['amount'].amount)),
                'reference':
                reference + (' EREF: {}'.format(eref) if eref else ''),
                'payer':
                payer['name'].strip(),
                'date':
                t.data['date'].isoformat(),
                **{
                    k: payer[k].strip()
                    for k in ("iban", "bic") if payer.get(k)
                }
            })
        else:
            result.append({
                'reference':
                "\n".join([
                    t.data.get(f)
                    for f in ('transaction_details', 'customer_reference',
                              'bank_reference', 'extra_details',
                              'non_swift_text') if t.data.get(f, '')
                ]),
                'amount':
                str(round_decimal(t.data['amount'].amount)),
                'date':
                t.data['date'].isoformat()
            })
    return result
Пример #8
0
 def format_price(self, value):
     return str(
         round_decimal(
             value,
             self.event.currency,
             {
                 # PayPal behaves differently than Stripe in deciding what currencies have decimal places
                 # Source https://developer.paypal.com/docs/classic/api/currency_codes/
                 'HUF': 0,
                 'JPY': 0,
                 'MYR': 0,
                 'TWD': 0,
                 # However, CLPs are not listed there while PayPal requires us not to send decimal places there. WTF.
                 'CLP': 0,
                 # Let's just guess that the ones listed here are 0-based as well
                 # https://developers.braintreepayments.com/reference/general/currencies
                 'BIF': 0,
                 'DJF': 0,
                 'GNF': 0,
                 'KMF': 0,
                 'KRW': 0,
                 'LAK': 0,
                 'PYG': 0,
                 'RWF': 0,
                 'UGX': 0,
                 'VND': 0,
                 'VUV': 0,
                 'XAF': 0,
                 'XOF': 0,
                 'XPF': 0,
             }))
Пример #9
0
 def format_price(self, value):
     return str(round_decimal(value, self.event.currency, {
         # PayPal behaves differently than Stripe in deciding what currencies have decimal places
         # Source https://developer.paypal.com/docs/classic/api/currency_codes/
         'HUF': 0,
         'JPY': 0,
         'MYR': 0,
         'TWD': 0,
         # However, CLPs are not listed there while PayPal requires us not to send decimal places there. WTF.
         'CLP': 0,
         # Let's just guess that the ones listed here are 0-based as well
         # https://developers.braintreepayments.com/reference/general/currencies
         'BIF': 0,
         'DJF': 0,
         'GNF': 0,
         'KMF': 0,
         'KRW': 0,
         'LAK': 0,
         'PYG': 0,
         'RWF': 0,
         'UGX': 0,
         'VND': 0,
         'VUV': 0,
         'XAF': 0,
         'XOF': 0,
         'XPF': 0,
     }))
Пример #10
0
    def calculate_fee(self, price: Decimal) -> Decimal:
        """
        Calculate the fee for this payment provider which will be added to
        final price before fees (but after taxes). It should include any taxes.
        The default implementation makes use of the setting ``_fee_abs`` for an
        absolute fee and ``_fee_percent`` for a percentage.

        :param price: The total value without the payment method fee, after taxes.
        """
        fee_abs = self.settings.get('_fee_abs', as_type=Decimal, default=0)
        fee_percent = self.settings.get('_fee_percent', as_type=Decimal, default=0)
        fee_reverse_calc = self.settings.get('_fee_reverse_calc', as_type=bool, default=True)
        if fee_reverse_calc:
            return round_decimal((price + fee_abs) * (1 / (1 - fee_percent / 100)) - price)
        else:
            return round_decimal(price * fee_percent / 100) + fee_abs
Пример #11
0
    def calculate_fee(self, price: Decimal) -> Decimal:
        """
        Calculate the fee for this payment provider which will be added to
        final price before fees (but after taxes). It should include any taxes.
        The default implementation makes use of the setting ``_fee_abs`` for an
        absolute fee and ``_fee_percent`` for a percentage.

        :param price: The total value without the payment method fee, after taxes.
        """
        fee_abs = self.settings.get('_fee_abs', as_type=Decimal, default=0)
        fee_percent = self.settings.get('_fee_percent', as_type=Decimal, default=0)
        fee_reverse_calc = self.settings.get('_fee_reverse_calc', as_type=bool, default=True)
        if fee_reverse_calc:
            return round_decimal((price + fee_abs) * (1 / (1 - fee_percent / 100)) - price)
        else:
            return round_decimal(price * fee_percent / 100) + fee_abs
Пример #12
0
def parse(file):
    data = file.read()
    try:
        import chardet

        charset = chardet.detect(data)['encoding']
    except ImportError:
        charset = file.charset
    data = data.decode(charset or 'utf-8')
    mt = mt940.parse(io.StringIO(data.strip()))
    result = []
    for t in mt:
        result.append({
            'reference':
            "\n".join([
                t.data.get(f)
                for f in ('transaction_details', 'customer_reference',
                          'bank_reference', 'extra_details', 'non_swift_text')
                if t.data.get(f, '')
            ]),
            'amount':
            str(round_decimal(t.data['amount'].amount)),
            'date':
            t.data['date'].isoformat()
        })
    return result
Пример #13
0
def get_fees(event,
             total,
             invoice_address,
             mod='',
             request=None,
             positions=[]):
    if request is not None and not positions:
        positions = get_cart(request)
    positions = [
        pos for pos in positions
        if not pos.addon_to and pos.price != Decimal('0.00')
    ]

    fee_per_ticket = event.settings.get('service_fee_per_ticket' + mod,
                                        as_type=Decimal)
    if mod and fee_per_ticket is None:
        fee_per_ticket = event.settings.get('service_fee_per_ticket',
                                            as_type=Decimal)

    fee_abs = event.settings.get('service_fee_abs' + mod, as_type=Decimal)
    if mod and fee_abs is None:
        fee_abs = event.settings.get('service_fee_abs', as_type=Decimal)

    fee_percent = event.settings.get('service_fee_percent' + mod,
                                     as_type=Decimal)
    if mod and fee_percent is None:
        fee_percent = event.settings.get('service_fee_percent',
                                         as_type=Decimal)

    fee_per_ticket = Decimal("0") if fee_per_ticket is None else fee_per_ticket
    fee_abs = Decimal("0") if fee_abs is None else fee_abs
    fee_percent = Decimal("0") if fee_percent is None else fee_percent

    if (fee_per_ticket or fee_abs or fee_percent) and total != Decimal('0.00'):
        fee = round_decimal(
            fee_abs + total * (fee_percent / 100) +
            len(positions) * fee_per_ticket, event.currency)
        tax_rule = event.settings.tax_rate_default or TaxRule.zero()
        if tax_rule.tax_applicable(invoice_address):
            tax = tax_rule.tax(fee)
            return [
                OrderFee(fee_type=OrderFee.FEE_TYPE_SERVICE,
                         internal_type='',
                         value=fee,
                         tax_rate=tax.rate,
                         tax_value=tax.tax,
                         tax_rule=tax_rule)
            ]
        else:
            return [
                OrderFee(fee_type=OrderFee.FEE_TYPE_SERVICE,
                         internal_type='',
                         value=fee,
                         tax_rate=Decimal('0.00'),
                         tax_value=Decimal('0.00'),
                         tax_rule=tax_rule)
            ]
    return []
Пример #14
0
 def test_change_price_success(self):
     self.ocm.change_price(self.op1, Decimal('24.00'))
     self.ocm.commit()
     self.op1.refresh_from_db()
     self.order.refresh_from_db()
     assert self.op1.item == self.ticket
     assert self.op1.price == Decimal('24.00')
     assert round_decimal(self.op1.price * (1 - 100 / (100 + self.op1.tax_rate))) == self.op1.tax_value
     assert self.order.total == self.op1.price + self.op2.price
Пример #15
0
 def test_change_price_success(self):
     self.ocm.change_price(self.op1, Decimal('24.00'))
     self.ocm.commit()
     self.op1.refresh_from_db()
     self.order.refresh_from_db()
     assert self.op1.item == self.ticket
     assert self.op1.price == Decimal('24.00')
     assert round_decimal(self.op1.price * (1 - 100 / (100 + self.op1.tax_rate))) == self.op1.tax_value
     assert self.order.total == self.op1.price + self.op2.price
Пример #16
0
 def test_change_item_success(self):
     self.ocm.change_item(self.op1, self.shirt, None)
     self.ocm.commit()
     self.op1.refresh_from_db()
     self.order.refresh_from_db()
     assert self.op1.item == self.shirt
     assert self.op1.price == self.shirt.default_price
     assert self.op1.tax_rate == self.shirt.tax_rule.rate
     assert round_decimal(self.op1.price * (1 - 100 / (100 + self.op1.tax_rate))) == self.op1.tax_value
     assert self.order.total == self.op1.price + self.op2.price
Пример #17
0
 def test_change_item_success(self):
     self.ocm.change_item(self.op1, self.shirt, None)
     self.ocm.commit()
     self.op1.refresh_from_db()
     self.order.refresh_from_db()
     assert self.op1.item == self.shirt
     assert self.op1.price == self.shirt.default_price
     assert self.op1.tax_rate == self.shirt.tax_rate
     assert round_decimal(self.op1.price * (1 - 100 / (100 + self.op1.tax_rate))) == self.op1.tax_value
     assert self.order.total == self.op1.price + self.op2.price
Пример #18
0
 def test_payment_fee_calculation(self):
     self.event.settings.set('tax_rate_default', Decimal('19.00'))
     prov = self.ocm._get_payment_provider()
     prov.settings.set('_fee_abs', Decimal('0.30'))
     self.ocm.change_price(self.op1, Decimal('24.00'))
     self.ocm.commit()
     self.order.refresh_from_db()
     assert self.order.total == Decimal('47.30')
     assert self.order.payment_fee == prov.calculate_fee(self.order.total)
     assert self.order.payment_fee_tax_rate == Decimal('19.00')
     assert round_decimal(self.order.payment_fee * (1 - 100 / (100 + self.order.payment_fee_tax_rate))) == self.order.payment_fee_tax_value
Пример #19
0
 def test_payment_fee_calculation(self):
     self.event.settings.set('tax_rate_default', Decimal('19.00'))
     prov = self.ocm._get_payment_provider()
     prov.settings.set('_fee_abs', Decimal('0.30'))
     self.ocm.change_price(self.op1, Decimal('24.00'))
     self.ocm.commit()
     self.order.refresh_from_db()
     assert self.order.total == Decimal('47.30')
     assert self.order.payment_fee == prov.calculate_fee(self.order.total)
     assert self.order.payment_fee_tax_rate == Decimal('19.00')
     assert round_decimal(self.order.payment_fee * (1 - 100 / (100 + self.order.payment_fee_tax_rate))) == self.order.payment_fee_tax_value
Пример #20
0
 def test_change_price_net_success(self):
     self.tr7.price_includes_tax = False
     self.tr7.save()
     self.ocm.change_price(self.op1, Decimal('10.00'))
     self.ocm.commit()
     self.op1.refresh_from_db()
     self.order.refresh_from_db()
     assert self.op1.item == self.ticket
     assert self.op1.price == Decimal('10.70')
     assert round_decimal(self.op1.price * (1 - 100 / (100 + self.op1.tax_rate))) == self.op1.tax_value
     assert self.order.total == self.op1.price + self.op2.price
Пример #21
0
 def test_add_item_custom_price(self):
     self.ocm.add_position(self.shirt, None, Decimal('13.00'), None)
     self.ocm.commit()
     self.order.refresh_from_db()
     assert self.order.positions.count() == 3
     nop = self.order.positions.last()
     assert nop.item == self.shirt
     assert nop.price == Decimal('13.00')
     assert nop.tax_rate == self.shirt.tax_rule.rate
     assert round_decimal(nop.price * (1 - 100 / (100 + self.shirt.tax_rule.rate))) == nop.tax_value
     assert self.order.total == self.op1.price + self.op2.price + nop.price
Пример #22
0
 def test_change_item_net_price_success(self):
     self.tr19.price_includes_tax = False
     self.tr19.save()
     self.ocm.change_item(self.op1, self.shirt, None)
     self.ocm.commit()
     self.op1.refresh_from_db()
     self.order.refresh_from_db()
     assert self.op1.item == self.shirt
     assert self.op1.price == Decimal('14.28')
     assert self.op1.tax_rate == self.shirt.tax_rule.rate
     assert round_decimal(self.op1.price * (1 - 100 / (100 + self.op1.tax_rate))) == self.op1.tax_value
     assert self.order.total == self.op1.price + self.op2.price
Пример #23
0
 def test_add_item_success(self):
     self.ocm.add_position(self.shirt, None, None, None)
     self.ocm.commit()
     self.order.refresh_from_db()
     assert self.order.positions.count() == 3
     nop = self.order.positions.last()
     assert nop.item == self.shirt
     assert nop.price == self.shirt.default_price
     assert nop.tax_rate == self.shirt.tax_rate
     assert round_decimal(nop.price * (1 - 100 / (100 + self.shirt.tax_rate))) == nop.tax_value
     assert self.order.total == self.op1.price + self.op2.price + nop.price
     assert nop.positionid == 3
Пример #24
0
 def __mul__(self, other):
     newgross = self.gross * other
     newnet = round_decimal(newgross - (newgross * (1 - 100 / (100 + self.rate)))).quantize(
         Decimal('10') ** self.gross.as_tuple().exponent
     )
     return TaxedPrice(
         gross=newgross,
         net=newnet,
         tax=newgross - newnet,
         rate=self.rate,
         name=self.name,
     )
Пример #25
0
 def test_payment_fee_calculation(self):
     self.event.settings.set('tax_rate_default', self.tr19.pk)
     prov = self.ocm._get_payment_provider()
     prov.settings.set('_fee_abs', Decimal('0.30'))
     self.ocm.change_price(self.op1, Decimal('24.00'))
     self.ocm.commit()
     self.order.refresh_from_db()
     assert self.order.total == Decimal('47.30')
     fee = self.order.fees.get(fee_type=OrderFee.FEE_TYPE_PAYMENT)
     assert fee.value == prov.calculate_fee(self.order.total)
     assert fee.tax_rate == Decimal('19.00')
     assert round_decimal(fee.value * (1 - 100 / (100 + fee.tax_rate))) == fee.tax_value
Пример #26
0
 def __mul__(self, other):
     newgross = self.gross * other
     newnet = round_decimal(
         newgross - (newgross * (1 - 100 / (100 + self.rate)))).quantize(
             Decimal('10')**self.gross.as_tuple().exponent)
     return TaxedPrice(
         gross=newgross,
         net=newnet,
         tax=newgross - newnet,
         rate=self.rate,
         name=self.name,
     )
Пример #27
0
def parse(file):
    data = file.read()
    try:
        import chardet

        charset = chardet.detect(data)['encoding']
    except ImportError:
        charset = file.charset
    data = data.decode(charset or 'utf-8')
    mt = mt940.parse(io.StringIO(data.strip()))
    result = []
    for t in mt:
        td = t.data.get('transaction_details', '')
        if len(td) >= 4 and td[3] == '?':
            # SEPA content
            transaction_details = parse_transaction_details(td.replace("\n", ""))

            payer = {
                'name': transaction_details.get('accountholder', ''),
                'iban': transaction_details.get('accountnumber', ''),
            }
            reference, eref = join_reference(transaction_details.get('reference', '').split('\n'), payer)
            if not eref:
                eref = transaction_details.get('eref', '')

            result.append({
                'amount': str(round_decimal(t.data['amount'].amount)),
                'reference': reference + (' EREF: {}'.format(eref) if eref else ''),
                'payer': (payer.get('name', '') + ' - ' + payer.get('iban', '')).strip(),
                'date': t.data['date'].isoformat()
            })
        else:
            result.append({
                'reference': "\n".join([
                    t.data.get(f) for f in ('transaction_details', 'customer_reference', 'bank_reference',
                                            'extra_details', 'non_swift_text') if t.data.get(f, '')]),
                'amount': str(round_decimal(t.data['amount'].amount)),
                'date': t.data['date'].isoformat()
            })
    return result
Пример #28
0
 def test_add_item_net_price_success(self):
     self.tr19.price_includes_tax = False
     self.tr19.save()
     self.ocm.add_position(self.shirt, None, None, None)
     self.ocm.commit()
     self.order.refresh_from_db()
     assert self.order.positions.count() == 3
     nop = self.order.positions.last()
     assert nop.item == self.shirt
     assert nop.price == Decimal('14.28')
     assert nop.tax_rate == self.shirt.tax_rule.rate
     assert round_decimal(nop.price * (1 - 100 / (100 + self.shirt.tax_rule.rate))) == nop.tax_value
     assert self.order.total == self.op1.price + self.op2.price + nop.price
     assert nop.positionid == 3
Пример #29
0
    def _label(self, event, item_or_variation, avail, override_price=None):
        if isinstance(item_or_variation, ItemVariation):
            variation = item_or_variation
            item = item_or_variation.item
            price = variation.price
            price_net = variation.net_price
            label = variation.value
        else:
            item = item_or_variation
            price = item.default_price
            price_net = item.default_price_net
            label = item.name

        if override_price:
            price = override_price
            tax_value = round_decimal(price * (1 - 100 /
                                               (100 + item.tax_rate)))
            price_net = price - tax_value

        if self.price_included:
            price = Decimal('0.00')

        if not price:
            n = '{name}'.format(name=label)
        elif not item.tax_rate:
            n = _('{name} (+ {currency} {price})').format(
                name=label,
                currency=event.currency,
                price=number_format(price))
        elif event.settings.display_net_prices:
            n = _('{name} (+ {currency} {price} plus {taxes}% taxes)').format(
                name=label,
                currency=event.currency,
                price=number_format(price_net),
                taxes=number_format(item.tax_rate))
        else:
            n = _('{name} (+ {currency} {price} incl. {taxes}% taxes)').format(
                name=label,
                currency=event.currency,
                price=number_format(price),
                taxes=number_format(item.tax_rate))

        if avail[0] < 20:
            n += ' – {}'.format(_('SOLD OUT'))
        elif avail[0] < 100:
            n += ' – {}'.format(_('Currently unavailable'))

        return n
def get_fee(event, total, invoice_address):
    payment_fee = round_decimal(Decimal('0.25') + Decimal('0.029') * total)
    payment_fee_tax_rule = event.settings.tax_rate_default or TaxRule.zero()
    if payment_fee_tax_rule.tax_applicable(invoice_address):
        payment_fee_tax = payment_fee_tax_rule.tax(payment_fee,
                                                   base_price_is='gross')
        return OrderFee(fee_type=OrderFee.FEE_TYPE_PAYMENT,
                        value=payment_fee,
                        tax_rate=payment_fee_tax.rate,
                        tax_value=payment_fee_tax.tax,
                        tax_rule=payment_fee_tax_rule)
    else:
        return OrderFee(fee_type=OrderFee.FEE_TYPE_PAYMENT,
                        value=payment_fee,
                        tax_rate=Decimal('0.00'),
                        tax_value=Decimal('0.00'),
                        tax_rule=payment_fee_tax_rule)
Пример #31
0
    def _get_price(self, item: Item, variation: Optional[ItemVariation],
                   voucher: Optional[Voucher], custom_price: Optional[Decimal]):
        price = item.default_price if variation is None else (
            variation.default_price if variation.default_price is not None else item.default_price
        )
        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(custom_price.replace(",", "."))
            if custom_price > 100000000:
                raise CartError(error_messages['price_too_high'])
            if self.event.settings.display_net_prices:
                custom_price = round_decimal(custom_price * (100 + item.tax_rate) / 100)
            price = max(custom_price, price)

        return price
Пример #32
0
 def _connect_kwargs(self, payment):
     d = {}
     if self.settings.connect_client_id and self.settings.connect_user_id:
         fee = Decimal('0.00')
         if self.settings.get('connect_app_fee_percent', as_type=Decimal):
             fee = round_decimal(
                 self.settings.get('connect_app_fee_percent',
                                   as_type=Decimal) * payment.amount /
                 Decimal('100.00'), self.event.currency)
         if self.settings.connect_app_fee_max:
             fee = min(
                 fee,
                 self.settings.get('connect_app_fee_max', as_type=Decimal))
         if self.settings.get('connect_app_fee_min', as_type=Decimal):
             fee = max(
                 fee,
                 self.settings.get('connect_app_fee_min', as_type=Decimal))
         if fee:
             d['application_fee_amount'] = self._decimal_to_int(fee)
     return d
Пример #33
0
def parse(file):
    data = file.read()
    try:
        import chardet

        charset = chardet.detect(data)['encoding']
    except ImportError:
        charset = file.charset
    data = data.decode(charset or 'utf-8')
    mt = mt940.parse(io.StringIO(data.strip()))
    result = []
    for t in mt:
        result.append({
            'reference': "\n".join([
                t.data.get(f) for f in ('transaction_details', 'customer_reference', 'bank_reference',
                                        'extra_details') if t.data.get(f, '')]),
            'amount': str(round_decimal(t.data['amount'].amount)),
            'date': t.data['date'].isoformat()
        })
    return result
Пример #34
0
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
Пример #35
0
def test_country_specific_rule_gross_based_subtract_bundled(item):
    item.default_price = Decimal('100.00')
    item.tax_rule = item.event.tax_rules.create(rate=Decimal('19.00'),
                                                price_includes_tax=True,
                                                custom_rules=json.dumps([{
                                                    'country':
                                                    'BE',
                                                    'address_type':
                                                    '',
                                                    'action':
                                                    'vat',
                                                    'rate':
                                                    '100.00'
                                                }]))
    ia = InvoiceAddress(is_business=True,
                        vat_id="EU1234",
                        vat_id_validated=True,
                        country=Country('BE'))
    assert get_price(
        item, invoice_address=ia,
        bundled_sum=Decimal('20.00')).gross == (round_decimal(
            (Decimal('100.00') - Decimal('20.00')) / Decimal('1.19')) *
                                                Decimal('2'))
Пример #36
0
def base_widgets(sender, subevent=None, **kwargs):
    prodc = Item.objects.filter(
        event=sender, active=True,
    ).filter(
        (Q(available_until__isnull=True) | Q(available_until__gte=now())) &
        (Q(available_from__isnull=True) | Q(available_from__lte=now()))
    ).count()

    if subevent:
        opqs = OrderPosition.objects.filter(subevent=subevent)
    else:
        opqs = OrderPosition.objects

    tickc = opqs.filter(
        order__event=sender, item__admission=True,
        order__status__in=(Order.STATUS_PAID, Order.STATUS_PENDING),
    ).count()

    paidc = opqs.filter(
        order__event=sender, item__admission=True,
        order__status=Order.STATUS_PAID,
    ).count()

    if subevent:
        rev = opqs.filter(
            order__event=sender, order__status=Order.STATUS_PAID
        ).aggregate(
            sum=Sum('price')
        )['sum'] or Decimal('0.00')
    else:
        rev = Order.objects.filter(
            event=sender,
            status=Order.STATUS_PAID
        ).aggregate(sum=Sum('total'))['sum'] or Decimal('0.00')

    return [
        {
            'content': NUM_WIDGET.format(num=tickc, text=_('Attendees (ordered)')),
            'display_size': 'small',
            'priority': 100,
            'url': reverse('control:event.orders', kwargs={
                'event': sender.slug,
                'organizer': sender.organizer.slug
            }) + ('?subevent={}'.format(subevent.pk) if subevent else '')
        },
        {
            'content': NUM_WIDGET.format(num=paidc, text=_('Attendees (paid)')),
            'display_size': 'small',
            'priority': 100,
            'url': reverse('control:event.orders.overview', kwargs={
                'event': sender.slug,
                'organizer': sender.organizer.slug
            }) + ('?subevent={}'.format(subevent.pk) if subevent else '')
        },
        {
            'content': NUM_WIDGET.format(
                num=formats.localize(round_decimal(rev, sender.currency)), text=_('Total revenue ({currency})').format(currency=sender.currency)),
            'display_size': 'small',
            'priority': 100,
            'url': reverse('control:event.orders.overview', kwargs={
                'event': sender.slug,
                'organizer': sender.organizer.slug
            }) + ('?subevent={}'.format(subevent.pk) if subevent else '')
        },
        {
            'content': NUM_WIDGET.format(num=prodc, text=_('Active products')),
            'display_size': 'small',
            'priority': 100,
            'url': reverse('control:event.items', kwargs={
                'event': sender.slug,
                'organizer': sender.organizer.slug
            })
        },
    ]
Пример #37
0
    def iterate_orders(self, form_data):
        tz = self.event.timezone

        tax_rates = set(
            a for a
            in OrderFee.objects.filter(
                order__event=self.event
            ).values_list('tax_rate', flat=True).distinct().order_by()
        )
        tax_rates |= set(
            a for a
            in OrderPosition.objects.filter(order__event=self.event).filter(
                order__status__in=form_data['status']
            ).values_list('tax_rate', flat=True).distinct().order_by()
        )
        tax_rates = sorted(tax_rates)

        headers = [
            _('Order code'), _('Order date'),
            _('Company'), _('Name'),
            _('Country'), _('VAT ID'), _('Status'), _('Payment date'), _('Order total'),
        ] + sum(([str(t) + ' % ' + _('Gross'), str(t) + ' % ' + _('Tax')] for t in tax_rates), [])
        yield headers

        op_date = OrderPayment.objects.filter(
            order=OuterRef('order'),
            state__in=(OrderPayment.PAYMENT_STATE_CONFIRMED, OrderPayment.PAYMENT_STATE_REFUNDED),
            payment_date__isnull=False
        ).values('order').annotate(
            m=Max('payment_date')
        ).values(
            'm'
        ).order_by()
        qs = self.filter_qs(OrderPosition.objects, form_data).filter(
            order__status__in=form_data['status'],
            order__event=self.event,
        ).annotate(payment_date=Subquery(op_date, output_field=models.DateTimeField())).values(
            'order__code', 'order__datetime', 'payment_date', 'order__total', 'tax_rate', 'order__status',
            'order__id', 'order__invoice_address__name_cached', 'order__invoice_address__company',
            'order__invoice_address__country', 'order__invoice_address__vat_id'
        ).annotate(prices=Sum('price'), tax_values=Sum('tax_value')).order_by(
            'order__datetime' if form_data['sort'] == 'datetime' else 'payment_date',
            'order__datetime',
            'order__code'
        )
        fee_sum_cache = {
            (o['order__id'], o['tax_rate']): o for o in
            OrderFee.objects.values('tax_rate', 'order__id').order_by().annotate(
                taxsum=Sum('tax_value'), grosssum=Sum('value')
            )
        }

        last_order_code = None
        tax_sums = defaultdict(Decimal)
        price_sums = defaultdict(Decimal)
        status_labels = dict(Order.STATUS_CHOICE)
        row = None
        for op in qs:
            if op['order__code'] != last_order_code:
                if row:
                    yield row
                    row = None
                row = [
                    op['order__code'],
                    date_format(op['order__datetime'].astimezone(tz), "SHORT_DATE_FORMAT"),
                    op['order__invoice_address__company'],
                    op['order__invoice_address__name_cached'],
                    op['order__invoice_address__country'],
                    op['order__invoice_address__vat_id'],
                    status_labels[op['order__status']],
                    date_format(op['payment_date'], "SHORT_DATE_FORMAT") if op['payment_date'] else '',
                    round_decimal(op['order__total'], self.event.currency),
                ] + sum(([Decimal('0.00'), Decimal('0.00')] for t in tax_rates), [])
                last_order_code = op['order__code']
                for i, rate in enumerate(tax_rates):
                    odata = fee_sum_cache.get((op['order__id'], rate))
                    if odata:
                        row[9 + 2 * i] = odata['grosssum'] or 0
                        row[10 + 2 * i] = odata['taxsum'] or 0
                        tax_sums[rate] += odata['taxsum'] or 0
                        price_sums[rate] += odata['grosssum'] or 0

            i = tax_rates.index(op['tax_rate'])
            row[9 + 2 * i] = round_decimal(row[9 + 2 * i] + op['prices'], self.event.currency)
            row[10 + 2 * i] = round_decimal(row[10 + 2 * i] + op['tax_values'], self.event.currency)
            tax_sums[op['tax_rate']] += op['tax_values']
            price_sums[op['tax_rate']] += op['prices']

        if row:
            yield row
        yield [
            _('Total'), '', '', '', '', '', '', '', ''
        ] + sum(([
            round_decimal(price_sums.get(t) or Decimal('0.00'), self.event.currency),
            round_decimal(tax_sums.get(t) or Decimal('0.00'), self.event.currency)
        ] for t in tax_rates), [])
Пример #38
0
    def get_story(self, doc, form_data):
        from reportlab.lib.units import mm
        from reportlab.platypus import Paragraph, Spacer, Table, TableStyle

        headlinestyle = self.get_style()
        headlinestyle.fontSize = 15
        headlinestyle.fontName = 'OpenSansBd'
        tz = pytz.timezone(self.event.settings.timezone)

        tax_rates = set(
            a for a
            in OrderFee.objects.filter(
                order__event=self.event
            ).values_list('tax_rate', flat=True).distinct().order_by()
        )
        tax_rates |= set(
            a for a
            in OrderPosition.objects.filter(order__event=self.event).filter(
                order__status__in=self.form_data['status']
            ).values_list('tax_rate', flat=True).distinct().order_by()
        )
        tax_rates = sorted(tax_rates)

        # Cols: Order ID | Order date | Status | Payment Date | Total | {gross tax} for t in taxes
        colwidths = [a * doc.width for a in [0.12, 0.1, 0.10, 0.12, 0.08]]
        if tax_rates:
            colwidths += [0.48 / (len(tax_rates) * 2) * doc.width] * (len(tax_rates) * 2)

        tstyledata = [
            # Alignment
            ('ALIGN', (0, 0), (3, 0), 'LEFT'),  # Headlines
            ('ALIGN', (4, 0), (-1, 0), 'CENTER'),  # Headlines
            ('ALIGN', (4, 1), (-1, -1), 'RIGHT'),  # Money
            ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),

            # Fonts
            ('FONTNAME', (0, 0), (-1, 0), 'OpenSansBd'),  # Headlines
            ('FONTNAME', (0, -1), (-1, -1), 'OpenSansBd'),  # Sums
        ]
        for i, rate in enumerate(tax_rates):
            tstyledata.append(('SPAN', (5 + 2 * i, 0), (6 + 2 * i, 0)))

        story = [
            Paragraph(_('Orders by tax rate ({currency})').format(currency=self.event.currency), headlinestyle),
            Spacer(1, 5 * mm)
        ]
        tdata = [
            [
                _('Order code'), _('Order date'), _('Status'), _('Payment date'), _('Order total'),
            ] + sum(([localize(t) + ' %', ''] for t in tax_rates), []),
            [
                '', '', '', '', ''
            ] + sum(([_('Gross'), _('Tax')] for t in tax_rates), []),
        ]

        op_date = OrderPayment.objects.filter(
            order=OuterRef('order'),
            state__in=(OrderPayment.PAYMENT_STATE_CONFIRMED, OrderPayment.PAYMENT_STATE_REFUNDED),
            payment_date__isnull=False
        ).values('order').annotate(
            m=Max('payment_date')
        ).values(
            'm'
        ).order_by()
        qs = OrderPosition.objects.filter(
            order__status__in=self.form_data['status'],
            order__event=self.event,
        ).annotate(payment_date=Subquery(op_date, output_field=models.DateTimeField())).values(
            'order__code', 'order__datetime', 'payment_date', 'order__total', 'tax_rate', 'order__status',
            'order__id'
        ).annotate(prices=Sum('price'), tax_values=Sum('tax_value')).order_by(
            'order__datetime' if self.form_data['sort'] == 'datetime' else 'payment_date',
            'order__datetime',
            'order__code'
        )
        fee_sum_cache = {
            (o['order__id'], o['tax_rate']): o for o in
            OrderFee.objects.values('tax_rate', 'order__id').order_by().annotate(
                taxsum=Sum('tax_value'), grosssum=Sum('value')
            )
        }

        last_order_code = None
        tax_sums = defaultdict(Decimal)
        price_sums = defaultdict(Decimal)
        status_labels = dict(Order.STATUS_CHOICE)
        for op in qs:
            if op['order__code'] != last_order_code:
                tdata.append(
                    [
                        op['order__code'],
                        date_format(op['order__datetime'].astimezone(tz), "SHORT_DATE_FORMAT"),
                        status_labels[op['order__status']],
                        date_format(op['payment_date'], "SHORT_DATE_FORMAT") if op['payment_date'] else '',
                        op['order__total']
                    ] + sum((['', ''] for t in tax_rates), []),
                )
                last_order_code = op['order__code']
                for i, rate in enumerate(tax_rates):
                    odata = fee_sum_cache.get((op['order__id'], rate))
                    if odata:
                        tdata[-1][5 + 2 * i] = odata['grosssum'] or Decimal('0.00')
                        tdata[-1][6 + 2 * i] = odata['taxsum'] or Decimal('0.00')
                        tax_sums[rate] += odata['taxsum'] or Decimal('0.00')
                        price_sums[rate] += odata['grosssum'] or Decimal('0.00')

            i = tax_rates.index(op['tax_rate'])
            tdata[-1][5 + 2 * i] = (tdata[-1][5 + 2 * i] or Decimal('0.00')) + op['prices']
            tdata[-1][6 + 2 * i] = (tdata[-1][6 + 2 * i] or Decimal('0.00')) + op['tax_values']
            tax_sums[op['tax_rate']] += op['tax_values']
            price_sums[op['tax_rate']] += op['prices']

        tdata.append(
            [
                _('Total'), '', '', '', ''
            ] + sum(([
                price_sums.get(t) or Decimal('0.00'),
                tax_sums.get(t) or Decimal('0.00')
            ] for t in tax_rates), []),
        )
        tdata = [
            [
                localize(round_decimal(c, self.event.currency))
                if isinstance(c, (Decimal, int, float))
                else c
                for c in row
            ] for row in tdata
        ]

        table = Table(tdata, colWidths=colwidths, repeatRows=2)
        table.setStyle(TableStyle(tstyledata))
        story.append(table)
        return story
Пример #39
0
 def net_price(self):
     tax_value = round_decimal(self.price * (1 - 100 / (100 + self.item.tax_rate)))
     return self.price - tax_value
Пример #40
0
 def default_price_net(self):
     tax_value = round_decimal(self.default_price * (1 - 100 / (100 + self.tax_rate)))
     return self.default_price - tax_value
Пример #41
0
    def get_story(self, doc, form_data):
        from reportlab.platypus import Paragraph, Spacer, TableStyle, Table
        from reportlab.lib.units import mm

        headlinestyle = self.get_style()
        headlinestyle.fontSize = 15
        headlinestyle.fontName = 'OpenSansBd'
        tz = pytz.timezone(self.event.settings.timezone)

        tax_rates = set(
            a for a
            in OrderFee.objects.filter(
                order__event=self.event
            ).values_list('tax_rate', flat=True).distinct().order_by()
        )
        tax_rates |= set(
            a for a
            in OrderPosition.objects.filter(order__event=self.event).filter(
                order__status__in=self.form_data['status']
            ).values_list('tax_rate', flat=True).distinct().order_by()
        )
        tax_rates = sorted(tax_rates)

        # Cols: Order ID | Order date | Status | Payment Date | Total | {gross tax} for t in taxes
        colwidths = [a * doc.width for a in [0.12, 0.1, 0.10, 0.12, 0.08]]
        if tax_rates:
            colwidths += [0.48 / (len(tax_rates) * 2) * doc.width] * (len(tax_rates) * 2)

        tstyledata = [
            # Alignment
            ('ALIGN', (0, 0), (3, 0), 'LEFT'),  # Headlines
            ('ALIGN', (4, 0), (-1, 0), 'CENTER'),  # Headlines
            ('ALIGN', (4, 1), (-1, -1), 'RIGHT'),  # Money
            ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),

            # Fonts
            ('FONTNAME', (0, 0), (-1, 0), 'OpenSansBd'),  # Headlines
            ('FONTNAME', (0, -1), (-1, -1), 'OpenSansBd'),  # Sums
        ]
        for i, rate in enumerate(tax_rates):
            tstyledata.append(('SPAN', (5 + 2 * i, 0), (6 + 2 * i, 0)))

        story = [
            Paragraph(_('Orders by tax rate ({currency})').format(currency=self.event.currency), headlinestyle),
            Spacer(1, 5 * mm)
        ]
        tdata = [
            [
                _('Order code'), _('Order date'), _('Status'), _('Payment date'), _('Order total'),
            ] + sum(([str(t) + ' %', ''] for t in tax_rates), []),
            [
                '', '', '', '', ''
            ] + sum(([_('Gross'), _('Tax')] for t in tax_rates), []),
        ]

        op_date = OrderPayment.objects.filter(
            order=OuterRef('order'),
            state__in=(OrderPayment.PAYMENT_STATE_CONFIRMED, OrderPayment.PAYMENT_STATE_REFUNDED),
            payment_date__isnull=False
        ).values('order').annotate(
            m=Max('payment_date')
        ).values(
            'm'
        ).order_by()
        qs = OrderPosition.objects.filter(
            order__status__in=self.form_data['status'],
            order__event=self.event,
        ).annotate(payment_date=Subquery(op_date, output_field=models.DateTimeField())).values(
            'order__code', 'order__datetime', 'payment_date', 'order__total', 'tax_rate', 'order__status',
            'order__id'
        ).annotate(prices=Sum('price'), tax_values=Sum('tax_value')).order_by(
            'order__datetime' if self.form_data['sort'] == 'datetime' else 'payment_date',
            'order__datetime',
            'order__code'
        )
        fee_sum_cache = {
            (o['order__id'], o['tax_rate']): o for o in
            OrderFee.objects.values('tax_rate', 'order__id').order_by().annotate(
                taxsum=Sum('tax_value'), grosssum=Sum('value')
            )
        }

        last_order_code = None
        tax_sums = defaultdict(Decimal)
        price_sums = defaultdict(Decimal)
        status_labels = dict(Order.STATUS_CHOICE)
        for op in qs:
            if op['order__code'] != last_order_code:
                tdata.append(
                    [
                        op['order__code'],
                        date_format(op['order__datetime'].astimezone(tz), "SHORT_DATE_FORMAT"),
                        status_labels[op['order__status']],
                        date_format(op['payment_date'], "SHORT_DATE_FORMAT") if op['payment_date'] else '',
                        localize(round_decimal(op['order__total'], self.event.currency))
                    ] + sum((['', ''] for t in tax_rates), []),
                )
                last_order_code = op['order__code']
                for i, rate in enumerate(tax_rates):
                    odata = fee_sum_cache.get((op['order__id'], rate))
                    if odata:
                        tdata[-1][5 + 2 * i] = str(odata['grosssum'] or 0)
                        tdata[-1][6 + 2 * i] = str(odata['taxsum'] or 0)
                        tax_sums[rate] += odata['taxsum'] or 0
                        price_sums[rate] += odata['grosssum'] or 0

                i = tax_rates.index(op['tax_rate'])
                tdata[-1][5 + 2 * i] = localize(
                    round_decimal(Decimal(tdata[-1][5 + 2 * i] or '0') + op['prices'], self.event.currency))
                tdata[-1][6 + 2 * i] = localize(
                    round_decimal(Decimal(tdata[-1][6 + 2 * i] or '0') + op['tax_values'], self.event.currency))
                tax_sums[op['tax_rate']] += op['tax_values']
                price_sums[op['tax_rate']] += op['prices']

        tdata.append(
            [
                _('Total'), '', '', '', ''
            ] + sum(([
                localize(round_decimal(price_sums.get(t) or Decimal('0.00'), self.event.currency)),
                localize(round_decimal(tax_sums.get(t) or Decimal('0.00'), self.event.currency))
            ] for t in tax_rates), []),
        )

        table = Table(tdata, colWidths=colwidths, repeatRows=2)
        table.setStyle(TableStyle(tstyledata))
        story.append(table)
        return story
Пример #42
0
    def _get_story(self, doc):
        has_taxes = any(il.tax_value for il in self.invoice.lines.all())

        story = [
            NextPageTemplate('FirstPage'),
            Paragraph(
                (
                    pgettext('invoice', 'Tax Invoice') if str(self.invoice.invoice_from_country) == 'AU'
                    else pgettext('invoice', 'Invoice')
                ) if not self.invoice.is_cancellation else pgettext('invoice', 'Cancellation'),
                self.stylesheet['Heading1']
            ),
            Spacer(1, 5 * mm),
            NextPageTemplate('OtherPages'),
        ]
        story += self._get_intro()

        taxvalue_map = defaultdict(Decimal)
        grossvalue_map = defaultdict(Decimal)

        tstyledata = [
            ('ALIGN', (1, 0), (-1, -1), 'RIGHT'),
            ('VALIGN', (0, 0), (-1, -1), 'TOP'),
            ('FONTNAME', (0, 0), (-1, 0), self.font_bold),
            ('FONTNAME', (0, -1), (-1, -1), self.font_bold),
            ('LEFTPADDING', (0, 0), (0, -1), 0),
            ('RIGHTPADDING', (-1, 0), (-1, -1), 0),
        ]
        if has_taxes:
            tdata = [(
                pgettext('invoice', 'Description'),
                pgettext('invoice', 'Qty'),
                pgettext('invoice', 'Tax rate'),
                pgettext('invoice', 'Net'),
                pgettext('invoice', 'Gross'),
            )]
        else:
            tdata = [(
                pgettext('invoice', 'Description'),
                pgettext('invoice', 'Qty'),
                pgettext('invoice', 'Amount'),
            )]

        total = Decimal('0.00')
        for line in self.invoice.lines.all():
            if has_taxes:
                tdata.append((
                    Paragraph(line.description, self.stylesheet['Normal']),
                    "1",
                    localize(line.tax_rate) + " %",
                    money_filter(line.net_value, self.invoice.event.currency),
                    money_filter(line.gross_value, self.invoice.event.currency),
                ))
            else:
                tdata.append((
                    Paragraph(line.description, self.stylesheet['Normal']),
                    "1",
                    money_filter(line.gross_value, self.invoice.event.currency),
                ))
            taxvalue_map[line.tax_rate, line.tax_name] += line.tax_value
            grossvalue_map[line.tax_rate, line.tax_name] += line.gross_value
            total += line.gross_value

        if has_taxes:
            tdata.append([
                pgettext('invoice', 'Invoice total'), '', '', '', money_filter(total, self.invoice.event.currency)
            ])
            colwidths = [a * doc.width for a in (.50, .05, .15, .15, .15)]
        else:
            tdata.append([
                pgettext('invoice', 'Invoice total'), '', money_filter(total, self.invoice.event.currency)
            ])
            colwidths = [a * doc.width for a in (.65, .05, .30)]

        if self.invoice.event.settings.invoice_show_payments and not self.invoice.is_cancellation and \
                self.invoice.order.status == Order.STATUS_PENDING:
            pending_sum = self.invoice.order.pending_sum
            if pending_sum != total:
                tdata.append([pgettext('invoice', 'Received payments')] + (['', '', ''] if has_taxes else ['']) + [
                    money_filter(pending_sum - total, self.invoice.event.currency)
                ])
                tdata.append([pgettext('invoice', 'Outstanding payments')] + (['', '', ''] if has_taxes else ['']) + [
                    money_filter(pending_sum, self.invoice.event.currency)
                ])
                tstyledata += [
                    ('FONTNAME', (0, len(tdata) - 3), (-1, len(tdata) - 3), self.font_bold),
                ]

        table = Table(tdata, colWidths=colwidths, repeatRows=1)
        table.setStyle(TableStyle(tstyledata))
        story.append(table)

        story.append(Spacer(1, 15 * mm))

        if self.invoice.payment_provider_text:
            story.append(Paragraph(self.invoice.payment_provider_text, self.stylesheet['Normal']))

        if self.invoice.additional_text:
            story.append(Paragraph(self.invoice.additional_text, self.stylesheet['Normal']))
            story.append(Spacer(1, 15 * mm))

        tstyledata = [
            ('ALIGN', (1, 0), (-1, -1), 'RIGHT'),
            ('LEFTPADDING', (0, 0), (0, -1), 0),
            ('RIGHTPADDING', (-1, 0), (-1, -1), 0),
            ('FONTSIZE', (0, 0), (-1, -1), 8),
            ('FONTNAME', (0, 0), (-1, -1), self.font_regular),
        ]
        thead = [
            pgettext('invoice', 'Tax rate'),
            pgettext('invoice', 'Net value'),
            pgettext('invoice', 'Gross value'),
            pgettext('invoice', 'Tax'),
            ''
        ]
        tdata = [thead]

        for idx, gross in grossvalue_map.items():
            rate, name = idx
            if rate == 0:
                continue
            tax = taxvalue_map[idx]
            tdata.append([
                localize(rate) + " % " + name,
                money_filter(gross - tax, self.invoice.event.currency),
                money_filter(gross, self.invoice.event.currency),
                money_filter(tax, self.invoice.event.currency),
                ''
            ])

        def fmt(val):
            try:
                return vat_moss.exchange_rates.format(val, self.invoice.foreign_currency_display)
            except ValueError:
                return localize(val) + ' ' + self.invoice.foreign_currency_display

        if len(tdata) > 1 and has_taxes:
            colwidths = [a * doc.width for a in (.25, .15, .15, .15, .3)]
            table = Table(tdata, colWidths=colwidths, repeatRows=2, hAlign=TA_LEFT)
            table.setStyle(TableStyle(tstyledata))
            story.append(Spacer(5 * mm, 5 * mm))
            story.append(KeepTogether([
                Paragraph(pgettext('invoice', 'Included taxes'), self.stylesheet['FineprintHeading']),
                table
            ]))

            if self.invoice.foreign_currency_display and self.invoice.foreign_currency_rate:
                tdata = [thead]

                for idx, gross in grossvalue_map.items():
                    rate, name = idx
                    if rate == 0:
                        continue
                    tax = taxvalue_map[idx]
                    gross = round_decimal(gross * self.invoice.foreign_currency_rate)
                    tax = round_decimal(tax * self.invoice.foreign_currency_rate)
                    net = gross - tax

                    tdata.append([
                        localize(rate) + " % " + name,
                        fmt(net), fmt(gross), fmt(tax), ''
                    ])

                table = Table(tdata, colWidths=colwidths, repeatRows=2, hAlign=TA_LEFT)
                table.setStyle(TableStyle(tstyledata))

                story.append(KeepTogether([
                    Spacer(1, height=2 * mm),
                    Paragraph(
                        pgettext(
                            'invoice', 'Using the conversion rate of 1:{rate} as published by the European Central Bank on '
                                       '{date}, this corresponds to:'
                        ).format(rate=localize(self.invoice.foreign_currency_rate),
                                 date=date_format(self.invoice.foreign_currency_rate_date, "SHORT_DATE_FORMAT")),
                        self.stylesheet['Fineprint']
                    ),
                    Spacer(1, height=3 * mm),
                    table
                ]))
        elif self.invoice.foreign_currency_display and self.invoice.foreign_currency_rate:
            story.append(Spacer(1, 5 * mm))
            story.append(Paragraph(
                pgettext(
                    'invoice', 'Using the conversion rate of 1:{rate} as published by the European Central Bank on '
                               '{date}, the invoice total corresponds to {total}.'
                ).format(rate=localize(self.invoice.foreign_currency_rate),
                         date=date_format(self.invoice.foreign_currency_rate_date, "SHORT_DATE_FORMAT"),
                         total=fmt(total)),
                self.stylesheet['Fineprint']
            ))

        return story
Пример #43
0
 def _amount_to_decimal(self, cents):
     places = settings.CURRENCY_PLACES.get(self.event.currency, 2)
     return round_decimal(float(cents) / (10 ** places), self.event.currency)
Пример #44
0
 def _amount_to_decimal(self, cents):
     places = settings.CURRENCY_PLACES.get(self.event.currency, 2)
     return round_decimal(float(cents) / (10**places), self.event.currency)
Пример #45
0
    def _get_story(self, doc):
        has_taxes = any(il.tax_value for il in self.invoice.lines.all())

        story = [
            NextPageTemplate('FirstPage'),
            Paragraph(pgettext('invoice', 'Invoice')
                      if not self.invoice.is_cancellation
                      else pgettext('invoice', 'Cancellation'),
                      self.stylesheet['Heading1']),
            Spacer(1, 5 * mm),
            NextPageTemplate('OtherPages'),
        ]

        if self.invoice.internal_reference:
            story.append(Paragraph(
                pgettext('invoice', 'Customer reference: {reference}').format(reference=self.invoice.internal_reference),
                self.stylesheet['Normal']
            ))

        if self.invoice.introductory_text:
            story.append(Paragraph(self.invoice.introductory_text, self.stylesheet['Normal']))
            story.append(Spacer(1, 10 * mm))

        taxvalue_map = defaultdict(Decimal)
        grossvalue_map = defaultdict(Decimal)

        tstyledata = [
            ('ALIGN', (1, 0), (-1, -1), 'RIGHT'),
            ('VALIGN', (0, 0), (-1, -1), 'TOP'),
            ('FONTNAME', (0, 0), (-1, 0), 'OpenSansBd'),
            ('FONTNAME', (0, -1), (-1, -1), 'OpenSansBd'),
            ('LEFTPADDING', (0, 0), (0, -1), 0),
            ('RIGHTPADDING', (-1, 0), (-1, -1), 0),
        ]
        if has_taxes:
            tdata = [(
                pgettext('invoice', 'Description'),
                pgettext('invoice', 'Qty'),
                pgettext('invoice', 'Tax rate'),
                pgettext('invoice', 'Net'),
                pgettext('invoice', 'Gross'),
            )]
        else:
            tdata = [(
                pgettext('invoice', 'Description'),
                pgettext('invoice', 'Qty'),
                pgettext('invoice', 'Amount'),
            )]

        total = Decimal('0.00')
        for line in self.invoice.lines.all():
            if has_taxes:
                tdata.append((
                    Paragraph(line.description, self.stylesheet['Normal']),
                    "1",
                    localize(line.tax_rate) + " %",
                    money_filter(line.net_value, self.invoice.event.currency),
                    money_filter(line.gross_value, self.invoice.event.currency),
                ))
            else:
                tdata.append((
                    Paragraph(line.description, self.stylesheet['Normal']),
                    "1",
                    money_filter(line.gross_value, self.invoice.event.currency),
                ))
            taxvalue_map[line.tax_rate, line.tax_name] += line.tax_value
            grossvalue_map[line.tax_rate, line.tax_name] += line.gross_value
            total += line.gross_value

        if has_taxes:
            tdata.append([
                pgettext('invoice', 'Invoice total'), '', '', '', money_filter(total, self.invoice.event.currency)
            ])
            colwidths = [a * doc.width for a in (.50, .05, .15, .15, .15)]
        else:
            tdata.append([
                pgettext('invoice', 'Invoice total'), '', money_filter(total, self.invoice.event.currency)
            ])
            colwidths = [a * doc.width for a in (.65, .05, .30)]

        table = Table(tdata, colWidths=colwidths, repeatRows=1)
        table.setStyle(TableStyle(tstyledata))
        story.append(table)

        story.append(Spacer(1, 15 * mm))

        if self.invoice.payment_provider_text:
            story.append(Paragraph(self.invoice.payment_provider_text, self.stylesheet['Normal']))

        if self.invoice.additional_text:
            story.append(Paragraph(self.invoice.additional_text, self.stylesheet['Normal']))
            story.append(Spacer(1, 15 * mm))

        tstyledata = [
            ('ALIGN', (1, 0), (-1, -1), 'RIGHT'),
            ('LEFTPADDING', (0, 0), (0, -1), 0),
            ('RIGHTPADDING', (-1, 0), (-1, -1), 0),
            ('FONTSIZE', (0, 0), (-1, -1), 8),
            ('FONTNAME', (0, 0), (-1, -1), 'OpenSans'),
        ]
        thead = [
            pgettext('invoice', 'Tax rate'),
            pgettext('invoice', 'Net value'),
            pgettext('invoice', 'Gross value'),
            pgettext('invoice', 'Tax'),
            ''
        ]
        tdata = [thead]

        for idx, gross in grossvalue_map.items():
            rate, name = idx
            if rate == 0:
                continue
            tax = taxvalue_map[idx]
            tdata.append([
                localize(rate) + " % " + name,
                money_filter(gross - tax, self.invoice.event.currency),
                money_filter(gross, self.invoice.event.currency),
                money_filter(tax, self.invoice.event.currency),
                ''
            ])

        def fmt(val):
            try:
                return vat_moss.exchange_rates.format(val, self.invoice.foreign_currency_display)
            except ValueError:
                return localize(val) + ' ' + self.invoice.foreign_currency_display

        if len(tdata) > 1 and has_taxes:
            colwidths = [a * doc.width for a in (.25, .15, .15, .15, .3)]
            table = Table(tdata, colWidths=colwidths, repeatRows=2, hAlign=TA_LEFT)
            table.setStyle(TableStyle(tstyledata))
            story.append(KeepTogether([
                Paragraph(pgettext('invoice', 'Included taxes'), self.stylesheet['FineprintHeading']),
                table
            ]))

            if self.invoice.foreign_currency_display and self.invoice.foreign_currency_rate:
                tdata = [thead]

                for idx, gross in grossvalue_map.items():
                    rate, name = idx
                    if rate == 0:
                        continue
                    tax = taxvalue_map[idx]
                    gross = round_decimal(gross * self.invoice.foreign_currency_rate)
                    tax = round_decimal(tax * self.invoice.foreign_currency_rate)
                    net = gross - tax

                    tdata.append([
                        localize(rate) + " % " + name,
                        fmt(net), fmt(gross), fmt(tax), ''
                    ])

                table = Table(tdata, colWidths=colwidths, repeatRows=2, hAlign=TA_LEFT)
                table.setStyle(TableStyle(tstyledata))

                story.append(KeepTogether([
                    Spacer(1, height=2 * mm),
                    Paragraph(
                        pgettext(
                            'invoice', 'Using the conversion rate of 1:{rate} as published by the European Central Bank on '
                                       '{date}, this corresponds to:'
                        ).format(rate=localize(self.invoice.foreign_currency_rate),
                                 date=date_format(self.invoice.foreign_currency_rate_date, "SHORT_DATE_FORMAT")),
                        self.stylesheet['Fineprint']
                    ),
                    Spacer(1, height=3 * mm),
                    table
                ]))
        elif self.invoice.foreign_currency_display and self.invoice.foreign_currency_rate:
            story.append(Spacer(1, 5 * mm))
            story.append(Paragraph(
                pgettext(
                    'invoice', 'Using the conversion rate of 1:{rate} as published by the European Central Bank on '
                               '{date}, the invoice total corresponds to {total}.'
                ).format(rate=localize(self.invoice.foreign_currency_rate),
                         date=date_format(self.invoice.foreign_currency_rate_date, "SHORT_DATE_FORMAT"),
                         total=fmt(total)),
                self.stylesheet['Fineprint']
            ))

        return story