Refactor commerce models and enhance payment logic
Refactored commerce models to remove language prefixes from status choices, improved order and payment validation, and enforced business rules for payment and shipping combinations. Updated order item and cart calculations to use VAT-inclusive prices, added unique constraints and indexes to reviews, and improved stock management logic. Added new Stripe client methods for session and refund management, and updated Zasilkovna and Deutsche Post models for consistency. Minor fixes and improvements across related tasks, URLs, and configuration models.
This commit is contained in:
20
backend/thirdparty/deutschepost/models.py
vendored
20
backend/thirdparty/deutschepost/models.py
vendored
@@ -42,12 +42,12 @@ class DeutschePostOrder(models.Model):
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class STATE(models.TextChoices):
|
||||
CREATED = "CREATED", "cz#Vytvořeno"
|
||||
FINALIZED = "FINALIZED", "cz#Dokončeno"
|
||||
SHIPPED = "SHIPPED", "cz#Odesláno"
|
||||
DELIVERED = "DELIVERED", "cz#Doručeno"
|
||||
CANCELLED = "CANCELLED", "cz#Zrušeno"
|
||||
ERROR = "ERROR", "cz#Chyba"
|
||||
CREATED = "CREATED", "Vytvořeno"
|
||||
FINALIZED = "FINALIZED", "Dokončeno"
|
||||
SHIPPED = "SHIPPED", "Odesláno"
|
||||
DELIVERED = "DELIVERED", "Doručeno"
|
||||
CANCELLED = "CANCELLED", "Zrušeno"
|
||||
ERROR = "ERROR", "Chyba"
|
||||
|
||||
state = models.CharField(max_length=20, choices=STATE.choices, default=STATE.CREATED)
|
||||
|
||||
@@ -280,10 +280,10 @@ class DeutschePostBulkOrder(models.Model):
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class STATUS(models.TextChoices):
|
||||
CREATED = "CREATED", "cz#Vytvořeno"
|
||||
PROCESSING = "PROCESSING", "cz#Zpracovává se"
|
||||
COMPLETED = "COMPLETED", "cz#Dokončeno"
|
||||
ERROR = "ERROR", "cz#Chyba"
|
||||
CREATED = "CREATED", "Vytvořeno"
|
||||
PROCESSING = "PROCESSING", "Zpracovává se"
|
||||
COMPLETED = "COMPLETED", "Dokončeno"
|
||||
ERROR = "ERROR", "Chyba"
|
||||
|
||||
status = models.CharField(max_length=20, choices=STATUS.choices, default=STATUS.CREATED)
|
||||
|
||||
|
||||
126
backend/thirdparty/stripe/client.py
vendored
126
backend/thirdparty/stripe/client.py
vendored
@@ -10,6 +10,7 @@ stripe.api_key = os.getenv("STRIPE_SECRET_KEY")
|
||||
|
||||
class StripeClient:
|
||||
|
||||
@staticmethod
|
||||
def create_checkout_session(order):
|
||||
"""
|
||||
Vytvoří Stripe Checkout Session pro danou objednávku.
|
||||
@@ -42,8 +43,64 @@ class StripeClient:
|
||||
|
||||
return session
|
||||
|
||||
@staticmethod
|
||||
def cancel_checkout_session(session_id):
|
||||
"""
|
||||
Zruší Stripe Checkout Session.
|
||||
Args:
|
||||
session_id (str): ID Stripe Checkout Session k zrušení.
|
||||
|
||||
Returns:
|
||||
stripe.checkout.Session: Zrušená Stripe Checkout Session.
|
||||
"""
|
||||
try:
|
||||
session = stripe.checkout.Session.expire(session_id)
|
||||
return session
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
@staticmethod
|
||||
def get_checkout_session(session_id):
|
||||
"""
|
||||
Získá informace o Stripe Checkout Session.
|
||||
Args:
|
||||
session_id (str): ID Stripe Checkout Session.
|
||||
|
||||
Returns:
|
||||
stripe.checkout.Session: Stripe Checkout Session objekt.
|
||||
"""
|
||||
try:
|
||||
session = stripe.checkout.Session.retrieve(session_id)
|
||||
return session
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
@staticmethod
|
||||
def get_payment_intent(payment_intent_id):
|
||||
"""
|
||||
Získá informace o Stripe Payment Intent.
|
||||
Args:
|
||||
payment_intent_id (str): ID Stripe Payment Intent.
|
||||
|
||||
Returns:
|
||||
stripe.PaymentIntent: Stripe Payment Intent objekt.
|
||||
"""
|
||||
try:
|
||||
payment_intent = stripe.PaymentIntent.retrieve(payment_intent_id)
|
||||
return payment_intent
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
@staticmethod
|
||||
def refund_order(stripe_payment_intent):
|
||||
"""
|
||||
Vrátí platbu pro danou objednávku.
|
||||
Args:
|
||||
stripe_payment_intent (str): ID Stripe Payment Intent k vrácení.
|
||||
|
||||
Returns:
|
||||
stripe.Refund: Vytvořený refund objekt nebo chyba.
|
||||
"""
|
||||
try:
|
||||
refund = stripe.Refund.create(
|
||||
payment_intent=stripe_payment_intent
|
||||
@@ -51,4 +108,71 @@ class StripeClient:
|
||||
return refund
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps({"error": str(e)})
|
||||
return {"error": str(e)}
|
||||
|
||||
@staticmethod
|
||||
def partial_refund_order(stripe_payment_intent, amount):
|
||||
"""
|
||||
Částečně vrátí platbu pro danou objednávku.
|
||||
Args:
|
||||
stripe_payment_intent (str): ID Stripe Payment Intent k vrácení.
|
||||
amount (int): Částka k vrácení v haléřích.
|
||||
|
||||
Returns:
|
||||
stripe.Refund: Vytvořený refund objekt nebo chyba.
|
||||
"""
|
||||
try:
|
||||
refund = stripe.Refund.create(
|
||||
payment_intent=stripe_payment_intent,
|
||||
amount=amount
|
||||
)
|
||||
return refund
|
||||
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
@staticmethod
|
||||
def create_customer(email, name=None, phone=None):
|
||||
"""
|
||||
Vytvoří Stripe Customer.
|
||||
Args:
|
||||
email (str): Email zákazníka.
|
||||
name (str, optional): Jméno zákazníka.
|
||||
phone (str, optional): Telefon zákazníka.
|
||||
|
||||
Returns:
|
||||
stripe.Customer: Vytvořený Stripe Customer.
|
||||
"""
|
||||
try:
|
||||
customer_data = {"email": email}
|
||||
if name:
|
||||
customer_data["name"] = name
|
||||
if phone:
|
||||
customer_data["phone"] = phone
|
||||
|
||||
customer = stripe.Customer.create(**customer_data)
|
||||
return customer
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
@staticmethod
|
||||
def webhook_verify_signature(payload, sig_header, endpoint_secret):
|
||||
"""
|
||||
Ověří webhook signature od Stripe.
|
||||
Args:
|
||||
payload: Raw webhook payload.
|
||||
sig_header: Stripe signature header.
|
||||
endpoint_secret: Webhook endpoint secret.
|
||||
|
||||
Returns:
|
||||
stripe.Event: Ověřený event objekt.
|
||||
"""
|
||||
try:
|
||||
event = stripe.Webhook.construct_event(
|
||||
payload, sig_header, endpoint_secret
|
||||
)
|
||||
return event
|
||||
except ValueError as e:
|
||||
return {"error": "Invalid payload"}
|
||||
except stripe.error.SignatureVerificationError as e:
|
||||
return {"error": "Invalid signature"}
|
||||
19
backend/thirdparty/stripe/models.py
vendored
19
backend/thirdparty/stripe/models.py
vendored
@@ -1,5 +1,6 @@
|
||||
from django.db import models
|
||||
from django.apps import apps
|
||||
from django.utils import timezone
|
||||
|
||||
# Create your models here.
|
||||
|
||||
@@ -29,23 +30,25 @@ class StripeModel(models.Model):
|
||||
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
#if new
|
||||
if self.pk:
|
||||
# If new (no primary key yet)
|
||||
if self.pk is None:
|
||||
super().save(*args, **kwargs) # Save first to get pk
|
||||
|
||||
Order = apps.get_model('commerce', 'Order')
|
||||
Payment = apps.get_model('commerce', 'Payment')
|
||||
|
||||
order = Order.objects.get(payment=Payment.objects.get(stripe=self))
|
||||
|
||||
session = StripeClient.create_checkout_session(order)# <-- předáme self.StripePayment
|
||||
session = StripeClient.create_checkout_session(order)
|
||||
|
||||
self.stripe_session_id = session.id
|
||||
self.stripe_payment_intent = session.payment_intent
|
||||
self.stripe_session_url = session.url
|
||||
|
||||
|
||||
# Save again with Stripe data
|
||||
super().save(update_fields=['stripe_session_id', 'stripe_payment_intent', 'stripe_session_url', 'updated_at'])
|
||||
else:
|
||||
self.updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
super().save(*args, **kwargs)
|
||||
self.updated_at = timezone.now()
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def paid(self):
|
||||
self.status = self.STATUS_CHOICES.PAID
|
||||
|
||||
5
backend/thirdparty/zasilkovna/client.py
vendored
5
backend/thirdparty/zasilkovna/client.py
vendored
@@ -3,7 +3,7 @@ from zeep.exceptions import Fault
|
||||
from zeep.transports import Transport
|
||||
from zeep.cache import SqliteCache
|
||||
|
||||
from configuration.models import Configuration
|
||||
from configuration.models import SiteConfiguration
|
||||
|
||||
import tempfile
|
||||
import base64
|
||||
@@ -17,9 +17,6 @@ logger = logging.getLogger(__name__)
|
||||
WSDL_URL = os.getenv("PACKETA_WSDL_URL", "https://www.zasilkovna.cz/api/soap.wsdl")
|
||||
PACKETA_API_PASSWORD = os.getenv("PACKETA_API_PASSWORD")
|
||||
|
||||
Configuration.g
|
||||
|
||||
|
||||
|
||||
# --- 1. Singleton pro klienta (aby se WSDL stáhlo jen jednou pro celý proces) ---
|
||||
@lru_cache(maxsize=1)
|
||||
|
||||
14
backend/thirdparty/zasilkovna/models.py
vendored
14
backend/thirdparty/zasilkovna/models.py
vendored
@@ -35,14 +35,14 @@ class ZasilkovnaPacket(models.Model):
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class STATE(models.TextChoices):
|
||||
WAITING_FOR_ORDER = "WAITING_FOR_ORDERING_SHIPMENT", "cz#Čeká na objednání zásilkovny"
|
||||
PENDING = "PENDING", "cz#Podáno"
|
||||
SENDED = "SENDED", "cz#Odesláno"
|
||||
ARRIVED = "ARRIVED", "cz#Doručeno"
|
||||
CANCELED = "CANCELED", "cz#Zrušeno"
|
||||
WAITING_FOR_ORDER = "WAITING_FOR_ORDERING_SHIPMENT", "Čeká na objednání zásilkovny"
|
||||
PENDING = "PENDING", "Podáno"
|
||||
SENDED = "SENDED", "Odesláno"
|
||||
ARRIVED = "ARRIVED", "Doručeno"
|
||||
CANCELED = "CANCELED", "Zrušeno"
|
||||
|
||||
RETURNING = "RETURNING", "cz#Posláno zpátky"
|
||||
RETURNED = "RETURNED", "cz#Vráceno"
|
||||
RETURNING = "RETURNING", "Posláno zpátky"
|
||||
RETURNED = "RETURNED", "Vráceno"
|
||||
state = models.CharField(max_length=35, choices=STATE.choices, default=STATE.PENDING)
|
||||
|
||||
# ------- API -------
|
||||
|
||||
Reference in New Issue
Block a user