lingo/tests/basket/test_basket.py

1018 lines
33 KiB
Python

import datetime
import uuid
from unittest import mock
import pytest
from django.shortcuts import redirect
from django.urls import reverse
from django.utils.timezone import now
from pyquery import PyQuery
from lingo.basket.models import Basket, BasketLine, BasketLineItem
from lingo.invoicing.models import (
Credit,
CreditAssignment,
CreditLine,
DraftInvoice,
DraftInvoiceLine,
Invoice,
InvoiceLine,
InvoiceLinePayment,
Payment,
PaymentType,
Regie,
)
from tests.utils import login
pytestmark = pytest.mark.django_db
def test_basket_detail(app, simple_user):
resp = app.get('/basket/')
assert resp.location.endswith('/login/?next=/basket/')
app = login(app, username='user', password='user')
# no basket object
resp = app.get('/basket/')
assert 'My basket' in resp
assert len(resp.pyquery('ul.basket li')) == 0
assert '/basket/invoice/pdf/' not in resp
assert '/basket/validate/' not in resp
assert '/basket/cancel/' not in resp
# basket without lines
regie = Regie.objects.create(label='Foo')
invoice = DraftInvoice.objects.create(
regie=regie,
date_publication=datetime.date(2023, 4, 21),
date_payment_deadline=datetime.date(2023, 4, 22),
date_due=datetime.date(2023, 4, 23),
)
DraftInvoiceLine.objects.create(
slug='event-a-foo-bar',
label='Event A',
event_date=datetime.date(2022, 9, 1),
invoice=invoice,
quantity=1,
unit_amount=6,
user_external_id='user:1',
)
basket = Basket.objects.create(
regie=regie,
draft_invoice=invoice,
payer_nameid='ab' * 16,
payer_external_id='payer:1',
expiry_at=now() + datetime.timedelta(hours=1),
)
resp = app.get('/basket/')
assert 'My basket' in resp
assert len(resp.pyquery('ul.basket li')) == 0
assert len(resp.pyquery('ul.basket-amounts')) == 0
assert '/basket/invoice/pdf/' not in resp
assert '/basket/validate/' not in resp
assert '/basket/cancel/' not in resp
# a not closed line
line = BasketLine.objects.create(
basket=basket,
closed=False,
user_external_id='user:1',
user_first_name='First1',
user_last_name='Last1',
information_message='Lorem ipsum',
)
resp = app.get('/basket/')
assert 'My basket' in resp
assert len(resp.pyquery('ul.basket li')) == 0
assert len(resp.pyquery('ul.basket-amounts')) == 0
assert resp.text.count('<p>Lorem ipsum</p>') == 0
assert '/basket/invoice/pdf/' not in resp
assert '/basket/validate/' not in resp
assert '/basket/cancel/' not in resp
# line is closed but empty
line.closed = True
line.save()
resp = app.get('/basket/')
assert 'My basket' in resp
assert len(resp.pyquery('ul.basket li')) == 0
assert len(resp.pyquery('ul.basket-amounts li')) == 2
assert resp.text.count('<p>Lorem ipsum</p>') == 1
assert [PyQuery(li).text() for li in resp.pyquery('ul.basket-amounts li')] == [
'Basket amount: 6.00€',
'Amount to pay: 6.00€',
]
assert '/basket/invoice/pdf/' in resp
assert '/basket/validate/' in resp
assert '/basket/cancel/' in resp
# add some items, group_items is False
BasketLineItem.objects.create(
line=line,
label='Repas',
subject='Réservation',
details='Lun 06/11, Mar 07/11',
quantity=2,
unit_amount=3,
)
BasketLineItem.objects.create(
line=line,
label='Repas',
subject='Réservation',
details='Jeu 09/11',
quantity=1,
unit_amount=3,
)
BasketLineItem.objects.create(
line=line,
label='Repas',
subject='Annulation',
details='Ven 10/11',
quantity=-1,
unit_amount=3,
)
resp = app.get('/basket/')
assert 'My basket' in resp
assert len(resp.pyquery('ul.basket li')) == 3
assert [PyQuery(li).text() for li in resp.pyquery('ul.basket li')] == [
'First1 Last1 - Repas - Annulation Ven 10/11 -3.00€',
'First1 Last1 - Repas - Réservation Jeu 09/11 3.00€',
'First1 Last1 - Repas - Réservation Lun 06/11, Mar 07/11 6.00€',
]
assert len(resp.pyquery('ul.basket-amounts li')) == 2
assert [PyQuery(li).text() for li in resp.pyquery('ul.basket-amounts li')] == [
'Basket amount: 6.00€',
'Amount to pay: 6.00€',
]
assert '/basket/invoice/pdf/' in resp
assert '/basket/validate/' in resp
assert '/basket/cancel/' in resp
# group items
line.group_items = True
line.save()
resp = app.get('/basket/')
assert 'My basket' in resp
assert len(resp.pyquery('ul.basket li')) == 2
assert [PyQuery(li).text() for li in resp.pyquery('ul.basket li')] == [
'First1 Last1 - Repas - Annulation Ven 10/11 -3.00€',
'First1 Last1 - Repas - Réservation Lun 06/11, Mar 07/11, Jeu 09/11 9.00€',
]
assert len(resp.pyquery('ul.basket-amounts li')) == 2
assert [PyQuery(li).text() for li in resp.pyquery('ul.basket-amounts li')] == [
'Basket amount: 6.00€',
'Amount to pay: 6.00€',
]
assert '/basket/invoice/pdf/' in resp
assert '/basket/validate/' in resp
assert '/basket/cancel/' in resp
# with available credit
credit = Credit.objects.create(
regie=regie,
payer_external_id='payer:1',
)
CreditLine.objects.create(
credit=credit,
event_date=datetime.date(2022, 9, 1),
quantity=1,
unit_amount=1,
)
resp = app.get('/basket/')
assert len(resp.pyquery('ul.basket-amounts li')) == 3
assert [PyQuery(li).text() for li in resp.pyquery('ul.basket-amounts li')] == [
'Basket amount: 6.00€',
'Credit: -1.00€',
'Amount to pay: 5.00€',
]
# not closed line
line.closed = False
line.save()
resp = app.get('/basket/')
assert 'My basket' in resp
assert len(resp.pyquery('ul.basket li')) == 0
assert len(resp.pyquery('ul.basket-amounts')) == 0
assert '/basket/invoice/pdf/' not in resp
assert '/basket/validate/' not in resp
assert '/basket/cancel/' not in resp
# basket payer_nameid is wrong
line.closed = True
line.save()
basket.payer_nameid = uuid.uuid4()
basket.save()
resp = app.get('/basket/')
assert 'My basket' in resp
assert len(resp.pyquery('ul.basket li')) == 0
assert len(resp.pyquery('ul.basket-amounts')) == 0
assert '/basket/invoice/pdf/' not in resp
assert '/basket/validate/' not in resp
assert '/basket/cancel/' not in resp
# check status
basket.payer_nameid = 'ab' * 16
basket.save()
for status in ['open', 'tobepaid']:
basket.status = status
basket.save()
resp = app.get('/basket/')
assert 'My basket' in resp
assert len(resp.pyquery('ul.basket li')) == 2
assert len(resp.pyquery('ul.basket-amounts')) == 1
assert '/basket/invoice/pdf/' in resp
if status == 'open':
assert '/basket/validate/' in resp
else:
assert '/basket/validate/' not in resp
assert '/basket/cancel/' in resp
for status in ['cancelled', 'expired', 'completed']:
basket.status = status
basket.save()
resp = app.get('/basket/')
assert 'My basket' in resp
assert len(resp.pyquery('ul.basket li')) == 0
assert len(resp.pyquery('ul.basket-amounts')) == 0
assert '/basket/invoice/pdf/' not in resp
assert '/basket/validate/' not in resp
assert '/basket/cancel/' not in resp
# other lines with information_message
basket.status = 'open'
basket.save()
line = BasketLine.objects.create(
basket=basket,
closed=True,
user_external_id='user:2',
user_first_name='First2',
user_last_name='Last2',
information_message='Lorem ipsum',
)
line = BasketLine.objects.create(
basket=basket,
closed=True,
user_external_id='user:3',
user_first_name='First3',
user_last_name='Last3',
information_message='Lorem ipsum bis',
)
resp = app.get('/basket/')
assert resp.text.count('<p>Lorem ipsum</p>') == 1
assert resp.text.count('<p>Lorem ipsum bis</p>') == 1
def test_basket_invoice_pdf(app, simple_user):
resp = app.get('/basket/invoice/pdf/')
assert resp.location.endswith('/login/?next=/basket/invoice/pdf/')
app = login(app, username='user', password='user')
# no basket object
app.get('/basket/invoice/pdf/', status=404)
# basket
regie = Regie.objects.create(label='Foo')
invoice = DraftInvoice.objects.create(
regie=regie,
date_publication=datetime.date(2023, 4, 21),
date_payment_deadline=datetime.date(2023, 4, 22),
date_due=datetime.date(2023, 4, 23),
)
DraftInvoiceLine.objects.create(
slug='event-a-foo-bar',
label='Event A',
event_date=datetime.date(2022, 9, 1),
invoice=invoice,
quantity=10,
unit_amount=1,
user_external_id='user:1',
)
basket = Basket.objects.create(regie=regie, draft_invoice=invoice, payer_nameid='ab' * 16)
app.get('/basket/invoice/pdf/', status=200)
# basket payer_nameid is wrong
basket.payer_nameid = uuid.uuid4()
basket.save()
app.get('/basket/invoice/pdf/', status=404)
# check status
basket.invoice = basket.draft_invoice.promote()
basket.payer_nameid = 'ab' * 16
basket.save()
for status in ['open', 'tobepaid']:
basket.status = status
basket.save()
resp = app.get('/basket/invoice/pdf/?html', status=200)
if status == 'open':
assert 'TEMPORARY-%s' % basket.draft_invoice.pk in resp
else:
assert 'F%02d-%s-0000001' % (regie.pk, basket.invoice.created_at.strftime('%y-%m')) in resp
assert 'Total amount to be paid before' not in resp
assert resp.pyquery('tfoot').text() == 'Total amount:\n10.00€'
for status in ['cancelled', 'expired', 'completed']:
basket.status = status
basket.save()
app.get('/basket/invoice/pdf/', status=404)
# invoice with credit and assignment
basket.status = 'tobepaid'
basket.save()
credit = Credit.objects.create(
regie=regie,
payer_external_id='payer:1',
)
CreditLine.objects.create(
credit=credit,
event_date=datetime.date(2022, 9, 1),
quantity=10,
unit_amount=1,
)
CreditAssignment.objects.create(
invoice=basket.invoice,
credit=credit,
amount=1,
)
resp = app.get('/basket/invoice/pdf/?html', status=200)
assert resp.pyquery('tfoot').text() == 'Credit:\n-1.00€\nTotal amount:\n9.00€'
def test_basket_validate(app, simple_user):
resp = app.get('/basket/validate/')
assert resp.location.endswith('/login/?next=/basket/validate/')
app = login(app, username='user', password='user')
# no basket object
app.get('/basket/validate/', status=404)
# basket without line
regie = Regie.objects.create(label='Foo')
invoice = DraftInvoice.objects.create(
regie=regie,
date_publication=datetime.date(2023, 4, 21),
date_payment_deadline=datetime.date(2023, 4, 22),
date_due=datetime.date(2023, 4, 23),
)
basket = Basket.objects.create(
regie=regie,
draft_invoice=invoice,
payer_nameid='ab' * 16,
expiry_at=now() + datetime.timedelta(hours=1),
)
app.get('/basket/validate/', status=404)
# a not closed line
line = BasketLine.objects.create(
basket=basket,
closed=False,
user_external_id='user:1',
)
app.get('/basket/validate/', status=404)
# line is closed, but wrong payer_nameid
line.closed = True
line.save()
basket.payer_nameid = uuid.uuid4()
basket.save()
app.get('/basket/validate/', status=404)
# good payer_nameid
basket.payer_nameid = 'ab' * 16
basket.save()
resp = app.get('/basket/validate/')
with mock.patch('lingo.basket.views.pay_invoice') as pay_invoice, mock.patch(
'lingo.utils.requests_wrapper.RequestsSession.send'
) as mock_send:
pay_invoice.side_effect = lambda *args: redirect(reverse('lingo-basket-detail'))
resp = resp.form.submit()
assert {x[0][0].url for x in mock_send.call_args_list} == set()
assert resp.location.endswith('/basket/')
basket.refresh_from_db()
assert basket.status == 'completed'
assert basket.validated_at is not None
assert basket.paid_at is not None
assert basket.completed_at is not None
assert Invoice.objects.count() == 1
invoice = Invoice.objects.latest('pk')
assert basket.invoice == invoice
assert basket.credit is None
# wrong status
for status in ['tobepaid', 'cancelled', 'expired', 'completed']:
basket.status = status
basket.save()
app.get('/basket/validate/', status=404)
# check callback
basket.status = 'open'
basket.save()
line.validation_callback_url = 'http://validation1.com'
line.credit_callback_url = 'http://validation1.com'
line.save()
BasketLine.objects.create(
basket=basket,
closed=True,
user_external_id='user:2',
validation_callback_url='http://validation2.com',
credit_callback_url='http://validation2.com',
)
resp = app.get('/basket/validate/')
with mock.patch('lingo.basket.views.pay_invoice') as pay_invoice, mock.patch(
'lingo.utils.requests_wrapper.RequestsSession.send'
) as mock_send:
pay_invoice.side_effect = lambda *args: redirect(reverse('lingo-basket-detail'))
resp = resp.form.submit()
assert {x[0][0].url for x in mock_send.call_args_list} == {
'http://validation1.com/',
'http://validation2.com/',
}
# basket is expired
basket.expiry_at = now()
basket.status = 'open'
basket.save()
resp = app.get('/basket/validate/')
resp.form.submit()
basket.refresh_from_db()
assert basket.status == 'open'
def test_basket_validate_generate_invoice(app, simple_user):
app = login(app, username='user', password='user')
regie = Regie.objects.create(label='Foo')
other_regie = Regie.objects.create(label='Bar')
draft_invoice = DraftInvoice.objects.create(
regie=regie,
date_publication=datetime.date(2023, 4, 21),
date_payment_deadline=datetime.date(2023, 4, 22),
date_due=datetime.date(2023, 4, 23),
)
DraftInvoiceLine.objects.create(
slug='event-a-foo-bar',
label='Event A',
event_date=datetime.date(2022, 9, 1),
invoice=draft_invoice,
quantity=10,
unit_amount=1,
user_external_id='user:1',
)
# invoice total amount is positive
draft_invoice.refresh_from_db()
assert draft_invoice.total_amount == 10
basket = Basket.objects.create(
regie=regie,
draft_invoice=draft_invoice,
payer_nameid='ab' * 16,
expiry_at=now() + datetime.timedelta(hours=1),
payer_external_id='payer:1',
)
BasketLine.objects.create(
basket=basket,
closed=True,
user_external_id='user:1',
group_items=False,
)
resp = app.get('/basket/validate/')
with mock.patch('lingo.basket.views.pay_invoice') as pay_invoice:
pay_invoice.side_effect = lambda *args, **kwargs: redirect(reverse('lingo-basket-detail'))
resp = resp.form.submit()
assert resp.location.endswith('/basket/')
basket.refresh_from_db()
assert basket.status == 'tobepaid'
assert basket.validated_at is not None
assert basket.paid_at is None
assert basket.completed_at is None
invoice = Invoice.objects.latest('pk')
assert basket.invoice == invoice
assert invoice.total_amount == 10
assert Credit.objects.count() == 0
# with credits, generated invoice is partially paid with credit
credit1 = Credit.objects.create(
regie=regie,
payer_external_id='payer:1',
)
CreditLine.objects.create(
credit=credit1,
event_date=datetime.date(2022, 9, 1),
quantity=1,
unit_amount=1,
)
credit2 = Credit.objects.create(
regie=regie,
payer_external_id='payer:1',
)
CreditLine.objects.create(
credit=credit2,
event_date=datetime.date(2022, 9, 1),
quantity=3,
unit_amount=1,
)
other_credit1 = Credit.objects.create(
regie=regie,
payer_external_id='payer:2',
)
CreditLine.objects.create(
credit=other_credit1,
event_date=datetime.date(2022, 9, 1),
quantity=1,
unit_amount=1,
)
other_credit2 = Credit.objects.create(
regie=other_regie,
payer_external_id='payer:1',
)
CreditLine.objects.create(
credit=other_credit2,
event_date=datetime.date(2022, 9, 1),
quantity=1,
unit_amount=1,
)
basket.status = 'open'
basket.save()
resp = app.get('/basket/validate/')
with mock.patch('lingo.basket.views.pay_invoice') as pay_invoice:
pay_invoice.side_effect = lambda *args, **kwargs: redirect(reverse('lingo-basket-detail'))
resp = resp.form.submit()
assert resp.location.endswith('/basket/')
basket.refresh_from_db()
assert basket.status == 'tobepaid'
assert basket.validated_at is not None
assert basket.paid_at is None
assert basket.completed_at is None
invoice = Invoice.objects.latest('pk')
assert basket.invoice == invoice
assert invoice.total_amount == 10
assert invoice.paid_amount == 0
assert invoice.remaining_amount == 10
credit1.refresh_from_db()
assert credit1.remaining_amount == 0
assert credit1.assigned_amount == 1
credit2.refresh_from_db()
assert credit2.remaining_amount == 0
assert credit2.assigned_amount == 3
assert Payment.objects.count() == 0
assert CreditAssignment.objects.count() == 2
assignment1, assignment2 = CreditAssignment.objects.all().order_by('pk')
assert assignment1.amount == 1
assert assignment1.invoice == invoice
assert assignment1.payment is None
assert assignment1.credit == credit1
assert assignment2.amount == 3
assert assignment2.invoice == invoice
assert assignment2.payment is None
assert assignment2.credit == credit2
def test_basket_validate_generate_invoice_nothing_to_pay(app, simple_user):
app = login(app, username='user', password='user')
regie = Regie.objects.create(label='Foo')
draft_invoice = DraftInvoice.objects.create(
regie=regie,
date_publication=datetime.date(2023, 4, 21),
date_payment_deadline=datetime.date(2023, 4, 22),
date_due=datetime.date(2023, 4, 23),
)
DraftInvoiceLine.objects.create(
slug='event-a-foo-bar',
label='Event A',
event_date=datetime.date(2022, 9, 1),
invoice=draft_invoice,
quantity=1,
unit_amount=1,
user_external_id='user:1',
)
invoice_line2 = DraftInvoiceLine.objects.create(
slug='event-b-foo-bar',
label='Event B',
event_date=datetime.date(2022, 9, 1),
invoice=draft_invoice,
quantity=-1,
unit_amount=1,
user_external_id='user:1',
)
draft_invoice.refresh_from_db()
assert draft_invoice.total_amount == 0
basket = Basket.objects.create(
regie=regie,
draft_invoice=draft_invoice,
payer_nameid='ab' * 16,
expiry_at=now() + datetime.timedelta(hours=1),
payer_external_id='payer:1',
)
line = BasketLine.objects.create(
basket=basket,
closed=True,
user_external_id='user:1',
group_items=False,
)
resp = app.get('/basket/validate/')
with mock.patch('lingo.utils.requests_wrapper.RequestsSession.send') as mock_send:
resp = resp.form.submit()
assert {x[0][0].url for x in mock_send.call_args_list} == set()
assert resp.location.endswith('/basket/')
basket.refresh_from_db()
assert basket.status == 'completed'
assert basket.validated_at is not None
assert basket.paid_at is not None
assert basket.completed_at is not None
invoice = Invoice.objects.latest('pk')
assert basket.invoice == invoice
assert invoice.total_amount == 0
assert Credit.objects.count() == 0
assert Payment.objects.count() == 0
# total is zero, but with credits
invoice_line2.delete()
line.validation_callback_url = 'http://validation1.com'
line.credit_callback_url = 'http://credit1.com'
line.payment_callback_url = 'http://payment1.com'
line.save()
credit = Credit.objects.create(
regie=regie,
payer_external_id='payer:1',
)
CreditLine.objects.create(
credit=credit,
event_date=datetime.date(2022, 9, 1),
quantity=10,
unit_amount=1,
)
draft_invoice.refresh_from_db()
assert draft_invoice.total_amount == 1
basket.status = 'open'
basket.save()
resp = app.get('/basket/validate/')
with mock.patch('lingo.utils.requests_wrapper.RequestsSession.send') as mock_send:
resp = resp.form.submit()
assert {x[0][0].url for x in mock_send.call_args_list} == {
'http://validation1.com/',
'http://payment1.com/',
}
assert resp.location.endswith('/basket/')
basket.refresh_from_db()
assert basket.status == 'completed'
assert basket.validated_at is not None
assert basket.paid_at is not None
assert basket.completed_at is not None
invoice = Invoice.objects.latest('pk')
assert basket.invoice == invoice
assert invoice.total_amount == 1
assert invoice.remaining_amount == 0
assert invoice.paid_amount == 1
assert Credit.objects.count() == 1
credit.refresh_from_db()
assert credit.remaining_amount == 9
assert credit.assigned_amount == 1
assert Payment.objects.count() == 1
payment = Payment.objects.latest('pk')
assert payment.amount == 1
assert payment.payment_type.slug == 'credit'
assert CreditAssignment.objects.count() == 1
assignment = CreditAssignment.objects.latest('pk')
assert assignment.amount == 1
assert assignment.invoice == invoice
assert assignment.payment == payment
assert assignment.credit == credit
assert payment.invoicelinepayment_set.count() == 1
invoicelinepayment = InvoiceLinePayment.objects.latest('pk')
assert invoicelinepayment.line == invoice.lines.get()
assert invoicelinepayment.amount == 1
def test_basket_validate_generate_credit(app, simple_user):
app = login(app, username='user', password='user')
regie = Regie.objects.create(label='Foo')
draft_invoice = DraftInvoice.objects.create(
regie=regie,
date_publication=datetime.date(2023, 4, 21),
date_payment_deadline=datetime.date(2023, 4, 22),
date_due=datetime.date(2023, 4, 23),
payer_external_id='payer:1',
payer_first_name='First',
payer_last_name='Last',
payer_address='41 rue des kangourous\n99999 Kangourou Ville',
)
DraftInvoiceLine.objects.create(
slug='event-a-foo-bar',
label='Event A',
event_date=datetime.date(2022, 9, 1),
invoice=draft_invoice,
quantity=-1,
unit_amount=1,
description='A description',
user_external_id='user:1',
user_first_name='First1',
user_last_name='Last1',
)
draft_invoice.refresh_from_db()
assert draft_invoice.total_amount == -1
basket = Basket.objects.create(
regie=regie,
draft_invoice=draft_invoice,
payer_nameid='ab' * 16,
expiry_at=now() + datetime.timedelta(hours=1),
)
line = BasketLine.objects.create(
basket=basket,
closed=True,
user_external_id='user:1',
)
# credit is not used if basket amount is negative
credit = Credit.objects.create(
regie=regie,
payer_external_id='payer:1',
)
CreditLine.objects.create(
credit=credit,
event_date=datetime.date(2022, 9, 1),
quantity=1,
unit_amount=1,
)
resp = app.get('/basket/validate/')
with mock.patch('lingo.utils.requests_wrapper.RequestsSession.send') as mock_send:
resp = resp.form.submit()
assert {x[0][0].url for x in mock_send.call_args_list} == set()
basket.refresh_from_db()
assert basket.status == 'completed'
assert basket.validated_at is not None
assert basket.paid_at is not None
assert basket.completed_at is not None
assert basket.invoice is None
credit = Credit.objects.latest('pk')
assert basket.credit == credit
assert credit.label == 'Credit from %s' % datetime.date.today().strftime('%d/%m/%Y')
assert credit.total_amount == 1
assert credit.regie == regie
assert credit.payer_external_id == 'payer:1'
assert credit.payer_first_name == 'First'
assert credit.payer_last_name == 'Last'
assert credit.payer_address == '41 rue des kangourous\n99999 Kangourou Ville'
assert credit.lines.count() == 1
(line1,) = credit.lines.all().order_by('pk')
assert line1.event_date == datetime.date(2022, 9, 1)
assert line1.slug == 'event-a-foo-bar'
assert line1.label == 'Event A'
assert line1.quantity == 1
assert line1.unit_amount == 1
assert line1.total_amount == 1
assert line1.user_external_id == 'user:1'
assert line1.user_first_name == 'First1'
assert line1.user_last_name == 'Last1'
assert line1.description == 'A description'
assert Invoice.objects.count() == 0
# check callback
basket.status = 'open'
basket.save()
line.validation_callback_url = 'http://validation1.com'
line.credit_callback_url = 'http://credit1.com'
line.save()
BasketLine.objects.create(
basket=basket,
closed=True,
user_external_id='user:2',
validation_callback_url='http://validation2.com',
credit_callback_url='http://credit2.com',
)
resp = app.get('/basket/validate/')
with mock.patch('lingo.utils.requests_wrapper.RequestsSession.send') as mock_send:
resp = resp.form.submit()
basket.refresh_from_db()
credit = Credit.objects.latest('pk')
assert basket.credit == credit
assert Invoice.objects.count() == 0
assert {x[0][0].url for x in mock_send.call_args_list} == {
'http://validation1.com/',
'http://validation2.com/',
'http://credit1.com/',
'http://credit2.com/',
}
def test_basket_cancel(app, simple_user):
resp = app.get('/basket/cancel/')
assert resp.location.endswith('/login/?next=/basket/cancel/')
app = login(app, username='user', password='user')
# no basket object
app.get('/basket/cancel/', status=404)
# basket without line
regie = Regie.objects.create(label='Foo')
PaymentType.create_defaults(regie)
draft_invoice = DraftInvoice.objects.create(
regie=regie,
date_publication=datetime.date(2023, 4, 21),
date_payment_deadline=datetime.date(2023, 4, 22),
date_due=datetime.date(2023, 4, 23),
)
invoice = Invoice.objects.create(
regie=regie,
date_publication=datetime.date(2023, 4, 21),
date_payment_deadline=datetime.date(2023, 4, 22),
date_due=datetime.date(2023, 4, 23),
)
InvoiceLine.objects.create(
slug='event-a-foo-bar',
label='Event A',
event_date=datetime.date(2022, 9, 1),
invoice=invoice,
quantity=10,
unit_amount=1,
user_external_id='user:1',
)
basket = Basket.objects.create(
regie=regie,
draft_invoice=draft_invoice,
invoice=invoice,
payer_nameid='ab' * 16,
expiry_at=now() + datetime.timedelta(hours=1),
)
app.get('/basket/cancel/', status=404)
# the invoice is partially paid with a credit
credit = Credit.objects.create(
regie=regie,
payer_external_id='payer:1',
)
CreditLine.objects.create(
credit=credit,
event_date=datetime.date(2022, 9, 1),
quantity=1,
unit_amount=1,
)
CreditAssignment.objects.create(
invoice=invoice,
credit=credit,
amount=1,
)
# a not closed line
line = BasketLine.objects.create(
basket=basket,
closed=False,
user_external_id='user:1',
cancel_information_message='Lorem ipsum',
)
app.get('/basket/cancel/', status=404)
# line is closed, but wrong payer_nameid
line.closed = True
line.save()
basket.payer_nameid = uuid.uuid4()
basket.save()
app.get('/basket/cancel/', status=404)
# good payer_nameid
assert CreditAssignment.objects.count() == 1
basket.payer_nameid = 'ab' * 16
basket.save()
resp = app.get('/basket/cancel/')
assert resp.text.count('<p>Lorem ipsum</p>') == 1
with mock.patch('lingo.utils.requests_wrapper.RequestsSession.send') as mock_send:
resp = resp.form.submit()
assert {x[0][0].url for x in mock_send.call_args_list} == set()
assert resp.location.endswith('/basket/')
basket.refresh_from_db()
assert basket.status == 'cancelled'
assert basket.cancelled_at is not None
invoice.refresh_from_db()
assert invoice.cancelled_at is not None
assert CreditAssignment.objects.count() == 0
basket.status = 'tobepaid'
basket.cancelled_at = None
basket.save()
resp = app.get('/basket/cancel/')
with mock.patch('lingo.utils.requests_wrapper.RequestsSession.send') as mock_send:
resp = resp.form.submit()
assert {x[0][0].url for x in mock_send.call_args_list} == set()
assert resp.location.endswith('/basket/')
basket.refresh_from_db()
assert basket.status == 'cancelled'
assert basket.cancelled_at is not None
# wrong status
for status in ['cancelled', 'expired', 'completed']:
basket.status = status
basket.save()
app.get('/basket/cancel/', status=404)
# check callback
basket.status = 'open'
basket.save()
line.cancel_callback_url = 'http://cancellation1.com'
line.save()
BasketLine.objects.create(
basket=basket,
closed=True,
user_external_id='user:2',
cancel_callback_url='http://cancellation2.com',
)
resp = app.get('/basket/cancel/')
with mock.patch('lingo.utils.requests_wrapper.RequestsSession.send') as mock_send:
resp = resp.form.submit()
assert {x[0][0].url for x in mock_send.call_args_list} == {
'http://cancellation1.com/',
'http://cancellation2.com/',
}
# basket is expired
basket.expiry_at = now()
basket.status = 'open'
basket.save()
app.get('/basket/cancel/')
# other lines with information_message
line = BasketLine.objects.create(
basket=basket,
closed=True,
user_external_id='user:3',
user_first_name='First3',
user_last_name='Last3',
cancel_information_message='Lorem ipsum',
)
line = BasketLine.objects.create(
basket=basket,
closed=True,
user_external_id='user:4',
user_first_name='First4',
user_last_name='Last4',
cancel_information_message='Lorem ipsum bis',
)
resp = app.get('/basket/cancel/')
assert resp.text.count('<p>Lorem ipsum</p>') == 1
assert resp.text.count('<p>Lorem ipsum bis</p>') == 1
def test_basket_status_js(app, simple_user):
resp = app.get('/basket/status.js')
assert resp.location.endswith('/login/?next=/basket/status.js')
app = login(app, username='user', password='user')
# no basket object
assert 'basket_entry_count.textContent = ""' in app.get('/basket/status.js').text
# basket without line
regie = Regie.objects.create(label='Foo')
invoice = DraftInvoice.objects.create(
regie=regie,
date_publication=datetime.date(2023, 4, 21),
date_payment_deadline=datetime.date(2023, 4, 22),
date_due=datetime.date(2023, 4, 23),
)
basket = Basket.objects.create(
regie=regie,
draft_invoice=invoice,
payer_nameid='ab' * 16,
expiry_at=now() + datetime.timedelta(hours=1),
)
assert 'basket_entry_count.textContent = ""' in app.get('/basket/status.js').text
# a not closed line
line = BasketLine.objects.create(
basket=basket,
closed=False,
user_external_id='user:1',
)
assert 'basket_entry_count.textContent = ""' in app.get('/basket/status.js').text
# line is closed, but wrong payer_nameid
line.closed = True
line.save()
basket.payer_nameid = uuid.uuid4()
basket.save()
assert 'basket_entry_count.textContent = ""' in app.get('/basket/status.js').text
# good payer_nameid
basket.payer_nameid = 'ab' * 16
basket.save()
assert 'basket_entry_count.textContent = "1"' in app.get('/basket/status.js').text
# basket is expired
basket.expiry_at = now()
basket.status = 'open'
basket.save()
assert 'basket_entry_count.textContent = ""' in app.get('/basket/status.js').text
def test_basket_detail_back_url(app, simple_user):
app = login(app, username='user', password='user')
resp = app.get('/basket/')
assert not resp.pyquery('.basket-back-link')
# set back link
resp = app.get('/basket/?back_url=https%3A//example.net/')
assert resp.pyquery('.basket-back-link')
# check it's maintained in session
resp = app.get('/basket/')
assert resp.pyquery('.basket-back-link')
assert resp.pyquery('.basket-back-link')[0].attrib['href'] == 'https://example.net/'