invoicing: move payer id calculation in Payer model (#78015)

This commit is contained in:
Lauréline Guérin 2023-06-15 17:53:04 +02:00
parent 9d57534786
commit a19fa51fae
No known key found for this signature in database
GPG Key ID: 1FAB9B9B4F93D473
8 changed files with 200 additions and 404 deletions

View File

@ -27,8 +27,15 @@ from weasyprint import HTML
from lingo.agendas.models import Agenda
from lingo.api import serializers
from lingo.api.utils import APIErrorBadRequest, Response
from lingo.invoicing.models import DraftInvoice, DraftInvoiceLine, InjectedLine, Invoice, Payment, Regie
from lingo.pricing.models import AgendaPricing, PayerError
from lingo.invoicing.models import (
DraftInvoice,
DraftInvoiceLine,
InjectedLine,
Invoice,
PayerError,
Payment,
Regie,
)
class AgendaCheckTypeList(APIView):
@ -82,32 +89,22 @@ invoicing_regies = InvoicingRegies.as_view()
class InvoiceMixin:
def get_payer_external_ids(self, request, regie, nameid=None, payer_external_id=None):
def get_payer_external_id(self, request, regie, nameid=None, payer_external_id=None):
if payer_external_id:
return [payer_external_id]
return payer_external_id
if not nameid:
raise Http404
payer_external_ids = set()
agenda_pricing_qs = (
AgendaPricing.objects.filter(
agendas__regie=regie,
)
.distinct()
.order_by('pk')
)
for agenda_pricing in agenda_pricing_qs:
try:
payer_external_ids.add(agenda_pricing.get_payer_external_id_from_nameid(request, nameid))
except PayerError:
pass
return list(payer_external_ids)
try:
return regie.get_payer_external_id_from_nameid(request, nameid)
except PayerError:
raise Http404
class InvoicingInvoices(InvoiceMixin, APIView):
permission_classes = (permissions.IsAuthenticated,)
def get_invoices_queryset(self, request, regie):
payer_external_ids = self.get_payer_external_ids(
payer_external_id = self.get_payer_external_id(
request=request,
regie=regie,
nameid=request.GET.get('NameID'),
@ -117,7 +114,7 @@ class InvoicingInvoices(InvoiceMixin, APIView):
regie=regie,
remaining_amount__gt=0,
date_publication__lte=datetime.date.today(),
payer_external_id__in=payer_external_ids,
payer_external_id=payer_external_id,
).order_by('-created_at')
def get(self, request, regie_identifier):
@ -138,7 +135,7 @@ invoicing_invoices = InvoicingInvoices.as_view()
class InvoicingHistoryInvoices(InvoicingInvoices):
def get_invoices_queryset(self, request, regie):
payer_external_ids = self.get_payer_external_ids(
payer_external_id = self.get_payer_external_id(
request=request,
regie=regie,
nameid=request.GET.get('NameID'),
@ -148,7 +145,7 @@ class InvoicingHistoryInvoices(InvoicingInvoices):
regie=regie,
remaining_amount=0,
date_publication__lte=datetime.date.today(),
payer_external_id__in=payer_external_ids,
payer_external_id=payer_external_id,
).order_by('-created_at')
@ -160,7 +157,7 @@ class InvoicingInvoice(InvoiceMixin, APIView):
def get(self, request, regie_identifier, invoice_identifier):
regie = get_object_or_404(Regie, slug=regie_identifier)
payer_external_ids = self.get_payer_external_ids(
payer_external_id = self.get_payer_external_id(
request=request,
regie=regie,
nameid=request.GET.get('NameID'),
@ -171,7 +168,7 @@ class InvoicingInvoice(InvoiceMixin, APIView):
uuid=invoice_identifier,
regie=regie,
date_publication__lte=datetime.date.today(),
payer_external_id__in=payer_external_ids,
payer_external_id=payer_external_id,
)
return Response(
{'data': invoice.normalize(for_backoffice=bool(request.GET.get('payer_external_id')))}
@ -186,7 +183,7 @@ class InvoicingInvoicePDF(InvoiceMixin, APIView):
def get(self, request, regie_identifier, invoice_identifier):
regie = get_object_or_404(Regie, slug=regie_identifier)
payer_external_ids = self.get_payer_external_ids(
payer_external_id = self.get_payer_external_id(
request=request,
regie=regie,
nameid=request.GET.get('NameID'),
@ -197,7 +194,7 @@ class InvoicingInvoicePDF(InvoiceMixin, APIView):
uuid=invoice_identifier,
regie=regie,
date_publication__lte=datetime.date.today(),
payer_external_id__in=payer_external_ids,
payer_external_id=payer_external_id,
)
result = invoice.html()
html = HTML(string=result)

View File

@ -26,7 +26,7 @@ from django.contrib.auth.models import Group
from django.core import validators
from django.core.serializers.json import DjangoJSONEncoder
from django.db import connection, models, transaction
from django.template import RequestContext, Template
from django.template import RequestContext, Template, TemplateSyntaxError, VariableDoesNotExist
from django.template.loader import get_template
from django.utils.formats import date_format
from django.utils.text import slugify
@ -171,6 +171,36 @@ class Payer(models.Model):
result.append((label, value))
return result
def get_payer_external_id(self, request, original_context):
context = RequestContext(request)
context.push(original_context)
tplt = self.payer_external_id_template or ''
if not tplt:
raise PayerError(details={'reason': 'empty-template'})
try:
value = Template(tplt).render(context)
if not value:
raise PayerError(details={'reason': 'empty-result'})
return '%s%s' % (self.payer_external_id_prefix, value)
except TemplateSyntaxError:
raise PayerError(details={'reason': 'syntax-error'})
except VariableDoesNotExist:
raise PayerError(details={'reason': 'variable-error'})
def get_payer_external_id_from_nameid(self, request, original_context):
if not self.carddef_reference:
raise PayerError(details={'reason': 'missing-card-model'})
context = RequestContext(request)
context.push(original_context)
tplt = (
'{{ cards|objects:"%s"|filter_by_user:nameid|first|get:"id"|default:"" }}'
% self.carddef_reference.split(':')[1]
)
value = Template(tplt).render(context)
if not value:
raise PayerError(details={'reason': 'empty-result'})
return '%s%s' % (self.payer_external_id_prefix, value)
def get_payer_data(self, request, payer_external_id):
if not self.carddef_reference:
raise PayerError(details={'reason': 'missing-card-model'})
@ -301,6 +331,20 @@ class Regie(models.Model):
regie_id=self.pk,
)
def get_payer_external_id(self, request, user_external_id):
if not self.payer:
raise PayerError(details={'reason': 'missing-payer'})
context = {'user_external_id': user_external_id}
if ':' in user_external_id:
context['user_external_raw_id'] = user_external_id.split(':')[1]
return self.payer.get_payer_external_id(request, context)
def get_payer_external_id_from_nameid(self, request, nameid):
if not self.payer:
raise PayerError(details={'reason': 'missing-payer'})
context = {'nameid': nameid}
return self.payer.get_payer_external_id_from_nameid(request, context)
def get_payer_data(self, request, payer_external_id):
if not self.payer:
raise PayerError(details={'reason': 'missing-payer'})

View File

@ -23,7 +23,7 @@ from django.utils.translation import gettext_lazy as _
from lingo.agendas.chrono import get_check_status, get_subscriptions
from lingo.agendas.models import Agenda
from lingo.invoicing.models import DraftInvoice, DraftInvoiceLine, InjectedLine, Payer, Regie
from lingo.invoicing.models import DraftInvoice, DraftInvoiceLine, InjectedLine, Payer, PayerError, Regie
from lingo.pricing.models import AgendaPricing, AgendaPricingNotFound, PricingError
@ -115,7 +115,7 @@ def get_invoice_lines_for_user(
payer_data = {}
try:
agenda_pricing = get_agenda_pricing(agendas_pricings_by_agendas.get(agenda.slug), event_date)
payer_external_id = agenda_pricing.get_payer_external_id(request, user_external_id)
payer_external_id = pool.campaign.regie.get_payer_external_id(request, user_external_id)
payer_data = get_cached_payer_data(request, payer_external_id, agenda_pricing=agenda_pricing)
pricing_data = agenda_pricing.get_pricing_data_for_event(
request=request,
@ -125,7 +125,7 @@ def get_invoice_lines_for_user(
user_external_id=user_external_id,
payer_external_id=payer_external_id,
)
except PricingError as e:
except (PayerError, PricingError) as e:
# AgendaPricingNotFound: can happen if pricing model defined only on a part of the requested period
pricing_error = {
'error': type(e).__name__,

View File

@ -235,25 +235,6 @@ class Pricing(models.Model):
'payer_direct_debit',
]
def get_payer_external_id(self, request, original_context, key='payer_external_id'):
context = RequestContext(request)
context.push(original_context)
tplt = self.payer_variables.get(key) or ''
if not tplt:
raise PayerError(details={'reason': 'empty-template'})
try:
value = Template(tplt).render(context)
if not value:
raise PayerError(details={'reason': 'empty-result'})
return value
except TemplateSyntaxError:
raise PayerError(details={'reason': 'syntax-error'})
except VariableDoesNotExist:
raise PayerError(details={'reason': 'variable-error'})
def get_payer_external_id_from_nameid(self, request, original_context):
return self.get_payer_external_id(request, original_context, key='payer_external_id_from_nameid')
@classmethod
def import_json(cls, data):
data = data.copy()
@ -429,16 +410,6 @@ class AgendaPricing(models.Model):
return created, agenda_pricing
def get_payer_external_id(self, request, user_external_id):
context = {'user_external_id': user_external_id}
if ':' in user_external_id:
context['user_external_raw_id'] = user_external_id.split(':')[1]
return self.pricing.get_payer_external_id(request, context)
def get_payer_external_id_from_nameid(self, request, nameid):
context = {'nameid': nameid}
return self.pricing.get_payer_external_id_from_nameid(request, context)
def get_pricing_data(self, request, pricing_date, user_external_id, payer_external_id):
# compute pricing for flat_fee_schedule mode
data = {

View File

@ -7,7 +7,6 @@ from unittest import mock
import pytest
from django.utils.timezone import make_aware
from lingo.agendas.models import Agenda
from lingo.invoicing.models import (
Campaign,
DraftInvoice,
@ -16,11 +15,11 @@ from lingo.invoicing.models import (
Invoice,
InvoiceLine,
InvoicePayment,
PayerError,
Payment,
Pool,
Regie,
)
from lingo.pricing.models import AgendaPricing, Pricing
pytestmark = pytest.mark.django_db
@ -44,7 +43,7 @@ def test_regies(app, user):
]
@mock.patch.object(AgendaPricing, 'get_payer_external_id_from_nameid', autospec=True)
@mock.patch.object(Regie, 'get_payer_external_id_from_nameid', autospec=True)
def test_list_invoices(mock_payer, app, user):
app.get('/api/regie/foo/invoices/', status=403)
app.authorization = ('Basic', ('john.doe', 'password'))
@ -54,10 +53,6 @@ def test_list_invoices(mock_payer, app, user):
regie = Regie.objects.create(label='Foo')
app.get('/api/regie/foo/invoices/', status=404)
resp = app.get('/api/regie/foo/invoices/', params={'NameID': 'foobar'})
assert resp.json['err'] == 0
assert resp.json['data'] == []
invoice = Invoice.objects.create(
label='My invoice',
date_publication=datetime.date(2022, 10, 1),
@ -66,48 +61,15 @@ def test_list_invoices(mock_payer, app, user):
regie=regie,
payer_external_id='payer:1',
)
InvoiceLine.objects.create(
event_date=datetime.date.today(),
invoice=invoice,
quantity=1,
unit_amount=42,
total_amount=42,
status='success',
)
invoice.refresh_from_db()
# no agenda pricing configured, no payer from name id
resp = app.get('/api/regie/foo/invoices/', params={'NameID': 'foobar'})
assert resp.json['err'] == 0
assert resp.json['data'] == []
pricing = Pricing.objects.create(label='Model')
agenda1 = Agenda.objects.create(label='Foo Bar 1', regie=regie)
agenda2 = Agenda.objects.create(label='Foo Bar 2', regie=regie)
agenda3 = Agenda.objects.create(label='Foo Bar 3')
# agenda pricing configured, bot not for the regie
agenda_pricing = AgendaPricing.objects.create(
pricing=pricing,
date_start=datetime.date(year=2021, month=9, day=1),
date_end=datetime.date(year=2022, month=9, day=1),
)
agenda_pricing.agendas.add(agenda3)
# invoice remaining_amount is 0
assert invoice.remaining_amount == 0
mock_payer.return_value = 'payer:1'
resp = app.get('/api/regie/foo/invoices/', params={'NameID': 'foobar'})
assert resp.json['err'] == 0
assert resp.json['data'] == []
assert mock_payer.call_args_list == []
# agenda pricing configured for the regie, but invoice remaining_amount is 0
InvoiceLine.objects.all().delete()
invoice.refresh_from_db()
assert invoice.remaining_amount == 0
agenda_pricing.agendas.add(agenda2)
resp = app.get('/api/regie/foo/invoices/', params={'NameID': 'foobar'})
assert resp.json['err'] == 0
assert resp.json['data'] == []
assert mock_payer.call_args_list == [mock.call(agenda_pricing, mock.ANY, 'foobar')]
assert mock_payer.call_args_list == [mock.call(regie, mock.ANY, 'foobar')]
# invoice with something to pay
InvoiceLine.objects.create(
@ -191,46 +153,16 @@ def test_list_invoices(mock_payer, app, user):
assert resp.json['err'] == 0
assert resp.json['data'] == []
# more than one payer id
invoice_payment.amount = 2
invoice_payment.save()
mock_payer.reset_mock()
agenda_pricing2 = AgendaPricing.objects.create(
pricing=pricing,
date_start=datetime.date(year=2021, month=9, day=1),
date_end=datetime.date(year=2022, month=9, day=1),
)
agenda_pricing2.agendas.add(agenda1)
mock_payer.side_effect = ['payer:1', 'payer:other']
resp = app.get('/api/regie/foo/invoices/', params={'NameID': 'foobar'})
assert resp.json['err'] == 0
assert resp.json['data'] == [
{
'amount': 40,
'amount_paid': 2,
'created': datetime.date.today().isoformat(),
'display_id': '',
'has_pdf': True,
'id': str(invoice.uuid),
'label': 'My invoice',
'online_payment': True,
'paid': False,
'pay_limit_date': datetime.date.today().isoformat(),
'total_amount': 42,
}
]
assert mock_payer.call_args_list == [
mock.call(agenda_pricing, mock.ANY, 'foobar'),
mock.call(agenda_pricing2, mock.ANY, 'foobar'),
]
# no matching payer id
mock_payer.side_effect = None
mock_payer.return_value = 'payer:unknown'
resp = app.get('/api/regie/foo/invoices/', params={'NameID': 'foobar'})
assert resp.json['err'] == 0
assert resp.json['data'] == []
# payer error
mock_payer.side_effect = PayerError
app.get('/api/regie/foo/invoices/', params={'NameID': 'foobar'}, status=404)
def test_list_invoices_for_payer(app, user):
app.get('/api/regie/foo/invoices/', status=403)
@ -344,7 +276,7 @@ def test_list_invoices_for_payer(app, user):
assert resp.json['data'] == []
@mock.patch.object(AgendaPricing, 'get_payer_external_id_from_nameid', autospec=True)
@mock.patch.object(Regie, 'get_payer_external_id_from_nameid', autospec=True)
def test_list_history_invoices(mock_payer, app, user):
app.get('/api/regie/foo/invoices/history/', status=403)
app.authorization = ('Basic', ('john.doe', 'password'))
@ -354,10 +286,6 @@ def test_list_history_invoices(mock_payer, app, user):
regie = Regie.objects.create(label='Foo')
app.get('/api/regie/foo/invoices/history/', status=404)
resp = app.get('/api/regie/foo/invoices/history/', params={'NameID': 'foobar'})
assert resp.json['err'] == 0
assert resp.json['data'] == []
invoice = Invoice.objects.create(
label='My invoice',
date_publication=datetime.date(2022, 10, 1),
@ -383,42 +311,17 @@ def test_list_history_invoices(mock_payer, app, user):
invoice_payment = InvoicePayment.objects.create(
payment=payment,
invoice=invoice,
amount=42,
amount=2,
)
invoice.refresh_from_db()
# no agenda pricing configured, no payer from name id
resp = app.get('/api/regie/foo/invoices/history/', params={'NameID': 'foobar'})
assert resp.json['err'] == 0
assert resp.json['data'] == []
pricing = Pricing.objects.create(label='Model')
agenda1 = Agenda.objects.create(label='Foo Bar 1', regie=regie)
agenda2 = Agenda.objects.create(label='Foo Bar 2', regie=regie)
agenda3 = Agenda.objects.create(label='Foo Bar 3')
# agenda pricing configured, bot not for the regie
agenda_pricing = AgendaPricing.objects.create(
pricing=pricing,
date_start=datetime.date(year=2021, month=9, day=1),
date_end=datetime.date(year=2022, month=9, day=1),
)
agenda_pricing.agendas.add(agenda3)
# invoice remaining_amount is not 0
assert invoice.remaining_amount != 0
mock_payer.return_value = 'payer:1'
resp = app.get('/api/regie/foo/invoices/history/', params={'NameID': 'foobar'})
assert resp.json['err'] == 0
assert resp.json['data'] == []
assert mock_payer.call_args_list == []
# agenda pricing configured for the regie, but invoice remaining_amount is not 0
invoice_payment.amount = 2
invoice_payment.save()
invoice.refresh_from_db()
assert invoice.remaining_amount != 0
agenda_pricing.agendas.add(agenda2)
resp = app.get('/api/regie/foo/invoices/history/', params={'NameID': 'foobar'})
assert resp.json['err'] == 0
assert resp.json['data'] == []
assert mock_payer.call_args_list == [mock.call(agenda_pricing, mock.ANY, 'foobar')]
assert mock_payer.call_args_list == [mock.call(regie, mock.ANY, 'foobar')]
# invoice with nothing to pay
invoice_payment.amount = 42
@ -458,46 +361,16 @@ def test_list_history_invoices(mock_payer, app, user):
assert resp.json['err'] == 0
assert resp.json['data'] == []
# more than one payer id
invoice.regie = regie
invoice.save()
mock_payer.reset_mock()
agenda_pricing2 = AgendaPricing.objects.create(
pricing=pricing,
date_start=datetime.date(year=2021, month=9, day=1),
date_end=datetime.date(year=2022, month=9, day=1),
)
agenda_pricing2.agendas.add(agenda1)
mock_payer.side_effect = ['payer:1', 'payer:other']
resp = app.get('/api/regie/foo/invoices/history/', params={'NameID': 'foobar'})
assert resp.json['err'] == 0
assert resp.json['data'] == [
{
'amount': 0,
'amount_paid': 42,
'created': datetime.date.today().isoformat(),
'display_id': '',
'has_pdf': True,
'id': str(invoice.uuid),
'label': 'My invoice',
'online_payment': False,
'paid': True,
'pay_limit_date': '',
'total_amount': 42,
}
]
assert mock_payer.call_args_list == [
mock.call(agenda_pricing, mock.ANY, 'foobar'),
mock.call(agenda_pricing2, mock.ANY, 'foobar'),
]
# no matching payer id
mock_payer.side_effect = None
mock_payer.return_value = 'payer:unknown'
resp = app.get('/api/regie/foo/invoices/history/', params={'NameID': 'foobar'})
assert resp.json['err'] == 0
assert resp.json['data'] == []
# payer error
mock_payer.side_effect = PayerError
app.get('/api/regie/foo/invoices/history/', params={'NameID': 'foobar'}, status=404)
def test_list_history_invoices_for_payer(app, user):
app.get('/api/regie/foo/invoices/history/', status=403)
@ -585,7 +458,7 @@ def test_list_history_invoices_for_payer(app, user):
assert resp.json['data'] == []
@mock.patch.object(AgendaPricing, 'get_payer_external_id_from_nameid', autospec=True)
@mock.patch.object(Regie, 'get_payer_external_id_from_nameid', autospec=True)
def test_detail_invoice(mock_payer, app, user):
app.get('/api/regie/foo/invoice/%s/' % str(uuid.uuid4()), status=403)
app.authorization = ('Basic', ('john.doe', 'password'))
@ -615,27 +488,7 @@ def test_detail_invoice(mock_payer, app, user):
)
invoice.refresh_from_db()
# no agenda pricing configured, no payer from name id
resp = app.get('/api/regie/foo/invoice/%s/' % str(invoice.uuid), params={'NameID': 'foobar'}, status=404)
pricing = Pricing.objects.create(label='Model')
agenda1 = Agenda.objects.create(label='Foo Bar 1', regie=regie)
agenda2 = Agenda.objects.create(label='Foo Bar 2', regie=regie)
agenda3 = Agenda.objects.create(label='Foo Bar 3')
# agenda pricing configured, bot not for the regie
agenda_pricing = AgendaPricing.objects.create(
pricing=pricing,
date_start=datetime.date(year=2021, month=9, day=1),
date_end=datetime.date(year=2022, month=9, day=1),
)
agenda_pricing.agendas.add(agenda3)
mock_payer.return_value = 'payer:1'
resp = app.get('/api/regie/foo/invoice/%s/' % str(invoice.uuid), params={'NameID': 'foobar'}, status=404)
assert mock_payer.call_args_list == []
# agenda pricing configured for the regie
agenda_pricing.agendas.add(agenda2)
resp = app.get('/api/regie/foo/invoice/%s/' % str(invoice.uuid), params={'NameID': 'foobar'})
assert resp.json['err'] == 0
assert resp.json['data'] == {
@ -712,24 +565,7 @@ def test_detail_invoice(mock_payer, app, user):
'total_amount': 42,
}
# more than one payer id
mock_payer.reset_mock()
agenda_pricing2 = AgendaPricing.objects.create(
pricing=pricing,
date_start=datetime.date(year=2021, month=9, day=1),
date_end=datetime.date(year=2022, month=9, day=1),
)
agenda_pricing2.agendas.add(agenda1)
mock_payer.side_effect = ['payer:1', 'payer:other']
resp = app.get('/api/regie/foo/invoice/%s/' % str(invoice.uuid), params={'NameID': 'foobar'})
assert resp.json['err'] == 0
assert mock_payer.call_args_list == [
mock.call(agenda_pricing, mock.ANY, 'foobar'),
mock.call(agenda_pricing2, mock.ANY, 'foobar'),
]
# no matching payer id
mock_payer.side_effect = None
mock_payer.return_value = 'payer:unknown'
resp = app.get('/api/regie/foo/invoice/%s/' % str(invoice.uuid), params={'NameID': 'foobar'}, status=404)
@ -846,7 +682,7 @@ def test_detail_invoice_for_payer(app, user):
}
@mock.patch.object(AgendaPricing, 'get_payer_external_id_from_nameid', autospec=True)
@mock.patch.object(Regie, 'get_payer_external_id_from_nameid', autospec=True)
def test_pdf_invoice(mock_payer, app, user):
app.get('/api/regie/foo/invoice/%s/pdf/' % str(uuid.uuid4()), status=403)
app.authorization = ('Basic', ('john.doe', 'password'))
@ -880,31 +716,7 @@ def test_pdf_invoice(mock_payer, app, user):
)
invoice.refresh_from_db()
# no agenda pricing configured, no payer from name id
resp = app.get(
'/api/regie/foo/invoice/%s/pdf/' % str(invoice.uuid), params={'NameID': 'foobar'}, status=404
)
pricing = Pricing.objects.create(label='Model')
agenda1 = Agenda.objects.create(label='Foo Bar 1', regie=regie)
agenda2 = Agenda.objects.create(label='Foo Bar 2', regie=regie)
agenda3 = Agenda.objects.create(label='Foo Bar 3')
# agenda pricing configured, bot not for the regie
agenda_pricing = AgendaPricing.objects.create(
pricing=pricing,
date_start=datetime.date(year=2021, month=9, day=1),
date_end=datetime.date(year=2022, month=9, day=1),
)
agenda_pricing.agendas.add(agenda3)
mock_payer.return_value = 'payer:1'
resp = app.get(
'/api/regie/foo/invoice/%s/pdf/' % str(invoice.uuid), params={'NameID': 'foobar'}, status=404
)
assert mock_payer.call_args_list == []
# agenda pricing configured for the regie
agenda_pricing.agendas.add(agenda2)
resp = app.get('/api/regie/foo/invoice/%s/pdf/' % str(invoice.uuid), params={'NameID': 'foobar'})
assert resp.headers['Content-Disposition'] == 'attachment; filename="%s.pdf"' % invoice.formatted_number
@ -924,29 +736,14 @@ def test_pdf_invoice(mock_payer, app, user):
'/api/regie/foo/invoice/%s/pdf/' % str(invoice.uuid), params={'NameID': 'foobar'}, status=404
)
# more than one payer id
invoice.regie = regie
invoice.save()
mock_payer.reset_mock()
agenda_pricing2 = AgendaPricing.objects.create(
pricing=pricing,
date_start=datetime.date(year=2021, month=9, day=1),
date_end=datetime.date(year=2022, month=9, day=1),
)
agenda_pricing2.agendas.add(agenda1)
mock_payer.side_effect = ['payer:1', 'payer:other']
resp = app.get('/api/regie/foo/invoice/%s/pdf/' % str(invoice.uuid), params={'NameID': 'foobar'})
assert resp.headers['Content-Disposition'] == 'attachment; filename="%s.pdf"' % invoice.formatted_number
assert mock_payer.call_args_list == [
mock.call(agenda_pricing, mock.ANY, 'foobar'),
mock.call(agenda_pricing2, mock.ANY, 'foobar'),
]
# no matching payer id
mock_payer.side_effect = None
mock_payer.return_value = 'payer:unknown'
resp = app.get('/api/regie/foo/invoice/%s/' % str(invoice.uuid), params={'NameID': 'foobar'}, status=404)
# payer error
mock_payer.side_effect = PayerError
app.get('/api/regie/foo/invoice/%s/' % str(invoice.uuid), params={'NameID': 'foobar'}, status=404)
def test_pdf_invoice_for_payer(app, user):
app.get('/api/regie/foo/invoice/%s/pdf/' % str(uuid.uuid4()), status=403)

View File

@ -18,6 +18,7 @@ from lingo.invoicing.models import (
InjectedLine,
Invoice,
InvoiceLine,
PayerError,
Pool,
PoolPromotionError,
Regie,
@ -27,7 +28,6 @@ from lingo.pricing.models import (
Criteria,
CriteriaCategory,
PayerDataError,
PayerError,
Pricing,
PricingError,
)
@ -253,7 +253,7 @@ def test_get_invoice_lines_for_user_check_status_error(mock_status):
@pytest.mark.parametrize('injected_lines', ['no', 'period', 'all'])
@mock.patch('lingo.invoicing.utils.get_check_status')
@mock.patch('lingo.pricing.models.AgendaPricing.get_payer_external_id')
@mock.patch('lingo.invoicing.models.Regie.get_payer_external_id')
@mock.patch('lingo.pricing.models.AgendaPricing.get_pricing_data_for_event')
def test_get_invoice_lines_for_user_check_status(
mock_pricing_data_event, mock_payer, mock_status, injected_lines
@ -768,7 +768,7 @@ def test_get_invoice_lines_for_user_check_status(
@mock.patch('lingo.invoicing.utils.get_check_status')
@mock.patch('lingo.pricing.models.AgendaPricing.get_payer_external_id')
@mock.patch('lingo.invoicing.models.Regie.get_payer_external_id')
def test_get_invoice_lines_for_user_get_payer_id_error(mock_payer, mock_status):
regie = Regie.objects.create(label='Regie')
agenda = Agenda.objects.create(label='Agenda')
@ -843,7 +843,7 @@ def test_get_invoice_lines_for_user_get_payer_id_error(mock_payer, mock_status):
@mock.patch('lingo.invoicing.utils.get_check_status')
@mock.patch('lingo.pricing.models.AgendaPricing.get_payer_external_id')
@mock.patch('lingo.invoicing.models.Regie.get_payer_external_id')
@mock.patch('lingo.invoicing.models.Regie.get_payer_data')
def test_get_invoice_lines_for_user_get_payer_data_error(mock_payer_data, mock_payer, mock_status):
regie = Regie.objects.create(label='Regie')
@ -984,7 +984,7 @@ def test_get_invoice_lines_for_user_get_payer_id_and_data(mock_status):
},
}.get(payer_external_id)
payer_patch = mock.patch.object(AgendaPricing, 'get_payer_external_id', autospec=True)
payer_patch = mock.patch.object(Regie, 'get_payer_external_id', autospec=True)
payer_data_patch = mock.patch.object(Regie, 'get_payer_data', autospec=True)
with payer_patch as mock_payer, payer_data_patch as mock_payer_data:
mock_payer.side_effect = lambda *args: get_payer(*args)
@ -1046,9 +1046,9 @@ def test_get_invoice_lines_for_user_get_payer_id_and_data(mock_status):
},
}
assert mock_payer.call_args_list == [
mock.call(agenda_pricing, mock.ANY, 'user:1'),
mock.call(agenda_pricing, mock.ANY, 'user:2'),
mock.call(agenda_pricing, mock.ANY, 'user:1'),
mock.call(regie, mock.ANY, 'user:1'),
mock.call(regie, mock.ANY, 'user:2'),
mock.call(regie, mock.ANY, 'user:1'),
]
assert mock_payer_data.call_args_list == [
mock.call(regie, mock.ANY, 'payer:1'),
@ -1152,7 +1152,7 @@ def test_get_invoice_lines_for_user_get_payer_id_and_data(mock_status):
@mock.patch('lingo.invoicing.utils.get_check_status')
@mock.patch('lingo.pricing.models.AgendaPricing.get_payer_external_id')
@mock.patch('lingo.invoicing.models.Regie.get_payer_external_id')
def test_get_invoice_lines_for_user_check_status_agenda_pricing_dates(mock_payer, mock_status):
regie = Regie.objects.create(label='Regie')
agenda = Agenda.objects.create(label='Agenda')
@ -1324,7 +1324,7 @@ def test_get_invoice_lines_for_user_check_status_agenda_pricing_dates(mock_payer
@mock.patch('lingo.invoicing.utils.get_check_status')
@mock.patch('lingo.pricing.models.AgendaPricing.get_payer_external_id')
@mock.patch('lingo.invoicing.models.Regie.get_payer_external_id')
@mock.patch('lingo.pricing.models.AgendaPricing.get_pricing_data_for_event')
def test_get_invoice_lines_for_user_check_status_pricing_error(
mock_pricing_data_event, mock_payer, mock_status
@ -1569,7 +1569,7 @@ def test_get_all_invoice_lines(mock_user_lines):
@mock.patch('lingo.invoicing.utils.get_check_status')
@mock.patch('lingo.pricing.models.AgendaPricing.get_payer_external_id')
@mock.patch('lingo.invoicing.models.Regie.get_payer_external_id')
@mock.patch('lingo.invoicing.models.Regie.get_payer_data')
def test_get_all_invoice_lines_queryset(mock_payer_data, mock_payer, mock_status):
# don't mock get_pricing_data_for_event to check all querysets

View File

@ -436,6 +436,99 @@ def test_regie_format_number():
assert regie.format_number(datetime.date(2024, 12, 15), 42000000) == 'Ffoobar-2024-42000000'
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_get_payer_external_id(mock_send, context, nocache):
payer = Payer.objects.create(label='Payer')
regie = Regie.objects.create(label='Regie')
with pytest.raises(PayerError) as e:
regie.get_payer_external_id(request=context['request'], user_external_id='child:42')
assert e.value.details == {'reason': 'missing-payer'}
regie.payer = payer
regie.save()
values = [
('bar', 'bar'),
('{{ 40|add:2 }}', '42'),
('{{ cards|objects:"card_model_1"|first|get:"id" }}', '42'),
]
for value, result in values:
payer.payer_external_id_prefix = ''
payer.payer_external_id_template = value
payer.save()
assert regie.get_payer_external_id(request=context['request'], user_external_id='child:42') == result
payer.payer_external_id_prefix = 'prefix:'
payer.save()
assert (
regie.get_payer_external_id(request=context['request'], user_external_id='child:42')
== 'prefix:%s' % result
)
values = [
('', 'empty-template'),
('{{ "" }}', 'empty-result'),
('{% for %}', 'syntax-error'),
('{{ "foo"|add:user.email }}', 'variable-error'),
]
for value, error in values:
payer.payer_external_id_template = value
payer.save()
with pytest.raises(PayerError) as e:
regie.get_payer_external_id(request=context['request'], user_external_id='child:42')
assert e.value.details == {'reason': error}
# user_external_id can be used in variables
payer.payer_external_id_template = (
'{{ cards|objects:"qf"|filter_by:"foo"|filter_value:user_external_id|first|get:"id" }}'
)
payer.save()
mock_send.reset_mock()
regie.get_payer_external_id(request=context['request'], user_external_id='child:42')
assert 'filter-foo=child%3A42&' in mock_send.call_args_list[0][0][0].url
payer.payer_external_id_template = (
'{{ cards|objects:"qf"|filter_by:"foo"|filter_value:user_external_raw_id|first|get:"id" }}',
)
payer.save()
mock_send.reset_mock()
regie.get_payer_external_id(request=context['request'], user_external_id='child:42')
assert 'filter-foo=42&' in mock_send.call_args_list[0][0][0].url
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_get_payer_external_id_from_nameid(mock_send, context, nocache):
payer = Payer.objects.create(label='Payer')
regie = Regie.objects.create(label='Regie')
with pytest.raises(PayerError) as e:
regie.get_payer_external_id_from_nameid(request=context['request'], nameid='foobar')
assert e.value.details == {'reason': 'missing-payer'}
regie.payer = payer
regie.save()
with pytest.raises(PayerError) as e:
regie.get_payer_external_id_from_nameid(request=context['request'], nameid='foobar')
assert e.value.details == {'reason': 'missing-card-model'}
payer.carddef_reference = 'default:card_model_1'
payer.save()
regie.get_payer_external_id_from_nameid(request=context['request'], nameid='foobar')
assert '/api/cards/card_model_1/list?' in mock_send.call_args_list[-1][0][0].url
assert '&filter-user-uuid=foobar&' in mock_send.call_args_list[-1][0][0].url
assert regie.get_payer_external_id_from_nameid(request=context['request'], nameid='foobar') == '42'
payer.payer_external_id_prefix = 'prefix:'
payer.save()
assert regie.get_payer_external_id_from_nameid(request=context['request'], nameid='foobar') == 'prefix:42'
payer.carddef_reference = 'default:card_model_2'
payer.save()
with pytest.raises(PayerError) as e:
regie.get_payer_external_id_from_nameid(request=context['request'], nameid='foobar')
assert e.value.details == {'reason': 'empty-result'}
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_get_payer_data(mock_send, context, nocache):
payer = Payer.objects.create(label='Payer')

View File

@ -16,8 +16,6 @@ from lingo.pricing.models import (
CriteriaCategory,
CriteriaConditionNotFound,
MultipleDefaultCriteriaCondition,
PayerDataError,
PayerError,
Pricing,
PricingBookingCheckTypeError,
PricingBookingNotCheckedError,
@ -1688,107 +1686,3 @@ def test_agenda_pricing_iter_pricing_matrix_empty():
agenda_pricing.agendas.add(agenda)
assert list(agenda_pricing.iter_pricing_matrix()) == []
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_get_payer_external_id(mock_send, context, nocache):
pricing = Pricing.objects.create(label='Foo bar')
agenda_pricing = AgendaPricing.objects.create(
pricing=pricing,
date_start=datetime.date(year=2021, month=9, day=1),
date_end=datetime.date(year=2021, month=10, day=1),
)
values = [
('bar', 'bar'),
('{{ 40|add:2 }}', '42'),
('{{ cards|objects:"foo"|first|get:"id" }}', '1'),
]
for value, result in values:
pricing.payer_variables = {
'payer_external_id': value,
}
pricing.save()
assert (
agenda_pricing.get_payer_external_id(request=context['request'], user_external_id='child:42')
== result
)
values = [
('', 'empty-template'),
('{{ "" }}', 'empty-result'),
('{% for %}', 'syntax-error'),
('{{ "foo"|add:user.email }}', 'variable-error'),
]
for value, error in values:
pricing.payer_variables = {
'payer_external_id': value,
}
pricing.save()
with pytest.raises(PayerError) as e:
agenda_pricing.get_payer_external_id(request=context['request'], user_external_id='child:42')
assert e.value.details == {'reason': error}
# user_external_id can be used in variables
pricing.payer_variables = {
'payer_external_id': '{{ cards|objects:"qf"|filter_by:"foo"|filter_value:user_external_id|first|get:"id" }}',
}
pricing.save()
mock_send.reset_mock()
agenda_pricing.get_payer_external_id(request=context['request'], user_external_id='child:42')
assert 'filter-foo=child%3A42&' in mock_send.call_args_list[0][0][0].url
pricing.payer_variables = {
'payer_external_id': '{{ cards|objects:"qf"|filter_by:"foo"|filter_value:user_external_raw_id|first|get:"id" }}',
}
pricing.save()
mock_send.reset_mock()
agenda_pricing.get_payer_external_id(request=context['request'], user_external_id='child:42')
assert 'filter-foo=42&' in mock_send.call_args_list[0][0][0].url
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_get_payer_external_id_from_nameid(mock_send, context, nocache):
pricing = Pricing.objects.create(label='Foo bar')
agenda_pricing = AgendaPricing.objects.create(
pricing=pricing,
date_start=datetime.date(year=2021, month=9, day=1),
date_end=datetime.date(year=2021, month=10, day=1),
)
values = [
('bar', 'bar'),
('{{ 40|add:2 }}', '42'),
('{{ cards|objects:"foo"|first|get:"id" }}', '1'),
]
for value, result in values:
pricing.payer_variables = {
'payer_external_id_from_nameid': value,
}
pricing.save()
assert (
agenda_pricing.get_payer_external_id_from_nameid(request=context['request'], nameid='foobar')
== result
)
values = [
('', 'empty-template'),
('{{ "" }}', 'empty-result'),
('{% for %}', 'syntax-error'),
('{{ "foo"|add:user.email }}', 'variable-error'),
]
for value, error in values:
pricing.payer_variables = {
'payer_external_id_from_nameid': value,
}
pricing.save()
with pytest.raises(PayerError) as e:
agenda_pricing.get_payer_external_id_from_nameid(request=context['request'], nameid='foobar')
assert e.value.details == {'reason': error}
pricing.payer_variables = {
'payer_external_id_from_nameid': '{{ cards|objects:"qf"|filter_by_user:nameid|first|get:"id" }}',
}
pricing.save()
mock_send.reset_mock()
agenda_pricing.get_payer_external_id_from_nameid(request=context['request'], nameid='foobar')
assert 'filter-user-uuid=foobar&' in mock_send.call_args_list[0][0][0].url