mirror of
https://github.com/pretix/pretix.git
synced 2026-05-04 15:04:03 +00:00
New concept for fee handling (#610)
* New concept for fee handling * More usages * Remove all usages, make all tests pass * API changes * Small fixes * Fix order of invoice lines * Rebase migration
This commit is contained in:
@@ -1,12 +1,15 @@
|
||||
import datetime
|
||||
from decimal import Decimal
|
||||
from distutils.version import LooseVersion
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
from django_countries.fields import Country
|
||||
from pytz import UTC
|
||||
|
||||
from pretix import __version__
|
||||
from pretix.base.models import InvoiceAddress, Order, OrderPosition
|
||||
from pretix.base.models.orders import OrderFee
|
||||
from pretix.base.services.invoices import (
|
||||
generate_cancellation, generate_invoice,
|
||||
)
|
||||
@@ -18,7 +21,12 @@ def item(event):
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def order(event, item):
|
||||
def taxrule(event):
|
||||
return event.tax_rules.create(rate=Decimal('19.00'))
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def order(event, item, taxrule):
|
||||
testtime = datetime.datetime(2017, 12, 1, 10, 0, 0, tzinfo=UTC)
|
||||
|
||||
with mock.patch('django.utils.timezone.now') as mock_now:
|
||||
@@ -30,6 +38,8 @@ def order(event, item):
|
||||
expires=datetime.datetime(2017, 12, 10, 10, 0, 0, tzinfo=UTC),
|
||||
total=23, payment_provider='banktransfer', locale='en'
|
||||
)
|
||||
o.fees.create(fee_type=OrderFee.FEE_TYPE_PAYMENT, value=Decimal('0.25'), tax_rate=Decimal('19.00'),
|
||||
tax_value=Decimal('0.05'), tax_rule=taxrule)
|
||||
InvoiceAddress.objects.create(order=o, company="Sample company", country=Country('NZ'))
|
||||
OrderPosition.objects.create(
|
||||
order=o,
|
||||
@@ -71,11 +81,20 @@ TEST_ORDER_RES = {
|
||||
"datetime": "2017-12-01T10:00:00Z",
|
||||
"expires": "2017-12-10T10:00:00Z",
|
||||
"payment_date": None,
|
||||
"fees": [
|
||||
{
|
||||
"fee_type": "payment",
|
||||
"value": "0.25",
|
||||
"description": "",
|
||||
"internal_type": "",
|
||||
"tax_rate": "19.00",
|
||||
"tax_value": "0.05"
|
||||
}
|
||||
],
|
||||
"payment_provider": "banktransfer",
|
||||
"payment_fee": "0.00",
|
||||
"payment_fee_tax_rate": "0.00",
|
||||
"payment_fee_tax_value": "0.00",
|
||||
"payment_fee_tax_rule": None,
|
||||
"payment_fee": "0.25",
|
||||
"payment_fee_tax_rate": "19.00",
|
||||
"payment_fee_tax_value": "0.05",
|
||||
"total": "23.00",
|
||||
"comment": "",
|
||||
"invoice_address": {
|
||||
@@ -96,10 +115,15 @@ TEST_ORDER_RES = {
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_order_list(token_client, organizer, event, order, item):
|
||||
@pytest.mark.xfail(
|
||||
LooseVersion(__version__) >= LooseVersion("1.9.0.dev0"),
|
||||
reason="Deprecated attributes payment_fee_* should be removed by now",
|
||||
)
|
||||
def test_order_list(token_client, organizer, event, order, item, taxrule):
|
||||
res = dict(TEST_ORDER_RES)
|
||||
res["positions"][0]["id"] = order.positions.first().pk
|
||||
res["positions"][0]["item"] = item.pk
|
||||
res["fees"][0]["tax_rule"] = taxrule.pk
|
||||
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/'.format(organizer.slug, event.slug))
|
||||
assert resp.status_code == 200
|
||||
@@ -129,10 +153,11 @@ def test_order_list(token_client, organizer, event, order, item):
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_order_detail(token_client, organizer, event, order, item):
|
||||
def test_order_detail(token_client, organizer, event, order, item, taxrule):
|
||||
res = dict(TEST_ORDER_RES)
|
||||
res["positions"][0]["id"] = order.positions.first().pk
|
||||
res["positions"][0]["item"] = item.pk
|
||||
res["fees"][0]["tax_rule"] = taxrule.pk
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/{}/'.format(organizer.slug, event.slug,
|
||||
order.code))
|
||||
assert resp.status_code == 200
|
||||
@@ -282,6 +307,13 @@ TEST_INVOICE_RES = {
|
||||
"tax_value": "0.00",
|
||||
"tax_name": "",
|
||||
"tax_rate": "0.00"
|
||||
},
|
||||
{
|
||||
"description": "Payment fee",
|
||||
"gross_value": "0.25",
|
||||
"tax_value": "0.05",
|
||||
"tax_name": "",
|
||||
"tax_rate": "19.00"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ from pretix.base.models import (
|
||||
Event, Invoice, InvoiceAddress, Item, ItemVariation, Order, OrderPosition,
|
||||
Organizer,
|
||||
)
|
||||
from pretix.base.models.orders import OrderFee
|
||||
from pretix.base.services.invoices import (
|
||||
build_preview_invoice_pdf, generate_cancellation, generate_invoice,
|
||||
invoice_pdf_task, regenerate_invoice,
|
||||
@@ -27,15 +28,15 @@ def env():
|
||||
organizer=o, name='Dummy', slug='dummy',
|
||||
date_from=now(), plugins='pretix.plugins.banktransfer'
|
||||
)
|
||||
tr = event.tax_rules.create(rate=Decimal('19.00'))
|
||||
o = Order.objects.create(
|
||||
code='FOO', event=event, email='dummy@dummy.test',
|
||||
status=Order.STATUS_PENDING,
|
||||
datetime=now(), expires=now() + timedelta(days=10),
|
||||
total=0, payment_provider='banktransfer',
|
||||
payment_fee=Decimal('0.25'), payment_fee_tax_rate=Decimal('19.00'),
|
||||
payment_fee_tax_value=Decimal('0.04'), locale='en', payment_fee_tax_rule=tr
|
||||
total=0, payment_provider='banktransfer', locale='en'
|
||||
)
|
||||
tr = event.tax_rules.create(rate=Decimal('19.00'))
|
||||
o.fees.create(fee_type=OrderFee.FEE_TYPE_PAYMENT, value=Decimal('0.25'), tax_rate=Decimal('19.00'),
|
||||
tax_value=Decimal('0.05'), tax_rule=tr)
|
||||
ticket = Item.objects.create(event=event, name='Early-bird ticket',
|
||||
category=None, default_price=23, tax_rule=tr,
|
||||
admission=True)
|
||||
@@ -206,9 +207,10 @@ def test_positions(env):
|
||||
|
||||
last = inv.lines.last()
|
||||
assert 'Payment' in last.description
|
||||
assert last.gross_value == order.payment_fee
|
||||
assert last.tax_rate == order.payment_fee_tax_rate
|
||||
assert last.tax_value == order.payment_fee_tax_value
|
||||
fee = order.fees.get(fee_type=OrderFee.FEE_TYPE_PAYMENT)
|
||||
assert last.gross_value == fee.value
|
||||
assert last.tax_rate == fee.tax_rate
|
||||
assert last.tax_value == fee.tax_value
|
||||
assert inv.invoice_to == ""
|
||||
|
||||
|
||||
@@ -274,9 +276,10 @@ def test_invoice_numbers(env):
|
||||
status=Order.STATUS_PENDING,
|
||||
datetime=now(), expires=now() + timedelta(days=10),
|
||||
total=0, payment_provider='banktransfer',
|
||||
payment_fee=Decimal('0.25'), payment_fee_tax_rate=0,
|
||||
payment_fee_tax_value=0, locale='en'
|
||||
locale='en'
|
||||
)
|
||||
order2.fees.create(fee_type=OrderFee.FEE_TYPE_PAYMENT, value=Decimal('0.25'), tax_rate=Decimal('0.00'),
|
||||
tax_value=Decimal('0.00'))
|
||||
inv1 = generate_invoice(order)
|
||||
inv2 = generate_invoice(order)
|
||||
|
||||
@@ -320,9 +323,10 @@ def test_invoice_number_prefixes(env):
|
||||
status=Order.STATUS_PENDING,
|
||||
datetime=now(), expires=now() + timedelta(days=10),
|
||||
total=0, payment_provider='banktransfer',
|
||||
payment_fee=Decimal('0.25'), payment_fee_tax_rate=0,
|
||||
payment_fee_tax_value=0, locale='en'
|
||||
locale='en'
|
||||
)
|
||||
order2.fees.create(fee_type=OrderFee.FEE_TYPE_PAYMENT, value=Decimal('0.25'), tax_rate=Decimal('0.00'),
|
||||
tax_value=Decimal('0.00'))
|
||||
event.settings.set('invoice_numbers_consecutive', False)
|
||||
event2.settings.set('invoice_numbers_consecutive', False)
|
||||
assert generate_invoice(order).number == 'DUMMY-{}-1'.format(order.code)
|
||||
|
||||
@@ -13,6 +13,7 @@ from pretix.base.models import (
|
||||
CartPosition, Event, InvoiceAddress, Item, Order, OrderPosition, Organizer,
|
||||
)
|
||||
from pretix.base.models.items import SubEventItem
|
||||
from pretix.base.models.orders import OrderFee
|
||||
from pretix.base.payment import FreeOrderProvider
|
||||
from pretix.base.reldate import RelativeDate, RelativeDateWrapper
|
||||
from pretix.base.services.invoices import generate_invoice
|
||||
@@ -539,10 +540,10 @@ class OrderChangeManagerTests(TestCase):
|
||||
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
|
||||
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
|
||||
|
||||
def test_require_pending(self):
|
||||
self.order.status = Order.STATUS_PAID
|
||||
@@ -725,9 +726,10 @@ class OrderChangeManagerTests(TestCase):
|
||||
self.ocm._recalculate_total_and_payment_fee()
|
||||
|
||||
assert self.order.total == Decimal('46.30')
|
||||
assert self.order.payment_fee == prov.calculate_fee(self.order.total)
|
||||
assert self.order.payment_fee_tax_rate == Decimal('19.00')
|
||||
assert self.order.payment_fee_tax_value == Decimal('0.05')
|
||||
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 fee.tax_value == Decimal('0.05')
|
||||
|
||||
ia = self._enable_reverse_charge()
|
||||
self.ocm.recalculate_taxes()
|
||||
@@ -739,9 +741,10 @@ class OrderChangeManagerTests(TestCase):
|
||||
assert op.tax_rate == Decimal('0.00')
|
||||
|
||||
assert self.order.total == Decimal('43.30')
|
||||
assert self.order.payment_fee == prov.calculate_fee(self.order.total)
|
||||
assert self.order.payment_fee_tax_rate == Decimal('0.00')
|
||||
assert self.order.payment_fee_tax_value == Decimal('0.00')
|
||||
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('0.00')
|
||||
assert fee.tax_value == Decimal('0.00')
|
||||
|
||||
ia.vat_id_validated = False
|
||||
ia.save()
|
||||
@@ -755,6 +758,7 @@ class OrderChangeManagerTests(TestCase):
|
||||
assert op.tax_rate == Decimal('7.00')
|
||||
|
||||
assert self.order.total == Decimal('46.32')
|
||||
assert self.order.payment_fee == prov.calculate_fee(self.order.total)
|
||||
assert self.order.payment_fee_tax_rate == Decimal('19.00')
|
||||
assert self.order.payment_fee_tax_value == Decimal('0.05')
|
||||
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 fee.tax_value == Decimal('0.05')
|
||||
|
||||
@@ -5,6 +5,7 @@ from django.utils.timezone import now
|
||||
from tests.base import SoupTest, extract_form_fields
|
||||
|
||||
from pretix.base.models import Event, Order, Organizer, Team, User
|
||||
from pretix.base.models.orders import OrderFee
|
||||
|
||||
|
||||
class TaxRateFormTest(SoupTest):
|
||||
@@ -76,18 +77,16 @@ class TaxRateFormTest(SoupTest):
|
||||
self.assertIn("VAT", doc.select("#page-wrapper")[0].text)
|
||||
assert self.event1.tax_rules.exists()
|
||||
|
||||
def test_delete_order_existing(self):
|
||||
def test_delete_fee_existing(self):
|
||||
tr = self.event1.tax_rules.create(rate=19, name="VAT")
|
||||
self.event1.orders.create(
|
||||
o = self.event1.orders.create(
|
||||
code='FOO', event=self.event1, email='dummy@dummy.test',
|
||||
status=Order.STATUS_PENDING,
|
||||
datetime=now(), expires=now() + datetime.timedelta(days=10),
|
||||
total=14, payment_provider='banktransfer', locale='en',
|
||||
payment_fee=0.3,
|
||||
payment_fee_tax_rate=19,
|
||||
payment_fee_tax_value=0.05,
|
||||
payment_fee_tax_rule=tr
|
||||
)
|
||||
o.fees.create(fee_type=OrderFee.FEE_TYPE_PAYMENT, value=Decimal('0.25'), tax_rate=Decimal('19.00'),
|
||||
tax_value=Decimal('0.05'), tax_rule=tr)
|
||||
doc = self.get_doc('/control/event/%s/%s/settings/tax/%s/delete' % (self.orga1.slug, self.event1.slug, tr.id))
|
||||
form_data = extract_form_fields(doc.select('.container-fluid form')[0])
|
||||
doc = self.post_doc('/control/event/%s/%s/settings/tax/%s/delete' % (self.orga1.slug, self.event1.slug, tr.id),
|
||||
|
||||
@@ -11,6 +11,7 @@ from pretix.base.models import (
|
||||
Event, Item, ItemCategory, ItemVariation, Order, OrderPosition, Organizer,
|
||||
Question, Quota,
|
||||
)
|
||||
from pretix.base.models.orders import OrderFee
|
||||
from pretix.base.reldate import RelativeDate, RelativeDateWrapper
|
||||
from pretix.base.services.invoices import generate_invoice
|
||||
|
||||
@@ -417,8 +418,9 @@ class OrdersTest(TestCase):
|
||||
)
|
||||
self.order.refresh_from_db()
|
||||
assert self.order.payment_provider == 'testdummy'
|
||||
assert self.order.payment_fee == Decimal('12.00')
|
||||
assert self.order.total == Decimal('23.00') + self.order.payment_fee
|
||||
fee = self.order.fees.get(fee_type=OrderFee.FEE_TYPE_PAYMENT)
|
||||
assert fee.value == Decimal('12.00')
|
||||
assert self.order.total == Decimal('23.00') + fee.value
|
||||
assert self.order.invoices.count() == 3
|
||||
|
||||
def test_answer_download_token(self):
|
||||
|
||||
Reference in New Issue
Block a user