mirror of
https://github.com/pretix/pretix.git
synced 2026-05-04 15:04:03 +00:00
Pluggable invoice transmission methods (#5020)
* Flexible invoice transmission
* UI work
* Add peppol and output
* API support
* Profile integration
* Simplify form for individuals
* Remove sent_to_customer usage
* more steps
* Revert "Bank transfer: Allow to send the invoice direclty to the accounting department (#2975)"
This reverts commit cea6c340be.
* minor fixes
* Fixes after rebase
* update stati
* Backend view
* Transmit and show status
* status, retransmission
* API retransmission
* More fields
* API docs
* Plugin docs
* Update migration
* Add missing license headers
* Remove dead code, fix current tests
* Run isort
* Update regex
* Rebase migration
* Fix migration
* Add tests, fix bugs
* Rebase migration
* Apply suggestion from @luelista
Co-authored-by: luelista <weller@rami.io>
* Apply suggestion from @luelista
Co-authored-by: luelista <weller@rami.io>
* Apply suggestion from @luelista
Co-authored-by: luelista <weller@rami.io>
* Apply suggestion from @luelista
Co-authored-by: luelista <weller@rami.io>
* Apply suggestion from @luelista
Co-authored-by: luelista <weller@rami.io>
* Make migration reversible
* Add TransmissionType.enforce_transmission
* Fix registries API usage after rebase
* Remove code I forgot to delete
* Update transmission status display depending on type
* Add testmode_supported
* Update src/pretix/static/pretixbase/js/addressform.js
Co-authored-by: luelista <weller@rami.io>
* Update src/pretix/static/pretixbase/js/addressform.js
Co-authored-by: luelista <weller@rami.io>
* Update src/pretix/static/pretixbase/js/addressform.js
Co-authored-by: luelista <weller@rami.io>
* New mechanism for non-required invoice forms
* Update src/pretix/base/invoicing/transmission.py
Co-authored-by: luelista <weller@rami.io>
* Declare testmode_supported for email
* Make transmission_email_other an implementation detail
* Fix failing tests and add new ones
* Update src/pretix/base/services/invoices.py
Co-authored-by: luelista <weller@rami.io>
* Add emails to email history
* Fix comma error
* More generic default email text
* Cleanup
* Remove "email invoices" button and refine logic
* Rebase migration
* Fix edge case
---------
Co-authored-by: luelista <weller@rami.io>
This commit is contained in:
@@ -67,7 +67,7 @@ def event(organizer, meta_prop):
|
||||
e = Event.objects.create(
|
||||
organizer=organizer, name='Dummy', slug='dummy',
|
||||
date_from=datetime(2017, 12, 27, 10, 0, 0, tzinfo=timezone.utc),
|
||||
plugins='pretix.plugins.banktransfer,pretix.plugins.ticketoutputpdf',
|
||||
plugins='pretix.plugins.banktransfer,pretix.plugins.ticketoutputpdf,tests.testdummy',
|
||||
is_public=True
|
||||
)
|
||||
e.meta_values.create(property=meta_prop, value="Conference")
|
||||
|
||||
@@ -28,7 +28,7 @@ import pytest
|
||||
from django_countries.fields import Country
|
||||
from django_scopes import scopes_disabled
|
||||
|
||||
from pretix.base.models import InvoiceAddress, Order, OrderPosition
|
||||
from pretix.base.models import Invoice, InvoiceAddress, Order, OrderPosition
|
||||
from pretix.base.models.orders import OrderFee
|
||||
from pretix.base.services.invoices import (
|
||||
generate_cancellation, generate_invoice,
|
||||
@@ -201,6 +201,7 @@ TEST_INVOICE_RES = {
|
||||
"invoice_from_tax_id": "",
|
||||
"invoice_from_vat_id": "",
|
||||
"invoice_to": "Sample company\nNew Zealand\nVAT-ID: DE123",
|
||||
"invoice_to_is_business": False,
|
||||
"invoice_to_company": "Sample company",
|
||||
"invoice_to_name": "",
|
||||
"invoice_to_street": "",
|
||||
@@ -210,6 +211,7 @@ TEST_INVOICE_RES = {
|
||||
"invoice_to_country": "NZ",
|
||||
"invoice_to_vat_id": "DE123",
|
||||
"invoice_to_beneficiary": "",
|
||||
"invoice_to_transmission_info": {},
|
||||
"custom_field": None,
|
||||
"date": "2017-12-10",
|
||||
"refers": None,
|
||||
@@ -260,7 +262,11 @@ TEST_INVOICE_RES = {
|
||||
"tax_name": "",
|
||||
"tax_rate": "19.00"
|
||||
}
|
||||
]
|
||||
],
|
||||
"transmission_type": "email",
|
||||
"transmission_provider": None,
|
||||
"transmission_status": "pending",
|
||||
"transmission_date": None
|
||||
}
|
||||
|
||||
|
||||
@@ -366,6 +372,26 @@ def test_invoice_detail(token_client, organizer, event, item, invoice):
|
||||
assert res == resp.data
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_invoice_retransmit(token_client, organizer, event, invoice):
|
||||
invoice.transmission_status = Invoice.TRANSMISSION_STATUS_INFLIGHT
|
||||
invoice.save()
|
||||
resp = token_client.post('/api/v1/organizers/{}/events/{}/invoices/{}/retransmit/'.format(
|
||||
organizer.slug, event.slug, invoice.number
|
||||
))
|
||||
assert resp.status_code == 409
|
||||
|
||||
invoice.transmission_status = Invoice.TRANSMISSION_STATUS_FAILED
|
||||
invoice.save()
|
||||
resp = token_client.post('/api/v1/organizers/{}/events/{}/invoices/{}/retransmit/'.format(
|
||||
organizer.slug, event.slug, invoice.number
|
||||
))
|
||||
assert resp.status_code == 204
|
||||
|
||||
invoice.refresh_from_db()
|
||||
assert invoice.transmission_status == Invoice.TRANSMISSION_STATUS_PENDING
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_invoice_regenerate(token_client, organizer, event, invoice):
|
||||
organizer.settings.invoice_regenerate_allowed = True
|
||||
|
||||
@@ -247,6 +247,147 @@ def test_order_update_state_validation(token_client, organizer, event, order):
|
||||
assert order.invoice_address.country == "AU"
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_order_update_transmission_validation(token_client, organizer, event, order):
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/events/{}/orders/{}/'.format(
|
||||
organizer.slug, event.slug, order.code
|
||||
), format='json', data={
|
||||
'invoice_address': {
|
||||
"is_business": False,
|
||||
"company": "This is my company name",
|
||||
"name": "John Doe",
|
||||
"name_parts": {},
|
||||
"street": "",
|
||||
"state": "",
|
||||
"zipcode": "",
|
||||
"city": "Paris",
|
||||
"country": "FR",
|
||||
"internal_reference": "",
|
||||
"vat_id": "",
|
||||
"transmission_type": "invalid",
|
||||
"transmission_info": {},
|
||||
}
|
||||
}
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
assert resp.data == {"invoice_address": {"transmission_type": ["Unknown transmission type."]}}
|
||||
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/events/{}/orders/{}/'.format(
|
||||
organizer.slug, event.slug, order.code
|
||||
), format='json', data={
|
||||
'invoice_address': {
|
||||
"is_business": True,
|
||||
"company": "This is my company name",
|
||||
"name": "John Doe",
|
||||
"name_parts": {},
|
||||
"street": "",
|
||||
"zipcode": "",
|
||||
"city": "Test",
|
||||
"country": "FR",
|
||||
"internal_reference": "",
|
||||
"vat_id": "",
|
||||
"transmission_type": "it_sdi",
|
||||
"transmission_info": {
|
||||
"transmission_it_sdi_pec": "foobar",
|
||||
},
|
||||
}
|
||||
}
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
assert resp.data == {"invoice_address": {
|
||||
"transmission_type": ["The selected transmission type is not available for this country or address type."]
|
||||
}}
|
||||
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/events/{}/orders/{}/'.format(
|
||||
organizer.slug, event.slug, order.code
|
||||
), format='json', data={
|
||||
'invoice_address': {
|
||||
"is_business": True,
|
||||
"company": "This is my company name",
|
||||
"name": "John Doe",
|
||||
"name_parts": {},
|
||||
"street": "",
|
||||
"zipcode": "",
|
||||
"city": "Test",
|
||||
"country": "IT",
|
||||
"internal_reference": "",
|
||||
"vat_id": "",
|
||||
"transmission_type": "it_sdi",
|
||||
"transmission_info": {
|
||||
"transmission_it_sdi_pec": "foobar",
|
||||
},
|
||||
}
|
||||
}
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
assert resp.data == {"invoice_address": {"transmission_info": {
|
||||
"transmission_it_sdi_pec": ["Enter a valid email address.", "Enter a valid email address."],
|
||||
"transmission_it_sdi_recipient_code": ["This field is required."]
|
||||
}}}
|
||||
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/events/{}/orders/{}/'.format(
|
||||
organizer.slug, event.slug, order.code
|
||||
), format='json', data={
|
||||
'invoice_address': {
|
||||
"is_business": True,
|
||||
"company": "This is my company name",
|
||||
"name": "John Doe",
|
||||
"name_parts": {},
|
||||
"street": "Via Da Vinci 1",
|
||||
"zipcode": "12345",
|
||||
"city": "Test",
|
||||
"country": "IT",
|
||||
"state": "MI",
|
||||
"internal_reference": "",
|
||||
"vat_id": "",
|
||||
"transmission_type": "it_sdi",
|
||||
"transmission_info": {
|
||||
"transmission_it_sdi_pec": "foobar@pec.it",
|
||||
"transmission_it_sdi_recipient_code": "1234567",
|
||||
},
|
||||
}
|
||||
}
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
assert resp.data == {
|
||||
"invoice_address": {"vat_id": ["This field is required for the selected type of invoice transmission."]}
|
||||
}
|
||||
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/events/{}/orders/{}/'.format(
|
||||
organizer.slug, event.slug, order.code
|
||||
), format='json', data={
|
||||
'invoice_address': {
|
||||
"is_business": True,
|
||||
"company": "This is my company name",
|
||||
"name": "John Doe",
|
||||
"name_parts": {},
|
||||
"street": "Via Una 1",
|
||||
"zipcode": "12345",
|
||||
"city": "Test",
|
||||
"country": "FR",
|
||||
"internal_reference": "",
|
||||
"vat_id": "",
|
||||
"transmission_type": "peppol",
|
||||
"transmission_info": {
|
||||
"transmission_peppol_participant_id": "9930:DE811569869",
|
||||
"ignored": "parameter",
|
||||
},
|
||||
}
|
||||
}
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
order.invoice_address.refresh_from_db()
|
||||
assert order.invoice_address.transmission_type == "peppol"
|
||||
assert order.invoice_address.transmission_info == {
|
||||
"transmission_peppol_participant_id": "9930:DE811569869",
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_order_update_allowed_fields(token_client, organizer, event, order):
|
||||
event.settings.locales = ['de', 'en']
|
||||
@@ -442,6 +583,7 @@ def test_order_create_invoice(token_client, organizer, event, order):
|
||||
"invoice_from_vat_id": "",
|
||||
"invoice_to": "Sample company\nNew Zealand\nVAT-ID: DE123",
|
||||
"invoice_to_company": "Sample company",
|
||||
"invoice_to_is_business": False,
|
||||
"invoice_to_name": "",
|
||||
"invoice_to_street": "",
|
||||
"invoice_to_zipcode": "",
|
||||
@@ -450,6 +592,7 @@ def test_order_create_invoice(token_client, organizer, event, order):
|
||||
"invoice_to_country": "NZ",
|
||||
"invoice_to_vat_id": "DE123",
|
||||
"invoice_to_beneficiary": "",
|
||||
"invoice_to_transmission_info": {},
|
||||
"custom_field": None,
|
||||
'date': now().astimezone(event.timezone).date().isoformat(),
|
||||
'refers': None,
|
||||
@@ -500,7 +643,11 @@ def test_order_create_invoice(token_client, organizer, event, order):
|
||||
'foreign_currency_display': None,
|
||||
'foreign_currency_rate': None,
|
||||
'foreign_currency_rate_date': None,
|
||||
'internal_reference': ''
|
||||
'internal_reference': '',
|
||||
'transmission_date': None,
|
||||
'transmission_provider': None,
|
||||
'transmission_status': 'pending',
|
||||
'transmission_type': 'email',
|
||||
}
|
||||
|
||||
resp = token_client.post(
|
||||
|
||||
@@ -436,7 +436,9 @@ def test_order_create_simulate(token_client, organizer, event, item, quota, ques
|
||||
'vat_id': '',
|
||||
'vat_id_validated': False,
|
||||
'internal_reference': '',
|
||||
'custom_field': None
|
||||
'custom_field': None,
|
||||
'transmission_type': 'email',
|
||||
'transmission_info': None,
|
||||
},
|
||||
'positions': [
|
||||
{
|
||||
@@ -590,6 +592,39 @@ def test_order_create_invoice_address_optional(token_client, organizer, event, i
|
||||
o.invoice_address
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_order_create_invoice_address_transmission_type_validation(token_client, organizer, event, item, quota, question):
|
||||
res = copy.deepcopy(ORDER_CREATE_PAYLOAD)
|
||||
res['positions'][0]['item'] = item.pk
|
||||
res['positions'][0]['answers'][0]['question'] = question.pk
|
||||
res['invoice_address'] = {
|
||||
"is_business": True,
|
||||
"company": "This is my company name",
|
||||
"name": "John Doe",
|
||||
"name_parts": {},
|
||||
"street": "",
|
||||
"zipcode": "",
|
||||
"city": "Test",
|
||||
"country": "FR",
|
||||
"internal_reference": "",
|
||||
"vat_id": "",
|
||||
"transmission_type": "it_sdi",
|
||||
"transmission_info": {
|
||||
"transmission_it_sdi_pec": "foobar@pec.it",
|
||||
"transmission_it_sdi_recipient_code": "1234567",
|
||||
},
|
||||
}
|
||||
resp = token_client.post(
|
||||
'/api/v1/organizers/{}/events/{}/orders/'.format(
|
||||
organizer.slug, event.slug
|
||||
), format='json', data=res
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
assert resp.data == {"invoice_address": {
|
||||
"transmission_type": ["The selected transmission type is not available for this country or address type."]
|
||||
}}
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_order_create_sales_channel_optional(token_client, organizer, event, item, quota, question):
|
||||
res = copy.deepcopy(ORDER_CREATE_PAYLOAD)
|
||||
|
||||
@@ -325,7 +325,9 @@ TEST_ORDER_RES = {
|
||||
"internal_reference": "",
|
||||
"custom_field": "Custom info",
|
||||
"vat_id": "DE123",
|
||||
"vat_id_validated": True
|
||||
"vat_id_validated": True,
|
||||
"transmission_type": "email",
|
||||
"transmission_info": None,
|
||||
},
|
||||
"require_approval": False,
|
||||
"valid_if_pending": False,
|
||||
|
||||
@@ -75,6 +75,7 @@ event_permission_sub_urls = [
|
||||
('get', 'can_view_orders', 'invoices/1/', 404),
|
||||
('post', 'can_change_orders', 'invoices/1/regenerate/', 404),
|
||||
('post', 'can_change_orders', 'invoices/1/reissue/', 404),
|
||||
('post', 'can_change_orders', 'invoices/1/retransmit/', 404),
|
||||
('get', 'can_view_orders', 'waitinglistentries/', 200),
|
||||
('get', 'can_view_orders', 'waitinglistentries/1/', 404),
|
||||
('post', 'can_change_orders', 'waitinglistentries/', 400),
|
||||
|
||||
234
src/tests/base/test_js_helpers.py
Normal file
234
src/tests/base/test_js_helpers.py
Normal file
@@ -0,0 +1,234 @@
|
||||
#
|
||||
# This file is part of pretix (Community Edition).
|
||||
#
|
||||
# Copyright (C) 2014-2020 Raphael Michel and contributors
|
||||
# Copyright (C) 2020-2021 rami.io GmbH and contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
|
||||
# Public License as published by the Free Software Foundation in version 3 of the License.
|
||||
#
|
||||
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
|
||||
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
|
||||
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
|
||||
# this file, see <https://pretix.eu/about/en/license>.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
import pytest
|
||||
from django.utils.timezone import now
|
||||
from django_scopes import scopes_disabled
|
||||
|
||||
from pretix.base.models import Event, Organizer
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_no_invoice_address(client):
|
||||
response = client.get('/js_helpers/address_form/?country=DE')
|
||||
assert response.json() == {
|
||||
'city': {'required': 'if_any'},
|
||||
'data': [],
|
||||
'state': {'label': 'State', 'required': False, 'visible': False},
|
||||
'street': {'required': 'if_any'},
|
||||
'vat_id': {'required': False, 'visible': True},
|
||||
'zipcode': {'required': 'if_any'}
|
||||
}
|
||||
|
||||
response = client.get('/js_helpers/address_form/?country=CR')
|
||||
assert response.json() == {
|
||||
'city': {'required': False},
|
||||
'data': [],
|
||||
'state': {'label': 'State', 'required': False, 'visible': False},
|
||||
'street': {'required': 'if_any'},
|
||||
'vat_id': {'required': False, 'visible': False},
|
||||
'zipcode': {'required': False}
|
||||
}
|
||||
|
||||
response = client.get('/js_helpers/address_form/?country=US')
|
||||
d = response.json()
|
||||
assert d['state'] == {'label': 'State', 'required': 'if_any', 'visible': True}
|
||||
assert d['data'][0] == {'code': 'AL', 'name': 'Alabama'}
|
||||
|
||||
response = client.get('/js_helpers/address_form/?country=IT')
|
||||
d = response.json()
|
||||
assert d['state'] == {'label': 'Province', 'required': 'if_any', 'visible': True}
|
||||
assert d['data'][0] == {'code': 'AG', 'name': 'Agrigento'}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@scopes_disabled()
|
||||
def event():
|
||||
o = Organizer.objects.create(name='Dummy', slug='org')
|
||||
event = Event.objects.create(
|
||||
organizer=o, name='Dummy', slug='ev',
|
||||
date_from=now(), plugins='tests.testdummy'
|
||||
)
|
||||
return event
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_invalid_event(client):
|
||||
response = client.get(
|
||||
'/js_helpers/address_form/?country=DE&invoice=true&organizer=test&event=test'
|
||||
)
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_provider_only_email_available(client, event):
|
||||
response = client.get(
|
||||
'/js_helpers/address_form/?country=DE&invoice=true&organizer=org&event=ev&transmission_type_required=true'
|
||||
)
|
||||
assert response.status_code == 200
|
||||
d = response.json()
|
||||
assert d == {
|
||||
'city': {'required': 'if_any'},
|
||||
'data': [],
|
||||
'state': {'label': 'State', 'required': False, 'visible': False},
|
||||
'street': {'required': 'if_any'},
|
||||
'transmission_email_address': {'required': False, 'visible': False},
|
||||
'transmission_email_other': {'required': False, 'visible': False},
|
||||
'transmission_it_sdi_codice_fiscale': {'required': False, 'visible': False},
|
||||
'transmission_it_sdi_pec': {'required': False, 'visible': False},
|
||||
'transmission_it_sdi_recipient_code': {'required': False, 'visible': False},
|
||||
'transmission_peppol_participant_id': {'required': False, 'visible': False},
|
||||
'transmission_type': {'visible': False},
|
||||
'transmission_types': [{'code': 'email', 'name': 'Email'}],
|
||||
'vat_id': {'required': False, 'visible': True},
|
||||
'zipcode': {'required': 'if_any'}
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_provider_italy_sdi_not_enforced_when_optional(client, event):
|
||||
response = client.get(
|
||||
'/js_helpers/address_form/?country=IT&invoice=true&organizer=org&event=ev&transmission_type_required=false'
|
||||
)
|
||||
assert response.status_code == 200
|
||||
d = response.json()
|
||||
del d['data']
|
||||
assert d == {
|
||||
'city': {'required': 'if_any'},
|
||||
'state': {'label': 'Province', 'required': 'if_any', 'visible': True},
|
||||
'street': {'required': 'if_any'},
|
||||
'transmission_email_address': {'required': False, 'visible': False},
|
||||
'transmission_email_other': {'required': False, 'visible': False},
|
||||
'transmission_it_sdi_codice_fiscale': {'required': False, 'visible': False},
|
||||
'transmission_it_sdi_pec': {'required': False, 'visible': False},
|
||||
'transmission_it_sdi_recipient_code': {'required': False, 'visible': False},
|
||||
'transmission_peppol_participant_id': {'required': False, 'visible': False},
|
||||
'transmission_type': {'visible': True},
|
||||
'transmission_types': [{'code': 'it_sdi', 'name': 'Exchange System (SdI)'}],
|
||||
'vat_id': {'required': False, 'visible': True},
|
||||
'zipcode': {'required': 'if_any'}
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_provider_italy_sdi_enforced_individual(client, event):
|
||||
response = client.get(
|
||||
'/js_helpers/address_form/?country=IT&invoice=true&organizer=org&event=ev&transmission_type_required=true'
|
||||
)
|
||||
assert response.status_code == 200
|
||||
d = response.json()
|
||||
del d['data']
|
||||
assert d == {
|
||||
'city': {'required': True},
|
||||
'state': {'label': 'Province', 'required': True, 'visible': True},
|
||||
'street': {'required': True},
|
||||
'transmission_email_address': {'required': False, 'visible': False},
|
||||
'transmission_email_other': {'required': False, 'visible': False},
|
||||
'transmission_it_sdi_codice_fiscale': {'required': True, 'visible': True},
|
||||
'transmission_it_sdi_pec': {'required': False, 'visible': True},
|
||||
'transmission_it_sdi_recipient_code': {'required': False, 'visible': False},
|
||||
'transmission_peppol_participant_id': {'required': False, 'visible': False},
|
||||
'transmission_type': {'visible': True},
|
||||
'transmission_types': [{'code': 'it_sdi', 'name': 'Exchange System (SdI)'}],
|
||||
'vat_id': {'required': False, 'visible': True},
|
||||
'zipcode': {'required': True}
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_provider_italy_sdi_enforced_business(client, event):
|
||||
response = client.get(
|
||||
'/js_helpers/address_form/?country=IT&invoice=true&organizer=org&event=ev&transmission_type_required=true'
|
||||
'&is_business=business'
|
||||
)
|
||||
assert response.status_code == 200
|
||||
d = response.json()
|
||||
del d['data']
|
||||
assert d == {
|
||||
'city': {'required': True},
|
||||
'state': {'label': 'Province', 'required': True, 'visible': True},
|
||||
'street': {'required': True},
|
||||
'transmission_email_address': {'required': False, 'visible': False},
|
||||
'transmission_email_other': {'required': False, 'visible': False},
|
||||
'transmission_it_sdi_codice_fiscale': {'required': False, 'visible': True},
|
||||
'transmission_it_sdi_pec': {'required': True, 'visible': True},
|
||||
'transmission_it_sdi_recipient_code': {'required': True, 'visible': True},
|
||||
'transmission_peppol_participant_id': {'required': False, 'visible': False},
|
||||
'transmission_type': {'visible': True},
|
||||
'transmission_types': [{'code': 'it_sdi', 'name': 'Exchange System (SdI)'}],
|
||||
'vat_id': {'required': True, 'visible': True},
|
||||
'zipcode': {'required': True}
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_email_peppol_choice(client, event):
|
||||
response = client.get(
|
||||
'/js_helpers/address_form/?country=DE&invoice=true&organizer=org&event=ev'
|
||||
'&is_business=business&transmission_type_required=true'
|
||||
)
|
||||
assert response.status_code == 200
|
||||
d = response.json()
|
||||
assert d == {
|
||||
'city': {'required': 'if_any'},
|
||||
'data': [],
|
||||
'state': {'label': 'State', 'required': False, 'visible': False},
|
||||
'street': {'required': 'if_any'},
|
||||
'transmission_email_address': {'required': False, 'visible': True},
|
||||
'transmission_email_other': {'required': False, 'visible': True},
|
||||
'transmission_it_sdi_codice_fiscale': {'required': False, 'visible': False},
|
||||
'transmission_it_sdi_pec': {'required': False, 'visible': False},
|
||||
'transmission_it_sdi_recipient_code': {'required': False, 'visible': False},
|
||||
'transmission_peppol_participant_id': {'required': False, 'visible': False},
|
||||
'transmission_type': {'visible': True},
|
||||
'transmission_types': [
|
||||
{'code': 'email', 'name': 'Email'},
|
||||
{'code': 'peppol', 'name': 'PEPPOL'},
|
||||
],
|
||||
'vat_id': {'required': False, 'visible': True},
|
||||
'zipcode': {'required': 'if_any'}
|
||||
}
|
||||
|
||||
response = client.get(
|
||||
'/js_helpers/address_form/?country=DE&invoice=true&organizer=org&event=ev'
|
||||
'&is_business=business&transmission_type=peppol'
|
||||
)
|
||||
assert response.status_code == 200
|
||||
d = response.json()
|
||||
assert d == {
|
||||
'city': {'required': True},
|
||||
'data': [],
|
||||
'state': {'label': 'State', 'required': False, 'visible': False},
|
||||
'street': {'required': True},
|
||||
'transmission_email_address': {'required': False, 'visible': False},
|
||||
'transmission_email_other': {'required': False, 'visible': False},
|
||||
'transmission_it_sdi_codice_fiscale': {'required': False, 'visible': False},
|
||||
'transmission_it_sdi_pec': {'required': False, 'visible': False},
|
||||
'transmission_it_sdi_recipient_code': {'required': False, 'visible': False},
|
||||
'transmission_peppol_participant_id': {'required': True, 'visible': True},
|
||||
'transmission_type': {'visible': True},
|
||||
'transmission_types': [
|
||||
{'code': 'email', 'name': 'Email'},
|
||||
{'code': 'peppol', 'name': 'PEPPOL'},
|
||||
],
|
||||
'vat_id': {'required': False, 'visible': True},
|
||||
'zipcode': {'required': True}
|
||||
}
|
||||
@@ -34,12 +34,13 @@ from django.utils.timezone import make_aware, now
|
||||
from django_countries.fields import Country
|
||||
from django_scopes import scope
|
||||
from freezegun import freeze_time
|
||||
from i18nfield.strings import LazyI18nString
|
||||
from tests.testdummy.signals import FoobazSalesChannel
|
||||
|
||||
from pretix.base.decimal import round_decimal
|
||||
from pretix.base.models import (
|
||||
CartPosition, Event, GiftCard, InvoiceAddress, Item, Order, OrderPosition,
|
||||
Organizer, SeatingPlan,
|
||||
CartPosition, Event, GiftCard, Invoice, InvoiceAddress, Item, Order,
|
||||
OrderPosition, Organizer, SeatingPlan,
|
||||
)
|
||||
from pretix.base.models.items import SubEventItem
|
||||
from pretix.base.models.orders import OrderFee, OrderPayment, OrderRefund
|
||||
@@ -48,7 +49,9 @@ from pretix.base.payment import (
|
||||
)
|
||||
from pretix.base.reldate import RelativeDate, RelativeDateWrapper
|
||||
from pretix.base.secrets import assign_ticket_secret
|
||||
from pretix.base.services.invoices import generate_invoice
|
||||
from pretix.base.services.invoices import (
|
||||
generate_cancellation, generate_invoice,
|
||||
)
|
||||
from pretix.base.services.orders import (
|
||||
OrderChangeManager, OrderError, _create_order, approve_order, cancel_order,
|
||||
deny_order, expire_orders, reactivate_order, send_download_reminders,
|
||||
@@ -573,6 +576,83 @@ def test_approve_send_to_attendees(event):
|
||||
assert 'awaiting payment' not in djmail.outbox[1].subject
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_approve_mail_invoice_attached(event):
|
||||
djmail.outbox = []
|
||||
event.settings.invoice_address_asked = True
|
||||
event.settings.invoice_address_required = True
|
||||
event.settings.invoice_generate = "True"
|
||||
event.settings.invoice_email_attachment = True
|
||||
o1 = Order.objects.create(
|
||||
code='FOO', event=event, email='dummy@dummy.test',
|
||||
status=Order.STATUS_PENDING,
|
||||
datetime=now(), expires=now() - timedelta(days=10),
|
||||
total=10, require_approval=True, locale='en',
|
||||
sales_channel=event.organizer.sales_channels.get(identifier="web"),
|
||||
)
|
||||
ticket = Item.objects.create(event=event, name='Early-bird ticket',
|
||||
default_price=Decimal('23.00'), admission=True)
|
||||
OrderPosition.objects.create(
|
||||
order=o1, item=ticket, variation=None, price=Decimal("23.00"),
|
||||
attendee_name_parts={'full_name': "Peter"},
|
||||
positionid=1
|
||||
)
|
||||
InvoiceAddress.objects.create(
|
||||
order=o1,
|
||||
is_business=True,
|
||||
country=Country('AT'),
|
||||
transmission_type="email",
|
||||
transmission_info={}
|
||||
)
|
||||
o1.create_transactions()
|
||||
assert o1.transactions.count() == 0
|
||||
approve_order(o1)
|
||||
o1.refresh_from_db()
|
||||
assert len(djmail.outbox) == 1
|
||||
assert any(["Invoice_" in a[0] for a in djmail.outbox[0].attachments])
|
||||
|
||||
|
||||
@pytest.mark.django_db(transaction=True)
|
||||
def test_approve_mail_invoice_sent_somewhere_else(event):
|
||||
djmail.outbox = []
|
||||
event.settings.invoice_address_asked = True
|
||||
event.settings.invoice_address_required = True
|
||||
event.settings.invoice_generate = "True"
|
||||
event.settings.invoice_email_attachment = True
|
||||
o1 = Order.objects.create(
|
||||
code='FOO', event=event, email='dummy@dummy.test',
|
||||
status=Order.STATUS_PENDING,
|
||||
datetime=now(), expires=now() - timedelta(days=10),
|
||||
total=10, require_approval=True, locale='en',
|
||||
sales_channel=event.organizer.sales_channels.get(identifier="web"),
|
||||
)
|
||||
ticket = Item.objects.create(event=event, name='Early-bird ticket',
|
||||
default_price=Decimal('23.00'), admission=True)
|
||||
OrderPosition.objects.create(
|
||||
order=o1, item=ticket, variation=None, price=Decimal("23.00"),
|
||||
attendee_name_parts={'full_name': "Peter"},
|
||||
positionid=1
|
||||
)
|
||||
InvoiceAddress.objects.create(
|
||||
order=o1,
|
||||
is_business=True,
|
||||
country=Country('AT'),
|
||||
transmission_type="email",
|
||||
transmission_info={
|
||||
"transmission_email_address": "invoice@example.org",
|
||||
}
|
||||
)
|
||||
o1.create_transactions()
|
||||
assert o1.transactions.count() == 0
|
||||
approve_order(o1)
|
||||
o1.refresh_from_db()
|
||||
assert len(djmail.outbox) == 2
|
||||
assert ["invoice@example.org"] == djmail.outbox[0].to
|
||||
assert any(["Invoice_" in a[0] for a in djmail.outbox[0].attachments])
|
||||
assert ["dummy@dummy.test"] == djmail.outbox[1].to
|
||||
assert not any(["Invoice_" in a[0] for a in djmail.outbox[1].attachments])
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_approve_free(event):
|
||||
djmail.outbox = []
|
||||
@@ -670,6 +750,67 @@ def test_deny(event):
|
||||
assert 'denied' in djmail.outbox[0].subject
|
||||
|
||||
|
||||
@pytest.mark.django_db(transaction=True)
|
||||
def test_mark_invoices_as_sent(event):
|
||||
djmail.outbox = []
|
||||
event.settings.invoice_address_asked = True
|
||||
event.settings.invoice_address_required = True
|
||||
event.settings.invoice_generate = "True"
|
||||
event.settings.invoice_email_attachment = True
|
||||
o1 = Order.objects.create(
|
||||
code='FOO', event=event, email='dummy@dummy.test',
|
||||
status=Order.STATUS_PENDING,
|
||||
datetime=now(), expires=now() - timedelta(days=10),
|
||||
total=10, locale='en',
|
||||
sales_channel=event.organizer.sales_channels.get(identifier="web"),
|
||||
)
|
||||
ticket = Item.objects.create(event=event, name='Early-bird ticket',
|
||||
default_price=Decimal('23.00'), admission=True)
|
||||
OrderPosition.objects.create(
|
||||
order=o1, item=ticket, variation=None, price=Decimal("23.00"),
|
||||
attendee_name_parts={'full_name': "Peter"},
|
||||
positionid=1
|
||||
)
|
||||
ia = InvoiceAddress.objects.create(
|
||||
order=o1,
|
||||
is_business=True,
|
||||
country=Country('AT'),
|
||||
transmission_type="email",
|
||||
transmission_info={
|
||||
"transmission_email_address": "invoice@example.org",
|
||||
}
|
||||
)
|
||||
o1.create_transactions()
|
||||
i = generate_invoice(o1)
|
||||
assert i.transmission_type == "email"
|
||||
assert i.transmission_status == Invoice.TRANSMISSION_STATUS_PENDING
|
||||
assert not i.transmission_provider
|
||||
|
||||
# Not marked as sent because it is not the right address
|
||||
o1.send_mail(
|
||||
subject=LazyI18nString({"en": "Hey"}),
|
||||
template=LazyI18nString({"en": "Just wanted to send this invoice"}),
|
||||
context={},
|
||||
invoices=[i]
|
||||
)
|
||||
i.refresh_from_db()
|
||||
assert i.transmission_type == "email"
|
||||
assert i.transmission_status == Invoice.TRANSMISSION_STATUS_PENDING
|
||||
|
||||
# If no other address is there, order address will be accepted
|
||||
ia.transmission_info = {}
|
||||
ia.save()
|
||||
o1.send_mail(
|
||||
subject=LazyI18nString({"en": "Hey"}),
|
||||
template=LazyI18nString({"en": "Just wanted to send this invoice"}),
|
||||
context={},
|
||||
invoices=[i]
|
||||
)
|
||||
i.refresh_from_db()
|
||||
assert i.transmission_status == Invoice.TRANSMISSION_STATUS_COMPLETED
|
||||
assert i.transmission_provider == "email_pdf"
|
||||
|
||||
|
||||
class PaymentReminderTests(TestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
@@ -1033,6 +1174,12 @@ class DownloadReminderTests(TestCase):
|
||||
assert len(djmail.outbox) == 0
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def class_monkeypatch(request, monkeypatch):
|
||||
request.cls.monkeypatch = monkeypatch
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("class_monkeypatch")
|
||||
class OrderCancelTests(TestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
@@ -1060,6 +1207,7 @@ class OrderCancelTests(TestCase):
|
||||
self.order.create_transactions()
|
||||
generate_invoice(self.order)
|
||||
djmail.outbox = []
|
||||
self.monkeypatch.setattr("django.db.transaction.on_commit", lambda t: t())
|
||||
|
||||
@classscope(attr='o')
|
||||
def test_cancel_canceled(self):
|
||||
@@ -1111,6 +1259,56 @@ class OrderCancelTests(TestCase):
|
||||
assert self.order.transactions.count() == 4
|
||||
assert self.order.transactions.aggregate(s=Sum(F('price') * F('count')))['s'] == Decimal('0.00')
|
||||
|
||||
@classscope(attr='o')
|
||||
def test_cancel_mail_invoice_attached(self):
|
||||
self.event.settings.invoice_generate = "True"
|
||||
self.event.settings.invoice_email_attachment = True
|
||||
InvoiceAddress.objects.update_or_create(
|
||||
order=self.order,
|
||||
defaults=dict(
|
||||
is_business=True,
|
||||
country=Country('AT'),
|
||||
transmission_type="email",
|
||||
transmission_info={}
|
||||
)
|
||||
)
|
||||
self.order.status = Order.STATUS_PAID
|
||||
self.order.save()
|
||||
djmail.outbox = []
|
||||
cancel_order(self.order.pk, send_mail=True)
|
||||
assert len(djmail.outbox) == 1
|
||||
assert any(["Invoice_" in a[0] for a in djmail.outbox[0].attachments])
|
||||
|
||||
@classscope(attr='o')
|
||||
def test_cancel_mail_invoice_sent_somewhere_else(self):
|
||||
self.event.settings.invoice_generate = "True"
|
||||
self.event.settings.invoice_email_attachment = True
|
||||
InvoiceAddress.objects.update_or_create(
|
||||
order=self.order,
|
||||
defaults=dict(
|
||||
is_business=True,
|
||||
country=Country('AT'),
|
||||
transmission_type="email",
|
||||
transmission_info={
|
||||
"transmission_email_address": "invoice@example.org",
|
||||
}
|
||||
)
|
||||
)
|
||||
# Recreate invoice because otherwise it will be sent where the original was sent
|
||||
generate_cancellation(self.order.invoices.get())
|
||||
generate_invoice(self.order)
|
||||
self.order.status = Order.STATUS_PAID
|
||||
self.order.save()
|
||||
djmail.outbox = []
|
||||
cancel_order(self.order.pk, send_mail=True)
|
||||
print([s.subject for s in djmail.outbox])
|
||||
print([s.to for s in djmail.outbox])
|
||||
assert len(djmail.outbox) == 2
|
||||
assert ["invoice@example.org"] == djmail.outbox[0].to
|
||||
assert any(["Invoice_" in a[0] for a in djmail.outbox[0].attachments])
|
||||
assert ["dummy@dummy.test"] == djmail.outbox[1].to
|
||||
assert not any(["Invoice_" in a[0] for a in djmail.outbox[1].attachments])
|
||||
|
||||
@classscope(attr='o')
|
||||
def test_cancel_paid_with_too_high_fee(self):
|
||||
self.order.status = Order.STATUS_PAID
|
||||
@@ -1239,6 +1437,7 @@ class OrderCancelTests(TestCase):
|
||||
assert self.order.all_logentries().filter(action_type='pretix.event.order.refund.requested').exists()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("class_monkeypatch")
|
||||
class OrderChangeManagerTests(TestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
@@ -1247,6 +1446,7 @@ class OrderChangeManagerTests(TestCase):
|
||||
self.event = Event.objects.create(organizer=self.o, name='Dummy', slug='dummy', date_from=now(),
|
||||
plugins='pretix.plugins.banktransfer')
|
||||
self.event.settings.invoice_generate = "True"
|
||||
self.event.settings.invoice_email_attachment = True
|
||||
self.order = Order.objects.create(
|
||||
code='FOO', event=self.event, email='dummy@dummy.test',
|
||||
status=Order.STATUS_PENDING, locale='en',
|
||||
@@ -1301,6 +1501,7 @@ class OrderChangeManagerTests(TestCase):
|
||||
self.seat_a1 = self.event.seats.create(seat_number="A1", product=self.stalls, seat_guid="A1")
|
||||
self.seat_a2 = self.event.seats.create(seat_number="A2", product=self.stalls, seat_guid="A2")
|
||||
self.seat_a3 = self.event.seats.create(seat_number="A3", product=self.stalls, seat_guid="A3")
|
||||
self.monkeypatch.setattr("django.db.transaction.on_commit", lambda t: t())
|
||||
|
||||
def _enable_reverse_charge(self):
|
||||
self.tr7.eu_reverse_charge = True
|
||||
@@ -3525,6 +3726,79 @@ class OrderChangeManagerTests(TestCase):
|
||||
assert self.op1.valid_from is None
|
||||
assert self.op1.valid_until is None
|
||||
|
||||
@classscope(attr='o')
|
||||
def test_new_invoice_attached(self):
|
||||
generate_invoice(self.order)
|
||||
assert self.order.invoices.count() == 1
|
||||
djmail.outbox = []
|
||||
self.ocm.add_position(self.ticket, None, Decimal('0.00'))
|
||||
self.ocm.commit()
|
||||
assert self.order.invoices.count() == 3
|
||||
assert len(djmail.outbox) == 1
|
||||
assert len(["Invoice_" in a[0] for a in djmail.outbox[0].attachments]) == 2
|
||||
|
||||
@classscope(attr='o')
|
||||
def test_new_invoice_send_somewhere_else(self):
|
||||
generate_invoice(self.order)
|
||||
assert self.order.invoices.count() == 1
|
||||
|
||||
InvoiceAddress.objects.update_or_create(
|
||||
order=self.order,
|
||||
defaults=dict(
|
||||
is_business=True,
|
||||
country=Country('AT'),
|
||||
transmission_type="email",
|
||||
transmission_info={
|
||||
"transmission_email_address": "invoice@example.org",
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
djmail.outbox = []
|
||||
self.ocm.add_position(self.ticket, None, Decimal('0.00'))
|
||||
self.ocm.commit()
|
||||
assert self.order.invoices.count() == 3
|
||||
|
||||
# Cancellation is still sent to old method!
|
||||
assert len(djmail.outbox) == 2
|
||||
assert ["dummy@dummy.test"] == djmail.outbox[0].to
|
||||
assert len(["Invoice_" in a[0] for a in djmail.outbox[0].attachments]) == 1
|
||||
assert ["invoice@example.org"] == djmail.outbox[1].to
|
||||
assert len(["Invoice_" in a[0] for a in djmail.outbox[1].attachments]) == 1
|
||||
|
||||
@classscope(attr='o')
|
||||
def test_new_invoice_split_send_somewhere_else(self):
|
||||
generate_invoice(self.order)
|
||||
assert self.order.invoices.count() == 1
|
||||
|
||||
InvoiceAddress.objects.update_or_create(
|
||||
order=self.order,
|
||||
defaults=dict(
|
||||
is_business=True,
|
||||
country=Country('AT'),
|
||||
transmission_type="email",
|
||||
transmission_info={
|
||||
"transmission_email_address": "invoice@example.org",
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
djmail.outbox = []
|
||||
self.ocm.split(self.op2)
|
||||
self.ocm.commit()
|
||||
assert self.order.invoices.count() == 3
|
||||
|
||||
# Cancellation is still sent to old method!
|
||||
assert len(djmail.outbox) == 4
|
||||
assert ["dummy@dummy.test"] == djmail.outbox[0].to
|
||||
assert len(["Invoice_" in a[0] for a in djmail.outbox[0].attachments]) == 1
|
||||
assert ["dummy@dummy.test"] == djmail.outbox[1].to
|
||||
assert len(["Invoice_" in a[0] for a in djmail.outbox[1].attachments]) == 0
|
||||
assert ["invoice@example.org"] == djmail.outbox[2].to
|
||||
assert len(["Invoice_" in a[0] for a in djmail.outbox[2].attachments]) == 1
|
||||
assert ["invoice@example.org"] == djmail.outbox[3].to
|
||||
assert len(["Invoice_" in a[0] for a in djmail.outbox[3].attachments]) == 1
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_saleschannel_testmode_restriction(event):
|
||||
|
||||
@@ -208,14 +208,20 @@ def test_invoice_address_shredder(event, order):
|
||||
'pretix.event.order.modified',
|
||||
data={
|
||||
"data": [{"attendee_name": "Hans", "question_1": "Test"}],
|
||||
"invoice_data": {"name": "Peter", "country": "DE", "is_business": False, "internal_reference": "",
|
||||
"state": "",
|
||||
"company": "ACME", "street": "Sesam Street", "city": "Sample City", "zipcode": "12345"}
|
||||
"invoice_data": {
|
||||
"name": "Peter", "country": "DE", "is_business": False, "internal_reference": "",
|
||||
"state": "", "company": "ACME", "street": "Sesam Street", "city": "Sample City", "zipcode": "12345",
|
||||
"transmission_type": "email", "transmission_info": {"transmission_email_address": "other@example.org"}
|
||||
}
|
||||
}
|
||||
)
|
||||
ia = InvoiceAddress.objects.create(
|
||||
company='Acme Company', street='221B Baker Street',
|
||||
zipcode='12345', city='London', country='UK',
|
||||
order=order, transmission_type="email", transmission_info={
|
||||
"transmission_email_address": "other@example.org"
|
||||
}
|
||||
)
|
||||
ia = InvoiceAddress.objects.create(company='Acme Company', street='221B Baker Street',
|
||||
zipcode='12345', city='London', country='UK',
|
||||
order=order)
|
||||
s = InvoiceAddressShredder(event)
|
||||
f = list(s.generate_files())
|
||||
assert json.loads(f[0][2]) == {
|
||||
@@ -233,7 +239,9 @@ def test_invoice_address_shredder(event, order):
|
||||
'street': '221B Baker Street',
|
||||
'vat_id': '',
|
||||
'vat_id_validated': False,
|
||||
'zipcode': '12345'
|
||||
'zipcode': '12345',
|
||||
"transmission_type": "email",
|
||||
"transmission_info": {"transmission_email_address": "other@example.org"}
|
||||
}
|
||||
}
|
||||
s.shred_data()
|
||||
@@ -243,7 +251,9 @@ def test_invoice_address_shredder(event, order):
|
||||
assert l1.parsed_data == {
|
||||
"data": [{"attendee_name": "Hans", "question_1": "Test"}],
|
||||
"invoice_data": {"name": "█", "country": "█", "is_business": False, "internal_reference": "", "company": "█",
|
||||
"street": "█", "city": "█", "zipcode": "█", "state": ""}
|
||||
"street": "█", "city": "█", "zipcode": "█", "state": "",
|
||||
"transmission_type": "email",
|
||||
"transmission_info": {"_shredded": True}}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -47,9 +47,9 @@ from tests.plugins.stripe.test_checkout import apple_domain_create
|
||||
from tests.plugins.stripe.test_provider import MockedCharge
|
||||
|
||||
from pretix.base.models import (
|
||||
Event, GiftCard, InvoiceAddress, Item, Order, OrderFee, OrderPayment,
|
||||
OrderPosition, OrderRefund, Organizer, Question, QuestionAnswer, Quota,
|
||||
Team, User,
|
||||
Event, GiftCard, Invoice, InvoiceAddress, Item, Order, OrderFee,
|
||||
OrderPayment, OrderPosition, OrderRefund, Organizer, Question,
|
||||
QuestionAnswer, Quota, Team, User,
|
||||
)
|
||||
from pretix.base.payment import PaymentException
|
||||
from pretix.base.services.invoices import (
|
||||
@@ -625,6 +625,19 @@ def test_order_invoice_create_ok(client, env):
|
||||
assert env[2].invoices.exists()
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_order_invoice_retransmit(client, env):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
with scopes_disabled():
|
||||
i = generate_invoice(env[2])
|
||||
i.transmission_status = Invoice.TRANSMISSION_STATUS_FAILED
|
||||
i.save()
|
||||
response = client.post('/control/event/dummy/dummy/orders/FOO/invoices/%d/retransmit' % i.pk, {}, follow=True)
|
||||
assert 'alert-success' in response.content.decode()
|
||||
i.refresh_from_db()
|
||||
assert i.transmission_status == Invoice.TRANSMISSION_STATUS_PENDING
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_order_invoice_regenerate(client, env):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
#
|
||||
# This file is part of pretix (Community Edition).
|
||||
#
|
||||
# Copyright (C) 2014-2020 Raphael Michel and contributors
|
||||
# Copyright (C) 2020-2021 rami.io GmbH and contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
|
||||
# Public License as published by the Free Software Foundation in version 3 of the License.
|
||||
#
|
||||
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
|
||||
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
|
||||
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
|
||||
# this file, see <https://pretix.eu/about/en/license>.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# This file is based on an earlier version of pretix which was released under the Apache License 2.0. The full text of
|
||||
# the Apache License 2.0 can be obtained at <http://www.apache.org/licenses/LICENSE-2.0>.
|
||||
#
|
||||
# This file may have since been changed and any changes are released under the terms of AGPLv3 as described above. A
|
||||
# full history of changes and contributors is available at <https://github.com/pretix/pretix>.
|
||||
#
|
||||
# This file contains Apache-licensed contributions copyrighted by: Flavia Bastos
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is
|
||||
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations under the License.
|
||||
|
||||
from django.core import mail as djmail
|
||||
from django_countries.fields import Country
|
||||
from django_scopes import scopes_disabled
|
||||
from tests.presale.test_orders import BaseOrdersTest
|
||||
|
||||
from pretix.base.models import InvoiceAddress, OrderPayment
|
||||
from pretix.base.services.invoices import generate_invoice
|
||||
|
||||
|
||||
class BanktransferOrdersTest(BaseOrdersTest):
|
||||
def test_unknown_order(self):
|
||||
response = self.client.post(
|
||||
'/%s/%s/banktransfer/ABCDE/123/mail-invoice/' % (self.orga.slug, self.event.slug)
|
||||
)
|
||||
assert response.status_code == 404
|
||||
response = self.client.post(
|
||||
'/%s/%s/banktransfer/%s/123/mail-invoice/' % (self.orga.slug, self.event.slug, self.not_my_order.code)
|
||||
)
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_order_with_no_invoice(self):
|
||||
djmail.outbox = []
|
||||
response = self.client.post(
|
||||
'/%s/%s/banktransfer/%s/%s/mail-invoice/' % (
|
||||
self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
||||
{'email': 'test@example.org'}
|
||||
)
|
||||
assert response.status_code == 302
|
||||
|
||||
from django.contrib.messages import get_messages
|
||||
messages = list(get_messages(response.wsgi_request))
|
||||
assert len(messages) == 1
|
||||
assert str(messages[0]) == 'No pending bank transfer payment found. Maybe the order has been paid already?'
|
||||
assert len(djmail.outbox) == 0
|
||||
|
||||
def test_valid_order(self):
|
||||
with scopes_disabled():
|
||||
self.event.settings.set('payment_banktransfer_invoice_email', True)
|
||||
self.order.payments.create(provider='banktransfer', state=OrderPayment.PAYMENT_STATE_CREATED,
|
||||
amount=self.order.total)
|
||||
InvoiceAddress.objects.create(order=self.order, company="Sample company", country=Country('NZ'))
|
||||
generate_invoice(self.order)
|
||||
|
||||
djmail.outbox = []
|
||||
response = self.client.post(
|
||||
'/%s/%s/banktransfer/%s/%s/mail-invoice/' % (
|
||||
self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
||||
{'email': 'test@example.org'}
|
||||
)
|
||||
assert response.status_code == 302
|
||||
|
||||
from django.contrib.messages import get_messages
|
||||
messages = list(get_messages(response.wsgi_request))
|
||||
assert len(messages) == 1
|
||||
assert str(messages[0]) == 'Sending the latest invoice via email to test@example.org.'
|
||||
assert len(djmail.outbox) == 1
|
||||
@@ -60,6 +60,12 @@ from pretix.testutils.sessions import get_cart_session_key
|
||||
from .test_timemachine import TimemachineTestMixin
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def class_monkeypatch(request, monkeypatch):
|
||||
request.cls.monkeypatch = monkeypatch
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("class_monkeypatch")
|
||||
class BaseCheckoutTestCase:
|
||||
@scopes_disabled()
|
||||
def setUp(self):
|
||||
@@ -98,6 +104,7 @@ class BaseCheckoutTestCase:
|
||||
self.workshopquota.items.add(self.workshop2)
|
||||
self.workshopquota.variations.add(self.workshop2a)
|
||||
self.workshopquota.variations.add(self.workshop2b)
|
||||
self.monkeypatch.setattr("django.db.transaction.on_commit", lambda t: t())
|
||||
|
||||
def _set_session(self, key, value):
|
||||
session = self.client.session
|
||||
@@ -169,7 +176,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
'zipcode': '1234',
|
||||
'city': 'Here',
|
||||
'country': 'AT',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
assert b'TRACKING SCRIPT' not in payment_r.content
|
||||
|
||||
@@ -201,7 +209,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
'city': 'Here',
|
||||
'country': 'AT',
|
||||
'vat_id': 'AT123456',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
|
||||
cr1.refresh_from_db()
|
||||
@@ -224,7 +233,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
'city': 'Here',
|
||||
'country': 'AT',
|
||||
'vat_id': '',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
|
||||
with scopes_disabled():
|
||||
@@ -260,7 +270,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
'city': 'Here',
|
||||
'country': 'AT',
|
||||
'vat_id': 'AT123456',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
assert 'alert-danger' in resp.content.decode()
|
||||
|
||||
@@ -291,7 +302,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
'country': 'AU',
|
||||
'state': 'QLD',
|
||||
'vat_id': 'AU123456',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
|
||||
cr1.refresh_from_db()
|
||||
@@ -324,7 +336,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
'city': 'Here',
|
||||
'country': 'AT',
|
||||
'vat_id': 'AT123456',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
|
||||
cr1.refresh_from_db()
|
||||
@@ -355,7 +368,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
'city': 'Here',
|
||||
'country': 'FR',
|
||||
'vat_id': 'AT123456',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
assert 'alert-danger' in resp.content.decode()
|
||||
|
||||
@@ -388,7 +402,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
'city': 'Here',
|
||||
'country': 'AT',
|
||||
'vat_id': 'AT123456',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
|
||||
cr1.refresh_from_db()
|
||||
@@ -422,7 +437,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
'city': 'Here',
|
||||
'country': 'AT',
|
||||
'vat_id': 'AT123456',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
|
||||
cr1.refresh_from_db()
|
||||
@@ -459,7 +475,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
'city': 'Here',
|
||||
'country': 'AT',
|
||||
'vat_id': 'AT123456',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
|
||||
cr1.refresh_from_db()
|
||||
@@ -476,7 +493,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
'city': 'Here',
|
||||
'country': 'DE',
|
||||
'vat_id': 'DE123456',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
|
||||
cr1.refresh_from_db()
|
||||
@@ -508,7 +526,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
'zipcode': '12345',
|
||||
'city': 'Here',
|
||||
'country': 'DE',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
|
||||
with mock.patch('pretix.base.services.tax._validate_vat_id_EU') as mock_validate:
|
||||
@@ -522,7 +541,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
'city': 'Here',
|
||||
'country': 'AT',
|
||||
'vat_id': 'AT123456',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
|
||||
self.client.post('/%s/%s/checkout/payment/' % (self.orga.slug, self.event.slug), {
|
||||
@@ -556,7 +576,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
'zipcode': '12345',
|
||||
'city': 'Here',
|
||||
'country': 'DE',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
doc = BeautifulSoup(r.content.decode(), "lxml")
|
||||
assert doc.select(".alert-danger")
|
||||
@@ -575,7 +596,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
'city': 'Here',
|
||||
'country': 'AT',
|
||||
'vat_id': 'AT123456',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
doc = BeautifulSoup(r.content.decode(), "lxml")
|
||||
assert not doc.select(".alert-danger")
|
||||
@@ -605,7 +627,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
'zipcode': '12345',
|
||||
'city': 'Here',
|
||||
'country': 'DE',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
|
||||
self.client.post('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
@@ -633,7 +656,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
'zipcode': '1234',
|
||||
'city': 'Here',
|
||||
'country': 'AT',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
|
||||
cr1.refresh_from_db()
|
||||
@@ -685,7 +709,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
'zipcode': '1234',
|
||||
'city': 'Here',
|
||||
'country': 'AT',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
|
||||
cr1.refresh_from_db()
|
||||
@@ -714,7 +739,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
'city': 'Here',
|
||||
'country': 'US',
|
||||
'state': 'CA',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
|
||||
with scopes_disabled():
|
||||
@@ -767,7 +793,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
'city': 'Here',
|
||||
'country': 'AT',
|
||||
'vat_id': 'AT123456',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
|
||||
cr1.refresh_from_db()
|
||||
@@ -831,7 +858,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
'city': 'Here',
|
||||
'country': 'AT',
|
||||
'vat_id': 'AT123456',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
|
||||
cr1.refresh_from_db()
|
||||
@@ -868,7 +896,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
f = SimpleUploadedFile("testfile.txt", b"file_content")
|
||||
response = self.client.post('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), {
|
||||
'%s-question_%s' % (cr1.id, q1.id): f,
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response, '/%s/%s/checkout/payment/' % (self.orga.slug, self.event.slug),
|
||||
target_status_code=200)
|
||||
@@ -883,7 +912,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
# Delete
|
||||
self.client.post('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), {
|
||||
'%s-question_%s-clear' % (cr1.id, q1.id): 'on',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
with scopes_disabled():
|
||||
assert not cr1.answers.exists()
|
||||
@@ -904,6 +934,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
# Not all required fields filled out, expect failure
|
||||
response = self.client.post('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), {
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
self.assertGreaterEqual(len(doc.select('.has-error')), 1)
|
||||
@@ -913,6 +944,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
'email': 'admin@localhost',
|
||||
'phone_0': '+49',
|
||||
'phone_1': '0622199999', # yeah the 0 is wrong but users don't know that so it should work fine
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response, '/%s/%s/checkout/payment/' % (self.orga.slug, self.event.slug),
|
||||
target_status_code=200)
|
||||
@@ -942,7 +974,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
# Not all required fields filled out, expect failure
|
||||
response = self.client.post('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), {
|
||||
'%s-attendee_email' % cr1.id: '',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
self.assertGreaterEqual(len(doc.select('.has-error')), 1)
|
||||
@@ -950,7 +983,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
# Corrected request
|
||||
response = self.client.post('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), {
|
||||
'%s-attendee_email' % cr1.id: 'foo@localhost',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response, '/%s/%s/checkout/payment/' % (self.orga.slug, self.event.slug),
|
||||
target_status_code=200)
|
||||
@@ -974,7 +1008,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
# Not all required fields filled out, expect failure
|
||||
response = self.client.post('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), {
|
||||
'%s-company' % cr1.id: '',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
self.assertGreaterEqual(len(doc.select('.has-error')), 1)
|
||||
@@ -982,7 +1017,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
# Corrected request
|
||||
response = self.client.post('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), {
|
||||
'%s-company' % cr1.id: 'foobar',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response, '/%s/%s/checkout/payment/' % (self.orga.slug, self.event.slug),
|
||||
target_status_code=200)
|
||||
@@ -1022,7 +1058,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
'%s-city' % cr1.id: 'Musterstadt',
|
||||
'%s-country' % cr1.id: 'DE',
|
||||
'%s-state' % cr1.id: '',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response, '/%s/%s/checkout/payment/' % (self.orga.slug, self.event.slug),
|
||||
target_status_code=200)
|
||||
@@ -1049,7 +1086,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
# Not all required fields filled out, expect failure
|
||||
response = self.client.post('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), {
|
||||
'%s-attendee_name_parts_0' % cr1.id: '',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
self.assertGreaterEqual(len(doc.select('.has-error')), 1)
|
||||
@@ -1057,7 +1095,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
# Corrected request
|
||||
response = self.client.post('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), {
|
||||
'%s-attendee_name_parts_0' % cr1.id: 'Peter',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response, '/%s/%s/checkout/payment/' % (self.orga.slug, self.event.slug),
|
||||
target_status_code=200)
|
||||
@@ -1082,7 +1121,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
|
||||
# Accepted request
|
||||
response = self.client.post('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), {
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response, '/%s/%s/checkout/payment/' % (self.orga.slug, self.event.slug),
|
||||
target_status_code=200)
|
||||
@@ -1112,7 +1152,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
'%s-attendee_name_parts_1' % cr1.id: '',
|
||||
'%s-attendee_name_parts_2' % cr1.id: 'John',
|
||||
'%s-attendee_name_parts_3' % cr1.id: 'Doe',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
})
|
||||
self.assertRedirects(response, '/%s/%s/checkout/payment/' % (self.orga.slug, self.event.slug),
|
||||
target_status_code=200)
|
||||
@@ -1143,7 +1184,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
# Not all fields filled out, expect success
|
||||
response = self.client.post('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), {
|
||||
'%s-attendee_name_parts_0' % cr1.id: '',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response, '/%s/%s/checkout/payment/' % (self.orga.slug, self.event.slug),
|
||||
target_status_code=200)
|
||||
@@ -1173,7 +1215,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
'city': 'Here',
|
||||
'country': 'DE',
|
||||
'vat_id': 'DE123456',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
self.assertGreaterEqual(len(doc.select('.has-error')), 1)
|
||||
@@ -1191,7 +1234,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
'city': 'Here',
|
||||
'country': 'DE',
|
||||
'vat_id': 'DE123456',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response, '/%s/%s/checkout/payment/' % (self.orga.slug, self.event.slug),
|
||||
target_status_code=200)
|
||||
@@ -1233,7 +1277,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
'zipcode': '',
|
||||
'city': '',
|
||||
'country': 'BI',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
self.assertGreaterEqual(len(doc.select('.has-error')), 1)
|
||||
@@ -1250,7 +1295,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
'zipcode': '',
|
||||
'city': 'Bujumbura',
|
||||
'country': 'BI',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response, '/%s/%s/checkout/payment/' % (self.orga.slug, self.event.slug),
|
||||
target_status_code=200)
|
||||
@@ -1293,7 +1339,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
'city': 'Here',
|
||||
'country': 'DE',
|
||||
'vat_id': 'DE123456',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
self.assertGreaterEqual(len(doc.select('.has-error')), 1)
|
||||
@@ -1311,11 +1358,168 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
'city': 'Here',
|
||||
'country': 'DE',
|
||||
'vat_id': 'DE123456',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response, '/%s/%s/checkout/payment/' % (self.orga.slug, self.event.slug),
|
||||
target_status_code=200)
|
||||
|
||||
def test_invoice_transmission_providers_email_special_case(self):
|
||||
with scopes_disabled():
|
||||
CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
self.event.settings.invoice_address_asked = True
|
||||
self.event.settings.invoice_address_required = True
|
||||
self.event.settings.invoice_generate = "True"
|
||||
self.event.settings.invoice_email_attachment = True
|
||||
response = self.client.get('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
self.assertEqual(len(doc.select('input[name="transmission_email_other"]')), 1)
|
||||
|
||||
self.event.settings.invoice_generate = "False"
|
||||
response = self.client.get('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
self.assertEqual(len(doc.select('input[name="transmission_email_other"]')), 0)
|
||||
|
||||
def test_invoice_transmission_providers_all_fields_loaded(self):
|
||||
with scopes_disabled():
|
||||
CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
self.event.settings.invoice_address_asked = True
|
||||
self.event.settings.invoice_address_required = True
|
||||
self.event.settings.invoice_generate = "True"
|
||||
self.event.settings.invoice_email_attachment = True
|
||||
|
||||
response = self.client.get('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
self.assertEqual(len(doc.select('input[name="transmission_email_address"]')), 1)
|
||||
self.assertEqual(len(doc.select('input[name="transmission_email_other"]')), 1)
|
||||
self.assertEqual(len(doc.select('input[name="transmission_it_sdi_codice_fiscale"]')), 1)
|
||||
self.assertEqual(len(doc.select('input[name="transmission_it_sdi_pec"]')), 1)
|
||||
self.assertEqual(len(doc.select('input[name="transmission_it_sdi_recipient_code"]')), 1)
|
||||
self.assertEqual(len(doc.select('input[name="transmission_peppol_participant_id"]')), 1)
|
||||
self.assertEqual(len(doc.select('select[name="transmission_type"]')), 1)
|
||||
self.assertEqual(len(doc.select('select[name="transmission_type"] option')), 3)
|
||||
|
||||
def test_invoice_transmission_invalid_submission(self):
|
||||
with scopes_disabled():
|
||||
CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
self.event.settings.invoice_address_asked = True
|
||||
self.event.settings.invoice_address_required = True
|
||||
self.event.settings.invoice_generate = "True"
|
||||
self.event.settings.invoice_email_attachment = True
|
||||
self.event.settings.invoice_address_vatid = True
|
||||
|
||||
response = self.client.post('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), {
|
||||
'is_business': 'business',
|
||||
'company': 'Foo',
|
||||
'name_parts_0': 'Mr',
|
||||
'name_parts_1': 'John',
|
||||
'name_parts_2': '',
|
||||
'name_parts_3': 'Kennedy',
|
||||
'street': 'Baz',
|
||||
'zipcode': '12345',
|
||||
'city': 'Here',
|
||||
'country': 'DE',
|
||||
'vat_id': 'DE123456',
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'it_sdi',
|
||||
}, follow=True)
|
||||
assert "The selected transmission type is not available" in response.content.decode()
|
||||
|
||||
response = self.client.post('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), {
|
||||
'is_business': 'business',
|
||||
'company': 'Foo',
|
||||
'name_parts_0': 'Mr',
|
||||
'name_parts_1': 'John',
|
||||
'name_parts_2': '',
|
||||
'name_parts_3': 'Kennedy',
|
||||
'street': 'Baz',
|
||||
'zipcode': '12345',
|
||||
'city': 'Here',
|
||||
'country': 'IT',
|
||||
'state': 'MI',
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'it_sdi',
|
||||
'vat_id': '',
|
||||
}, follow=True)
|
||||
assert "This field is required for the selected type" in response.content.decode()
|
||||
|
||||
response = self.client.post('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), {
|
||||
'is_business': 'business',
|
||||
'company': 'Foo',
|
||||
'name_parts_0': 'Mr',
|
||||
'name_parts_1': 'John',
|
||||
'name_parts_2': '',
|
||||
'name_parts_3': 'Kennedy',
|
||||
'street': 'Baz',
|
||||
'zipcode': '12345',
|
||||
'city': 'Here',
|
||||
'country': 'IT',
|
||||
'state': 'MI',
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
assert "must be used for this country" in response.content.decode()
|
||||
|
||||
def test_invoice_optional_transmission(self):
|
||||
with scopes_disabled():
|
||||
CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
self.event.settings.invoice_address_asked = True
|
||||
self.event.settings.invoice_address_required = False
|
||||
self.event.settings.invoice_generate = "True"
|
||||
self.event.settings.invoice_email_attachment = True
|
||||
self.event.settings.invoice_address_vatid = True
|
||||
|
||||
response = self.client.post('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), {
|
||||
'is_business': 'business',
|
||||
'company': 'Foo',
|
||||
'name_parts_0': 'Mr',
|
||||
'name_parts_1': 'John',
|
||||
'name_parts_2': '',
|
||||
'name_parts_3': 'Kennedy',
|
||||
'street': 'Baz',
|
||||
'zipcode': '12345',
|
||||
'city': 'Here',
|
||||
'country': 'DE',
|
||||
'vat_id': 'DE123456',
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': '-',
|
||||
}, follow=True)
|
||||
assert "If you enter an invoice address, you also need to select an invoice" in response.content.decode()
|
||||
|
||||
response = self.client.post('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), {
|
||||
'is_business': 'business',
|
||||
'company': '',
|
||||
'name_parts_0': '',
|
||||
'name_parts_1': '',
|
||||
'name_parts_2': '',
|
||||
'name_parts_3': '',
|
||||
'street': '',
|
||||
'zipcode': '',
|
||||
'city': '',
|
||||
'country': 'IT',
|
||||
'state': '',
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': '-',
|
||||
'vat_id': '',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response, '/%s/%s/checkout/payment/' % (self.orga.slug, self.event.slug),
|
||||
target_status_code=200)
|
||||
with scopes_disabled():
|
||||
ia = InvoiceAddress.objects.get()
|
||||
assert ia.transmission_type == "email"
|
||||
|
||||
def test_invoice_address_hidden_for_free(self):
|
||||
self.event.settings.invoice_address_asked = True
|
||||
self.event.settings.invoice_address_required = True
|
||||
@@ -1332,7 +1536,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
self.assertEqual(len(doc.select('input[name="city"]')), 0)
|
||||
|
||||
response = self.client.post('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), {
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response, '/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug),
|
||||
target_status_code=200)
|
||||
@@ -1365,7 +1570,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
'city': 'Here',
|
||||
'country': 'DE',
|
||||
'vat_id': 'DE123456',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response, '/%s/%s/checkout/payment/' % (self.orga.slug, self.event.slug),
|
||||
target_status_code=200)
|
||||
@@ -1406,7 +1612,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
'is_business': 'business',
|
||||
'country': 'DE',
|
||||
'city': 'Musterstadt',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
self.assertGreaterEqual(len(doc.select('.has-error')), 1)
|
||||
@@ -1416,7 +1623,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
'is_business': 'business',
|
||||
'country': 'DE',
|
||||
'vat_id': 'DE123456',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response, '/%s/%s/checkout/payment/' % (self.orga.slug, self.event.slug),
|
||||
target_status_code=200)
|
||||
@@ -1437,7 +1645,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
|
||||
# Not all required fields filled out, expect failure
|
||||
response = self.client.post('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), {
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
self.assertGreaterEqual(len(doc.select('.has-error')), 1)
|
||||
@@ -1445,7 +1654,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
# Corrected request
|
||||
response = self.client.post('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), {
|
||||
'name_parts_0': 'Raphael',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response, '/%s/%s/checkout/payment/' % (self.orga.slug, self.event.slug),
|
||||
target_status_code=200)
|
||||
@@ -2603,7 +2813,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
# Date too far in the future, expected to fail
|
||||
response = self.client.post('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), {
|
||||
'%s-requested_valid_from' % cr1.id: '2024-01-20',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
self.assertGreaterEqual(len(doc.select('.has-error')), 1)
|
||||
@@ -2611,7 +2822,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
# Corrected request
|
||||
response = self.client.post('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), {
|
||||
'%s-requested_valid_from' % cr1.id: '2023-01-20',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response, '/%s/%s/checkout/payment/' % (self.orga.slug, self.event.slug),
|
||||
target_status_code=200)
|
||||
@@ -2649,7 +2861,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
response = self.client.post('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), {
|
||||
'%s-requested_valid_from_0' % cr1.id: '2024-01-20',
|
||||
'%s-requested_valid_from_1' % cr1.id: '11:00:00',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
self.assertGreaterEqual(len(doc.select('.has-error')), 1)
|
||||
@@ -2658,7 +2871,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
response = self.client.post('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), {
|
||||
'%s-requested_valid_from_0' % cr1.id: '2023-01-20',
|
||||
'%s-requested_valid_from_1' % cr1.id: '11:00:00',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response, '/%s/%s/checkout/payment/' % (self.orga.slug, self.event.slug),
|
||||
target_status_code=200)
|
||||
@@ -2701,7 +2915,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
# Date too far in the future, expected to fail
|
||||
response = self.client.post('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), {
|
||||
'%s-requested_valid_from' % cr1.id: '2024-01-17',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
self.assertGreaterEqual(len(doc.select('.has-error')), 1)
|
||||
@@ -2709,7 +2924,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
# Corrected request
|
||||
response = self.client.post('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), {
|
||||
'%s-requested_valid_from' % cr1.id: '2023-01-10',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response, '/%s/%s/checkout/payment/' % (self.orga.slug, self.event.slug),
|
||||
target_status_code=200)
|
||||
@@ -2748,7 +2964,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
)
|
||||
|
||||
response = self.client.post('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), {
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response, '/%s/%s/checkout/payment/' % (self.orga.slug, self.event.slug),
|
||||
target_status_code=200)
|
||||
@@ -3797,6 +4014,120 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
o.payments.first().confirm()
|
||||
assert len(djmail.outbox) == 0
|
||||
|
||||
def test_order_confirmation_mail_invoice_attached(self):
|
||||
self.event.settings.invoice_address_asked = True
|
||||
self.event.settings.invoice_address_required = True
|
||||
self.event.settings.invoice_generate = "True"
|
||||
self.event.settings.invoice_email_attachment = True
|
||||
ia = InvoiceAddress.objects.create(
|
||||
is_business=True,
|
||||
country=Country('AT'),
|
||||
transmission_type="email",
|
||||
transmission_info={
|
||||
"transmission_email_other": False,
|
||||
"transmission_email_address": None,
|
||||
}
|
||||
)
|
||||
|
||||
with scopes_disabled():
|
||||
cp1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
djmail.outbox = []
|
||||
_perform_order(self.event, self._manual_payment(), [cp1.pk], 'admin@example.org', 'en', ia.pk, {}, 'web')
|
||||
assert len(djmail.outbox) == 1
|
||||
assert any(["Invoice_" in a[0] for a in djmail.outbox[0].attachments])
|
||||
|
||||
def test_order_confirmation_mail_invoice_sent_somewhere_else(self):
|
||||
self.event.settings.invoice_address_asked = True
|
||||
self.event.settings.invoice_address_required = True
|
||||
self.event.settings.invoice_generate = "True"
|
||||
self.event.settings.invoice_email_attachment = True
|
||||
ia = InvoiceAddress.objects.create(
|
||||
is_business=True,
|
||||
country=Country('AT'),
|
||||
transmission_type="email",
|
||||
transmission_info={
|
||||
"transmission_email_other": True,
|
||||
"transmission_email_address": "invoice@example.org",
|
||||
}
|
||||
)
|
||||
|
||||
with scopes_disabled():
|
||||
cp1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
djmail.outbox = []
|
||||
_perform_order(self.event, self._manual_payment(), [cp1.pk], 'admin@example.org', 'en', ia.pk, {}, 'web')
|
||||
assert len(djmail.outbox) == 2
|
||||
assert ["invoice@example.org"] == djmail.outbox[0].to
|
||||
assert any(["Invoice_" in a[0] for a in djmail.outbox[0].attachments])
|
||||
assert ["admin@example.org"] == djmail.outbox[1].to
|
||||
assert not any(["Invoice_" in a[0] for a in djmail.outbox[1].attachments])
|
||||
|
||||
def test_order_paid_confirmation_mail_invoice_attached(self):
|
||||
self.event.settings.invoice_address_asked = True
|
||||
self.event.settings.invoice_address_required = True
|
||||
self.event.settings.invoice_generate = "paid"
|
||||
self.event.settings.invoice_email_attachment = True
|
||||
ia = InvoiceAddress.objects.create(
|
||||
is_business=True,
|
||||
country=Country('AT'),
|
||||
transmission_type="email",
|
||||
transmission_info={
|
||||
"transmission_email_other": False,
|
||||
"transmission_email_address": None,
|
||||
}
|
||||
)
|
||||
|
||||
with scopes_disabled():
|
||||
cp1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
djmail.outbox = []
|
||||
oid = _perform_order(self.event, self._manual_payment(), [cp1.pk], 'admin@example.org', 'en', ia.pk, {}, 'web')
|
||||
assert len(djmail.outbox) == 1
|
||||
assert not any(["Invoice_" in a[0] for a in djmail.outbox[0].attachments])
|
||||
o = Order.objects.get(pk=oid['order_id'])
|
||||
o.payments.first().confirm()
|
||||
assert len(djmail.outbox) == 2
|
||||
assert any(["Invoice_" in a[0] for a in djmail.outbox[1].attachments])
|
||||
|
||||
def test_order_paid_confirmation_mail_invoice_sent_somewhere_else(self):
|
||||
self.event.settings.invoice_address_asked = True
|
||||
self.event.settings.invoice_address_required = True
|
||||
self.event.settings.invoice_generate = "paid"
|
||||
self.event.settings.invoice_email_attachment = True
|
||||
ia = InvoiceAddress.objects.create(
|
||||
is_business=True,
|
||||
country=Country('AT'),
|
||||
transmission_type="email",
|
||||
transmission_info={
|
||||
"transmission_email_other": True,
|
||||
"transmission_email_address": "invoice@example.org",
|
||||
}
|
||||
)
|
||||
|
||||
with scopes_disabled():
|
||||
cp1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
djmail.outbox = []
|
||||
oid = _perform_order(self.event, self._manual_payment(), [cp1.pk], 'admin@example.org', 'en', ia.pk, {}, 'web')
|
||||
assert len(djmail.outbox) == 1
|
||||
assert ["admin@example.org"] == djmail.outbox[0].to
|
||||
assert not any(["Invoice_" in a[0] for a in djmail.outbox[0].attachments])
|
||||
|
||||
o = Order.objects.get(pk=oid['order_id'])
|
||||
o.payments.first().confirm()
|
||||
assert len(djmail.outbox) == 3
|
||||
assert ["invoice@example.org"] == djmail.outbox[2].to
|
||||
assert any(["Invoice_" in a[0] for a in djmail.outbox[2].attachments])
|
||||
|
||||
def test_locale_region_not_saved(self):
|
||||
self.event.settings.origin = 'US'
|
||||
self.event.settings.locales = ['de']
|
||||
@@ -3882,6 +4213,7 @@ class QuestionsTestCase(BaseCheckoutTestCase, TestCase):
|
||||
'%s-question_%s_0' % (cr.id, q3.id): '2018-01-01',
|
||||
'%s-question_%s_1' % (cr.id, q3.id): '5:23',
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response, '/%s/%s/checkout/payment/' % (self.orga.slug, self.event.slug), target_status_code=200)
|
||||
self.event.settings.set('timezone', 'US/Central')
|
||||
@@ -3966,7 +4298,8 @@ class QuestionsTestCase(BaseCheckoutTestCase, TestCase):
|
||||
'%s-question_%s' % (cr2.id, q1.id): '',
|
||||
'%s-question_%s' % (cr1.id, q2.id): 'Internet',
|
||||
'%s-question_%s' % (cr2.id, q2.id): '',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
self.assertGreaterEqual(len(doc.select('.has-error')), 1)
|
||||
@@ -3977,7 +4310,8 @@ class QuestionsTestCase(BaseCheckoutTestCase, TestCase):
|
||||
'%s-question_%s' % (cr2.id, q1.id): '0',
|
||||
'%s-question_%s' % (cr1.id, q2.id): 'Internet',
|
||||
'%s-question_%s' % (cr2.id, q2.id): '',
|
||||
'email': 'admin@localhost'
|
||||
'email': 'admin@localhost',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response, '/%s/%s/checkout/payment/' % (self.orga.slug, self.event.slug),
|
||||
target_status_code=200)
|
||||
@@ -4000,6 +4334,7 @@ class QuestionsTestCase(BaseCheckoutTestCase, TestCase):
|
||||
('%s-question_%s' % (cr1.id, k.id)): v for k, v in data.items() if v != 'False'
|
||||
}
|
||||
pl['email'] = 'admin@localhost'
|
||||
pl['transmission_type'] = 'email'
|
||||
response = self.client.post('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), pl, follow=True)
|
||||
if should_fail:
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
@@ -4919,7 +5254,8 @@ class CustomerCheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
self.assertRedirects(response, '/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug),
|
||||
target_status_code=200)
|
||||
response = self.client.post('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), {
|
||||
'email': 'will-be-ignored'
|
||||
'email': 'will-be-ignored',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response, '/%s/%s/checkout/payment/' % (self.orga.slug, self.event.slug),
|
||||
target_status_code=200)
|
||||
@@ -5003,7 +5339,8 @@ class CustomerCheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
target_status_code=200)
|
||||
|
||||
response = self.client.post('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), {
|
||||
'email': 'will-be-ignored'
|
||||
'email': 'will-be-ignored',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response, '/%s/%s/checkout/payment/' % (self.orga.slug, self.event.slug),
|
||||
target_status_code=200)
|
||||
@@ -5140,6 +5477,7 @@ class CustomerCheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
assert b'Mark Fisher' not in response.content
|
||||
response = self.client.post('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), {
|
||||
'email': 'will-be-ignored',
|
||||
'transmission_type': 'email',
|
||||
f'{cp.pk}-attendee_name_parts_0': 'will-be-ignored'
|
||||
}, follow=True)
|
||||
self.assertRedirects(response, '/%s/%s/checkout/payment/' % (self.orga.slug, self.event.slug),
|
||||
|
||||
@@ -273,6 +273,7 @@ class OrdersTest(BaseOrdersTest):
|
||||
response = self.client.post(
|
||||
'/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), {
|
||||
'%s-attendee_name_parts_0' % self.ticket_pos.id: '',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response,
|
||||
'/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code,
|
||||
@@ -304,6 +305,7 @@ class OrdersTest(BaseOrdersTest):
|
||||
response = self.client.post(
|
||||
'/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), {
|
||||
'%s-attendee_name_parts_0' % self.ticket_pos.id: 'Peter',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response, '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code,
|
||||
self.order.secret),
|
||||
@@ -326,6 +328,7 @@ class OrdersTest(BaseOrdersTest):
|
||||
response = self.client.post(
|
||||
'/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), {
|
||||
'%s-question_%s' % (self.ticket_pos.id, self.question.id): '',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response,
|
||||
'/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code,
|
||||
@@ -350,6 +353,7 @@ class OrdersTest(BaseOrdersTest):
|
||||
response = self.client.post(
|
||||
'/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), {
|
||||
'%s-question_%s' % (self.ticket_pos.id, self.question.id): '',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
self.assertGreaterEqual(len(doc.select('.has-error')), 1)
|
||||
@@ -357,6 +361,7 @@ class OrdersTest(BaseOrdersTest):
|
||||
response = self.client.post(
|
||||
'/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), {
|
||||
'%s-question_%s' % (self.ticket_pos.id, self.question.id): 'ABC',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response,
|
||||
'/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code,
|
||||
@@ -374,6 +379,7 @@ class OrdersTest(BaseOrdersTest):
|
||||
response = self.client.post(
|
||||
'/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), {
|
||||
'%s-question_%s' % (self.ticket_pos.id, self.question.id): 'ABC',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response,
|
||||
'/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code,
|
||||
@@ -390,6 +396,7 @@ class OrdersTest(BaseOrdersTest):
|
||||
'street': 'Main Street',
|
||||
'city': 'Heidelberg',
|
||||
'country': 'DE',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
self.assertGreaterEqual(len(doc.select('.has-error')), 1)
|
||||
@@ -403,6 +410,7 @@ class OrdersTest(BaseOrdersTest):
|
||||
response = self.client.post(
|
||||
'/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), {
|
||||
'%s-question_%s' % (self.ticket_pos.id, self.question.id): 'ABC',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response,
|
||||
'/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code,
|
||||
@@ -419,6 +427,7 @@ class OrdersTest(BaseOrdersTest):
|
||||
'street': 'Main Street',
|
||||
'city': 'Heidelberg',
|
||||
'country': 'DE',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response,
|
||||
'/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code,
|
||||
@@ -436,6 +445,7 @@ class OrdersTest(BaseOrdersTest):
|
||||
'street': 'Main Street',
|
||||
'city': 'Heidelberg',
|
||||
'country': 'DE',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response,
|
||||
'/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code,
|
||||
@@ -477,8 +487,12 @@ class OrdersTest(BaseOrdersTest):
|
||||
# Not all fields filled out, expect success
|
||||
response = self.client.post(
|
||||
'/%s/%s/ticket/%s/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code,
|
||||
self.ticket_pos.positionid, self.ticket_pos.web_secret)
|
||||
self.ticket_pos.positionid, self.ticket_pos.web_secret),
|
||||
{
|
||||
'transmission_type': 'email',
|
||||
}
|
||||
)
|
||||
print(response.content.decode())
|
||||
self.assertRedirects(response,
|
||||
'/%s/%s/ticket/%s/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code,
|
||||
self.ticket_pos.positionid, self.ticket_pos.web_secret),
|
||||
|
||||
@@ -22,6 +22,10 @@
|
||||
from django.dispatch import receiver
|
||||
|
||||
from pretix.base.channels import SalesChannelType
|
||||
from pretix.base.invoicing.transmission import (
|
||||
TransmissionProvider, transmission_providers,
|
||||
)
|
||||
from pretix.base.models import Invoice
|
||||
from pretix.base.signals import (
|
||||
register_payment_providers, register_sales_channel_types,
|
||||
register_ticket_outputs,
|
||||
@@ -70,3 +74,37 @@ def html_head_presale(sender, request=None, **kwargs):
|
||||
# No tracking scripts on PCI DSS relevant payment pages
|
||||
return ""
|
||||
return "<script>alert('BAD TRACKING SCRIPT')</script>"
|
||||
|
||||
|
||||
@transmission_providers.new()
|
||||
class TestSdiTransmissionProvider(TransmissionProvider):
|
||||
identifier = "fatturapa_test"
|
||||
type = "it_sdi"
|
||||
verbose_name = "FatturaPA Test"
|
||||
|
||||
def is_ready(self, event) -> bool:
|
||||
return True
|
||||
|
||||
def is_available(self, event, country, is_business: bool) -> bool:
|
||||
return str(country) == "IT"
|
||||
|
||||
def transmit(self, invoice):
|
||||
invoice.transmission_status = Invoice.TRANSMISSION_STATUS_COMPLETED
|
||||
invoice.save()
|
||||
|
||||
|
||||
@transmission_providers.new()
|
||||
class TestPeppolTransmissionProvider(TransmissionProvider):
|
||||
identifier = "peppol_test"
|
||||
type = "peppol"
|
||||
verbose_name = "PEPPOL Test"
|
||||
|
||||
def is_ready(self, event) -> bool:
|
||||
return True
|
||||
|
||||
def is_available(self, event, country, is_business: bool) -> bool:
|
||||
return is_business
|
||||
|
||||
def transmit(self, invoice):
|
||||
invoice.transmission_status = Invoice.TRANSMISSION_STATUS_COMPLETED
|
||||
invoice.save()
|
||||
|
||||
Reference in New Issue
Block a user