From 1ace97c233634ef39423e694ff62829e9ae9f466 Mon Sep 17 00:00:00 2001 From: Egor fureunoir Gorbunov Date: Sun, 6 Jul 2025 23:53:46 +0300 Subject: [PATCH] Features: 1) Add support for optional `billing_address_uuid` and `shipping_address_uuid` in `apply_addresses`; 2) Introduce `chosen_products` parameter in the `buy` method for customized order creation; Fixes: 1) Correct type annotations in `buy` and `bulk_add_products` methods for improved type safety; Extra: 1) Refactor `buy` method for enhanced readability and maintainability; 2) Update usage of `self` to `order` for clarity in dynamic order creation scenarios. --- core/models.py | 52 ++++++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/core/models.py b/core/models.py index 6fb736b4..6f6976d7 100644 --- a/core/models.py +++ b/core/models.py @@ -1532,7 +1532,7 @@ class Order(ExportModelOperationsMixin("order"), NiceModel): # type: ignore [mi raise Http404(_("promocode does not exist")) from dne return promocode.use(self) - def apply_addresses(self, billing_address_uuid, shipping_address_uuid): + def apply_addresses(self, billing_address_uuid: str | None = None, shipping_address_uuid: str | None = None): try: if not any([shipping_address_uuid, billing_address_uuid]): if self.is_whole_digital: @@ -1561,21 +1561,27 @@ class Order(ExportModelOperationsMixin("order"), NiceModel): # type: ignore [mi def buy( self, - force_balance=False, - force_payment=False, - promocode_uuid=None, - billing_address=None, - shipping_address=None, + force_balance: bool = False, + force_payment: bool = False, + promocode_uuid: str | None = None, + billing_address: str | None = None, + shipping_address: str | None = None, + chosen_products: list = None, ) -> Self | Transaction | None: + order = self + if chosen_products: + order = Order.objects.create(status="MOMENTAL", user=self.user) + order.bulk_add_products(chosen_products) + if config.DISABLED_COMMERCE: raise DisabledCommerceError(_("you can not buy at this moment, please try again in a few minutes")) if (not force_balance and not force_payment) or (force_balance and force_payment): raise ValueError(_("invalid force value")) - self.apply_addresses(billing_address, shipping_address) + order.apply_addresses(billing_address, shipping_address) - if self.total_quantity < 1: + if order.total_quantity < 1: raise ValueError(_("you cannot purchase an empty order!")) force = None @@ -1586,34 +1592,34 @@ class Order(ExportModelOperationsMixin("order"), NiceModel): # type: ignore [mi if force_payment: force = "payment" - amount = self.apply_promocode(promocode_uuid) if promocode_uuid else self.total_price + amount = order.apply_promocode(promocode_uuid) if promocode_uuid else order.total_price - if not self.user: + if not order.user: raise ValueError(_("you cannot buy an order without a user")) - if not self.user.payments_balance: + if not order.user.payments_balance: raise ValueError(_("a user without a balance cannot buy with balance")) match force: case "balance": - if self.user.payments_balance.amount < amount: + if order.user.payments_balance.amount < amount: raise NotEnoughMoneyError(_("insufficient funds to complete the order")) - self.status = "CREATED" - self.buy_time = timezone.now() - self.order_products.all().update(status="DELIVERING") - self.save() - return self + order.status = "CREATED" + order.buy_time = timezone.now() + order.order_products.all().update(status="DELIVERING") + order.save() + return order case "payment": - self.status = "PAYMENT" - self.save() + order.status = "PAYMENT" + order.save() return Transaction.objects.create( - balance=self.user.payments_balance, + balance=order.user.payments_balance, amount=amount, currency=CURRENCY_CODE, - order=self, + order=order, ) - return self + return order def buy_without_registration(self, products: list, promocode_uuid, **kwargs) -> Transaction | None: if config.DISABLED_COMMERCE: @@ -1689,7 +1695,7 @@ class Order(ExportModelOperationsMixin("order"), NiceModel): # type: ignore [mi self.status = "FINISHED" self.save() - def bulk_add_products(self, products: list): + def bulk_add_products(self, products: list[dict[str, Any]]): for product in products: self.add_product( product.get("uuid"),