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:
Raphael Michel
2017-09-05 10:11:26 +03:00
committed by GitHub
parent a2a88cfafa
commit e54e0d6511
26 changed files with 568 additions and 227 deletions

View File

@@ -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"
}
]
}

View File

@@ -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)

View File

@@ -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')

View File

@@ -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),

View File

@@ -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):