integration of 3D secure v2 for eboutic bank payment

This commit is contained in:
Thomas Girod
2022-11-28 17:03:46 +01:00
parent e43d53e564
commit fe9e5ce861
26 changed files with 1896 additions and 763 deletions

View File

@ -21,6 +21,7 @@
# Place - Suite 330, Boston, MA 02111-1307, USA.
#
#
from django.db.models.functions import Length
from sith.settings import SITH_COUNTER_OFFICES, SITH_MAIN_CLUB
from django.db import models
@ -38,16 +39,19 @@ import string
import os
import base64
import datetime
from dict2xml import dict2xml
from club.models import Club, Membership
from accounting.models import CurrencyField
from core.models import Group, User, Notification
from subscription.models import Subscription
from django_countries.fields import CountryField
class Customer(models.Model):
"""
This class extends a user to make a customer. It adds some basic customers informations, such as the accound ID, and
This class extends a user to make a customer. It adds some basic customers' information, such as the account ID, and
is used by other accounting classes as reference to the customer, rather than using User
"""
@ -89,13 +93,28 @@ class Customer(models.Model):
.subscription_end
) < timedelta(days=90)
@staticmethod
def generate_account_id(number):
number = str(number)
letter = random.choice(string.ascii_lowercase)
while Customer.objects.filter(account_id=number + letter).exists():
letter = random.choice(string.ascii_lowercase)
return number + letter
@classmethod
def new_for_user(cls, user: User):
"""
Create a new Customer instance for the user given in parameter without saving it
The account if is automatically generated and the amount set at 0
"""
# account_id are number with a letter appended
account_id = (
Customer.objects.order_by(Length("account_id"), "account_id")
.values("account_id")
.last()
)
if account_id is None:
# legacy from the old site
return cls(user=user, account_id="1504a", amount=0)
account_id = account_id["account_id"]
num = int(account_id[:-1])
while Customer.objects.filter(account_id=account_id).exists():
num += 1
account_id = str(num) + random.choice(string.ascii_lowercase)
return cls(user=user, account_id=account_id, amount=0)
def save(self, allow_negative=False, is_selling=False, *args, **kwargs):
"""
@ -122,6 +141,53 @@ class Customer(models.Model):
return "".join(["https://", settings.SITH_URL, self.get_absolute_url()])
class BillingInfo(models.Model):
"""
Represent the billing information of a user, which are required
by the 3D-Secure v2 system used by the etransaction module
"""
customer = models.OneToOneField(
Customer, related_name="billing_infos", on_delete=models.CASCADE
)
# declaring surname and name even though they are already defined
# in User add some redundancy, but ensures that the billing infos
# shall stay correct, whatever shenanigans the user commits on its profile
first_name = models.CharField(_("First name"), max_length=30)
last_name = models.CharField(_("Last name"), max_length=30)
address_1 = models.CharField(_("Address 1"), max_length=50)
address_2 = models.CharField(_("Address 2"), max_length=50, blank=True, null=True)
zip_code = models.CharField(_("Zip code"), max_length=16) # code postal
city = models.CharField(_("City"), max_length=50)
country = CountryField(blank_label=_("Country"))
def to_3dsv2_xml(self) -> str:
"""
Convert the data from this model into a xml usable
by the online paying service of the Crédit Agricole bank.
see : `https://www.ca-moncommerce.com/espace-client-mon-commerce/up2pay-e-transactions/ma-documentation/manuel-dintegration-focus-3ds-v2/principes-generaux/#boutique-cms-utilisation-des-modules-up2pay-e-transactions-mise-a-jour-module`
"""
data = {
"Billing": {
"Address": {
"FirstName": self.first_name,
"LastName": self.last_name,
"Address1": self.address_1,
"ZipCode": self.zip_code,
"City": self.city,
"CountryCode": self.country,
}
}
}
if self.address_2:
data["Billing"]["Address"]["Address2"] = self.address_2
return dict2xml(data)
def __str__(self):
return f"{self.first_name} {self.last_name}"
class ProductType(models.Model):
"""
This describes a product type