145 lines
5.1 KiB
Python
145 lines
5.1 KiB
Python
from django.db import models
|
|
from django.db.models import Max
|
|
|
|
from vbv_lernwelt.core.models import Country
|
|
|
|
|
|
class Product(models.Model):
|
|
sku = models.CharField(max_length=255, primary_key=True)
|
|
price = models.IntegerField() # 10_00 = 10.00 CHF
|
|
name = models.CharField(max_length=255)
|
|
description = models.CharField(max_length=255)
|
|
|
|
|
|
class CheckoutState(models.TextChoices):
|
|
"""
|
|
The state of a checkout process transaction.
|
|
|
|
PAID: Datatrans transaction settled/transmitted.
|
|
ONGOING: Any state that is not final (e.g. initialized, challenge_ongoing, etc.)
|
|
|
|
1) We use the `autoSettle` feature of DataTrans!
|
|
-> https://docs.datatrans.ch/docs/after-the-payment
|
|
-> https://api-reference.datatrans.ch/#tag/v1transactions/operation/status
|
|
|
|
2) Difference between `settled` and `transmitted`:
|
|
- https://www.datatrans.ch/en/know-how/faq/#what-does-the-status-transaction-settled-or-settledtransmitted-mean
|
|
|
|
3) Related code: init_transaction and get_transaction_state in shop/services.py
|
|
"""
|
|
|
|
ONGOING = "ongoing"
|
|
PAID = "paid"
|
|
CANCELED = "canceled"
|
|
FAILED = "failed"
|
|
|
|
|
|
class CheckoutInformation(models.Model):
|
|
INVOICE_ADDRESS_PRIVATE = "prv"
|
|
INVOICE_ADDRESS_ORGANISATION = "org"
|
|
|
|
INVOICE_ADDRESS_CHOICES = (
|
|
(INVOICE_ADDRESS_PRIVATE, "Private"),
|
|
(INVOICE_ADDRESS_ORGANISATION, "Organisation"),
|
|
)
|
|
|
|
user = models.ForeignKey("core.User", on_delete=models.PROTECT)
|
|
|
|
product_sku = models.CharField(max_length=255)
|
|
product_name = models.CharField(max_length=255)
|
|
product_description = models.CharField(max_length=255)
|
|
product_price = models.IntegerField(
|
|
help_text="The total price of the product in centimes -> 1000 = 10.00 CHF"
|
|
)
|
|
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
updated_at = models.DateTimeField(auto_now=True)
|
|
|
|
state = models.CharField(
|
|
max_length=50,
|
|
choices=CheckoutState.choices,
|
|
)
|
|
|
|
invoice_transmitted_at = models.DateTimeField(blank=True, null=True)
|
|
transaction_id = models.CharField(max_length=255)
|
|
refno2 = models.CharField(max_length=255)
|
|
|
|
# end user (required)
|
|
first_name = models.CharField(max_length=255)
|
|
last_name = models.CharField(max_length=255)
|
|
street = models.CharField(max_length=255)
|
|
street_number = models.CharField(max_length=255)
|
|
postal_code = models.CharField(max_length=255)
|
|
city = models.CharField(max_length=255)
|
|
country = models.ForeignKey(
|
|
Country,
|
|
related_name="+",
|
|
on_delete=models.SET_NULL,
|
|
null=True,
|
|
blank=True,
|
|
)
|
|
|
|
# optional fields for cembra payment
|
|
cembra_byjuno_invoice = models.BooleanField(default=False)
|
|
birth_date = models.DateField(null=True, blank=True)
|
|
phone_number = models.CharField(max_length=255, blank=True, default="")
|
|
email = models.CharField(max_length=255, blank=True, default="")
|
|
device_fingerprint_session_key = models.CharField(
|
|
max_length=255, blank=True, default=""
|
|
)
|
|
ip_address = models.CharField(max_length=255, blank=True, default="")
|
|
|
|
invoice_address = models.CharField(
|
|
max_length=3, choices=INVOICE_ADDRESS_CHOICES, default="prv"
|
|
)
|
|
|
|
# organisation data (optional)
|
|
organisation_detail_name = models.CharField(max_length=255, blank=True)
|
|
organisation_street = models.CharField(max_length=255, blank=True)
|
|
organisation_street_number = models.CharField(max_length=255, blank=True)
|
|
organisation_postal_code = models.CharField(max_length=255, blank=True)
|
|
organisation_city = models.CharField(max_length=255, blank=True)
|
|
organisation_country = models.ForeignKey(
|
|
Country,
|
|
related_name="+",
|
|
on_delete=models.SET_NULL,
|
|
null=True,
|
|
blank=True,
|
|
)
|
|
chosen_profile = models.ForeignKey(
|
|
"learnpath.CourseProfile", on_delete=models.SET_NULL, null=True, blank=True
|
|
)
|
|
# webhook metadata
|
|
webhook_history = models.JSONField(default=list)
|
|
|
|
# is only set by abacus invoice export code
|
|
abacus_order_id = models.BigIntegerField(unique=True, null=True, blank=True)
|
|
abacus_ssh_upload_done = models.BooleanField(default=False)
|
|
|
|
def set_increment_abacus_order_id(self):
|
|
if self.abacus_order_id:
|
|
return self
|
|
|
|
# Get the current maximum abacus_order_id and increment it by 1
|
|
current_max = CheckoutInformation.objects.aggregate(
|
|
max_number=Max("abacus_order_id")
|
|
)["max_number"]
|
|
new_abacus_order_id = (
|
|
current_max if current_max is not None else 6_000_000_000
|
|
) + 1
|
|
self.abacus_order_id = new_abacus_order_id
|
|
self.save()
|
|
return self
|
|
|
|
def abacus_address_type(self) -> str:
|
|
# always use priv for abacus and CembraPay
|
|
return (
|
|
self.INVOICE_ADDRESS_ORGANISATION
|
|
if self.invoice_address == self.INVOICE_ADDRESS_ORGANISATION
|
|
and not self.cembra_byjuno_invoice
|
|
else self.INVOICE_ADDRESS_PRIVATE
|
|
)
|
|
|
|
def abacus_use_organisation_data(self) -> bool:
|
|
return self.abacus_address_type() == self.INVOICE_ADDRESS_ORGANISATION
|