From 48fc29d36cbfba213f1eb45f3afc90ff993a0ced Mon Sep 17 00:00:00 2001 From: Jonathan Reveille Date: Tue, 17 Dec 2024 15:10:48 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB(debug)=20upda?= =?UTF-8?q?te=20payment=20debug=20view=20with=20`OrderFactory`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `OrderGeneratorFactory` used for the debug payment view was not appropriate because it creates a transaction when the state of the order in in pending payment. When we create a payment with the debug view, and we want to refund it, the method `get_transaction_references_to_refund` would find 2 different transactions with the same amount to refund. Only one out of two is known to the payment provider, and thus, it would raise an error while attempting to refund the order from the backoffice of Joanie. --- src/backend/joanie/debug/views.py | 63 +++++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 7 deletions(-) diff --git a/src/backend/joanie/debug/views.py b/src/backend/joanie/debug/views.py index 4cf1c8d60..3b99c57f4 100644 --- a/src/backend/joanie/debug/views.py +++ b/src/backend/joanie/debug/views.py @@ -6,11 +6,12 @@ import json from decimal import Decimal from logging import getLogger +from uuid import uuid4 from django.conf import settings from django.contrib.auth.mixins import LoginRequiredMixin from django.urls import reverse -from django.utils import translation +from django.utils import timezone, translation from django.utils.decorators import method_decorator from django.views.decorators.csrf import csrf_exempt from django.views.generic.base import TemplateView @@ -29,16 +30,27 @@ PAYMENT_STATE_REFUSED, ) from joanie.core.factories import ( + ContractFactory, + CourseFactory, + CourseProductRelationFactory, + CourseRunFactory, + OrderFactory, OrderGeneratorFactory, + OrganizationFactory, ProductFactory, + UserAddressFactory, UserFactory, ) -from joanie.core.models import Certificate, Contract +from joanie.core.models import Certificate, Contract, CourseState from joanie.core.utils import contract_definition, issuers from joanie.core.utils.sentry import decrypt_data from joanie.payment import get_payment_backend from joanie.payment.enums import INVOICE_TYPE_INVOICE -from joanie.payment.models import CreditCard, Invoice +from joanie.payment.factories import ( + CreditCardFactory, + InvoiceFactory, +) +from joanie.payment.models import Invoice logger = getLogger(__name__) LOGO_FALLBACK = ( @@ -507,17 +519,54 @@ def get_context_data(self, **kwargs): last_name="Card", email="fun.dev+payment@fun-mooc.fr", ) - product = ProductFactory(price=Decimal("123.45")) + organization = OrganizationFactory() + run = CourseRunFactory(state=CourseState.ONGOING_OPEN) + product = ProductFactory( + price=Decimal("123.45"), + contract_definition=factories.ContractDefinitionFactory(), + target_courses=[run.course], + ) product.set_current_language("en-us") product.title = "Test product" product.set_current_language("fr-fr") product.title = "Test produit" product.save() - order = OrderGeneratorFactory( - owner=owner, product=product, state=ORDER_STATE_PENDING_PAYMENT + relation = CourseProductRelationFactory( + product=product, + course=CourseFactory(code="UX-00001"), + organizations=[organization], + ) + order = OrderFactory( + owner=owner, + product=relation.product, + course=relation.course, + organization=organization, + state=ORDER_STATE_PENDING_PAYMENT, + main_invoice=InvoiceFactory( + recipient_address=UserAddressFactory( + owner=owner, + address="1 Rue de l'Apprenant", + postcode="58000", + city="Nevers", + country="FR", + ) + ), + ) + contract = ContractFactory( + order=order, + context={"title": "sample"}, + definition_checksum="1234", + signature_backend_reference=f"wfl_fake_dummy_demo_dev{uuid4()}", + submitted_for_signature_on=None, + student_signed_on=timezone.now(), + organization_signed_on=timezone.now(), ) + contract.refresh_from_db() + order.generate_schedule() + # Credit card for order owner + credit_card = CreditCardFactory(owner=order.owner, is_main=True) billing_address = order.main_invoice.recipient_address - credit_card = CreditCard.objects.filter(owner=owner, is_main=True).first() + order.flow.update() one_click = "one-click" in self.request.GET tokenize_card = "tokenize-card" in self.request.GET zero_click = "zero-click" in self.request.GET