ajouter ?for-payment quand on lit une facture pour la payer (#76853) #85

Merged
bdauvergne merged 3 commits from wip/76853-lingo-lors-du-get-invoice-pour-p into main 2024-02-27 09:26:45 +01:00
4 changed files with 84 additions and 4 deletions

View File

@ -0,0 +1,19 @@
# Generated by Django 3.2.18 on 2023-04-20 23:11
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('lingo', '0056_increase_extra_css_class'),
]
operations = [
migrations.AddField(
model_name='regie',
name='has_invoice_for_payment',
field=models.BooleanField(
default=False, verbose_name='The invoice endpoint handle the for-payment parameter'
),
),
]

View File

@ -319,6 +319,9 @@ class Regie(models.Model):
can_pay_only_one_basket_item = models.BooleanField(
default=True, verbose_name=_('Basket items must be paid individually')
)
has_invoice_for_payment = models.BooleanField(
default=False, verbose_name=_('The invoice endpoint handle the for-payment parameter')
)
def is_remote(self):
return self.webservice_url != ''
@ -384,6 +387,11 @@ class Regie(models.Model):
raise RegieException(regie_exc_msg) from e
if items.get('err'):
raise RegieException(regie_exc_msg)
if not history:
has_invoice_for_payment = items.get('has_invoice_for_payment', False)
if self.has_invoice_for_payment != has_invoice_for_payment:
self.has_invoice_for_payment = has_invoice_for_payment
self.save(update_fields=['has_invoice_for_payment'])
if items.get('data'):
if not isinstance(items['data'], list):
raise RegieException(regie_exc_msg)
@ -410,12 +418,15 @@ class Regie(models.Model):
log_errors=True,
raise_4xx=False,
update_paid=False,
for_payment=False,
):
if not self.is_remote():
return self.basketitem_set.get(pk=invoice_id)
url = self.webservice_url + '/invoice/%s/' % invoice_id
if payer_external_id:
url += '?payer_external_id=%s' % payer_external_id
if self.has_invoice_for_payment and for_payment:
url += ('?' if '?' not in url else '&') + 'payment'
response = requests.get(
url,
user=user if not payer_external_id else None,
@ -1065,7 +1076,9 @@ class Transaction(models.Model):
to_be_paid_remote_items = []
for item_id in items:
try:
remote_item = regie.get_invoice(user=self.user, invoice_id=item_id, raise_4xx=True)
remote_item = regie.get_invoice(
user=self.user, invoice_id=item_id, raise_4xx=True, for_payment=True
)
with atomic(savepoint=False):
self.items.add(self.create_paid_invoice_basket_item(item_id, remote_item))
regie.pay_invoice(item_id, self.order_id, self.bank_transaction_date or self.end_date)

View File

@ -512,7 +512,7 @@ class PayView(PayMixin, View):
regie = Regie.objects.get(pk=regie_id)
# get all items data from regie webservice
for item_id in request.POST.getlist('item'):
remote_items.append(regie.get_invoice(user, item_id, update_paid=True))
remote_items.append(regie.get_invoice(user, item_id, update_paid=True, for_payment=True))
except (requests.exceptions.RequestException, RemoteInvoiceException):
messages.error(request, _('Technical error: impossible to retrieve invoices.'))
return HttpResponseRedirect(next_url)

View File

@ -30,6 +30,7 @@ from combo.apps.lingo.models import (
SelfDeclaredInvoicePayment,
Transaction,
)
from combo.apps.lingo.views import PayView
from combo.data.models import Page
from combo.utils import aes_hex_encrypt, check_query
@ -1133,21 +1134,27 @@ def test_send_new_remote_invoices_by_email(mock_get, user_saml, admin, app, remo
def remote_invoices_httmock():
invoices = []
invoice = {}
kwargs = {}
netloc = 'remote.regie.example.com'
@httmock.urlmatch(netloc=netloc, path='^/invoice/')
@httmock.remember_called
def invoice_mock(url, request):
return json.dumps({'err': 0, 'data': invoice})
return json.dumps({'err': 0, 'data': invoice, **kwargs})
@httmock.urlmatch(netloc=netloc, path='^/invoices/')
@httmock.remember_called
def invoices_mock(url, request):
return json.dumps({'err': 0, 'data': invoices})
return json.dumps({'err': 0, 'data': invoices, **kwargs})
context_manager = httmock.HTTMock(invoices_mock, invoice_mock)
context_manager.url = 'https://%s/' % netloc
context_manager.invoices = invoices
context_manager.invoice = invoice
context_manager.invoice_mock = invoice_mock
context_manager.invoices_mock = invoices_mock
context_manager.kwargs = kwargs
with context_manager:
yield context_manager
@ -1639,3 +1646,44 @@ def test_wrong_crypted_credit(mock_get, remote_regie, app):
mock_json.json.return_value = {'err': 0, 'data': CREDITS[0]}
mock_get.return_value = mock_json
app.get('/lingo/credit/%s/%s/' % (remote_regie.id, 'zrzer854sfaear45e6rzerzerzef'), status=404)
def test_has_invoice_for_payment_provisionning(remote_regie, remote_invoices_httmock):
remote_regie.webservice_url = remote_invoices_httmock.url
remote_regie.save()
user = MockUser()
assert not remote_regie.has_invoice_for_payment
remote_invoices_httmock.invoices[:] = INVOICES
remote_regie.get_invoices(user)
remote_regie.refresh_from_db()
assert not remote_regie.has_invoice_for_payment
remote_invoices_httmock.kwargs.update({'has_invoice_for_payment': True})
remote_regie.get_invoices(user)
remote_regie.refresh_from_db()
assert remote_regie.has_invoice_for_payment
def test_pay_with_has_invoice_for_payment(rf, remote_regie, remote_invoices_httmock):
remote_regie.webservice_url = remote_invoices_httmock.url
remote_regie.save()
remote_invoices_httmock.invoice.update(INVOICES[0])
user = User.objects.create()
request = rf.post('/pay/', {'regie': remote_regie.id, 'item': 1})
request.user = user
request.session = mock.MagicMock()
request._messages = mock.Mock()
pay_view = PayView.as_view()
pay_view(request)
assert remote_invoices_httmock.invoice_mock.call['count'] == 1
assert '?payment' not in remote_invoices_httmock.invoice_mock.call['requests'][0].url
remote_regie.has_invoice_for_payment = True
remote_regie.save()
pay_view(request)
assert remote_invoices_httmock.invoice_mock.call['count'] == 2
assert '?payment' in remote_invoices_httmock.invoice_mock.call['requests'][1].url