Add "DISABLED_COMMERCE" feature to disable buying functionality

Introduce a global config flag `DISABLED_COMMERCE` to toggle buy functionality availability. Raise specific `DisabledCommerceError` when buying is disabled, ensuring end-users are informed. Additionally, reformat code for readability and consistency, improving overall maintainability.
This commit is contained in:
Egor Pavlovich Gorbunov 2025-05-05 17:32:57 +03:00
parent 96c3fe23b0
commit 85a49c4e8b
3 changed files with 92 additions and 69 deletions

View file

@ -1,5 +1,9 @@
from django.core.exceptions import BadRequest from django.core.exceptions import BadRequest, ImproperlyConfigured
class NotEnoughMoneyError(BadRequest): class NotEnoughMoneyError(BadRequest):
pass pass
class DisabledCommerceError(ImproperlyConfigured):
pass

View file

@ -39,7 +39,7 @@ from mptt.models import MPTTModel
from core.abstract import NiceModel from core.abstract import NiceModel
from core.choices import ORDER_PRODUCT_STATUS_CHOICES, ORDER_STATUS_CHOICES from core.choices import ORDER_PRODUCT_STATUS_CHOICES, ORDER_STATUS_CHOICES
from core.errors import NotEnoughMoneyError from core.errors import NotEnoughMoneyError, DisabledCommerceError
from core.utils import get_product_uuid_as_path, get_random_code from core.utils import get_product_uuid_as_path, get_random_code
from core.utils.lists import FAILED_STATUSES from core.utils.lists import FAILED_STATUSES
from core.validators import validate_category_image_dimensions from core.validators import validate_category_image_dimensions
@ -219,14 +219,16 @@ class Brand(NiceModel):
verbose_name=_("brand name"), verbose_name=_("brand name"),
unique=True, unique=True,
) )
small_logo = ImageField(upload_to="brands/", small_logo = ImageField(
upload_to="brands/",
blank=True, blank=True,
null=True, null=True,
help_text=_("upload a logo representing this brand"), help_text=_("upload a logo representing this brand"),
validators=[validate_category_image_dimensions], validators=[validate_category_image_dimensions],
verbose_name=_("brand small image"), verbose_name=_("brand small image"),
) )
big_logo = ImageField(upload_to="brands/", big_logo = ImageField(
upload_to="brands/",
blank=True, blank=True,
null=True, null=True,
help_text=_("upload a big logo representing this brand"), help_text=_("upload a big logo representing this brand"),
@ -330,7 +332,7 @@ class Product(NiceModel):
@rating.setter @rating.setter
def rating(self, value): def rating(self, value):
self.__dict__['rating'] = value self.__dict__["rating"] = value
@property @property
def feedbacks_count(self): def feedbacks_count(self):
@ -606,10 +608,11 @@ class Order(NiceModel):
raise Http404(_("promocode does not exist")) raise Http404(_("promocode does not exist"))
return promocode.use(self) return promocode.use(self)
def buy(self, def buy(
force_balance: bool = False, self, force_balance: bool = False, force_payment: bool = False, promocode_uuid: str | None = None
force_payment: bool = False, ) -> Self | Transaction | None:
promocode_uuid: str | None = None) -> Self | Transaction | None: 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): if (not force_balance and not force_payment) or (force_balance and force_payment):
raise ValueError(_("invalid force value")) raise ValueError(_("invalid force value"))
@ -647,8 +650,11 @@ class Order(NiceModel):
return self return self
def buy_without_registration(self, products: list, promocode_uuid: str, **kwargs) -> Transaction | None: def buy_without_registration(self, products: list, promocode_uuid: str, **kwargs) -> Transaction | None:
if config.DISABLED_COMMERCE:
raise DisabledCommerceError(_("you can not buy at this moment, please try again in a few minutes"))
if len(products) < 1: if len(products) < 1:
raise ValueError(_("you cannot purchase without registration an empty order!")) raise ValueError(_("you cannot purchase an empty order!"))
customer_name = kwargs.pop("customer_name") customer_name = kwargs.pop("customer_name")
customer_email = kwargs.pop("customer_email") customer_email = kwargs.pop("customer_email")
@ -656,8 +662,11 @@ class Order(NiceModel):
if not all([customer_name, customer_email, customer_phone_number]): if not all([customer_name, customer_email, customer_phone_number]):
raise ValueError( raise ValueError(
_("you cannot buy without registration, please provide the following information:" _(
" customer name, customer email, customer phone number")) "you cannot buy without registration, please provide the following information:"
" customer name, customer email, customer phone number"
)
)
payment_method = kwargs.get("payment_method") payment_method = kwargs.get("payment_method")
@ -670,17 +679,24 @@ class Order(NiceModel):
billing_customer_postal_code = billing_customer_address.pop("customer_postal_code") billing_customer_postal_code = billing_customer_address.pop("customer_postal_code")
billing_customer_address_line = billing_customer_address.pop("customer_address_line") billing_customer_address_line = billing_customer_address.pop("customer_address_line")
if not all([billing_customer_city, billing_customer_country, billing_customer_postal_code, if not all(
billing_customer_address_line]): [
billing_customer_city,
billing_customer_country,
billing_customer_postal_code,
billing_customer_address_line,
]
):
raise ValueError(_("you cannot create a momental order without providing a billing address")) raise ValueError(_("you cannot create a momental order without providing a billing address"))
billing_address = Address.objects.get_or_create(user=None, billing_address = Address.objects.get_or_create(
user=None,
country=Country.objects.get(code=billing_customer_country), country=Country.objects.get(code=billing_customer_country),
region=Region.objects.get(code=billing_customer_city), region=Region.objects.get(code=billing_customer_city),
city=City.objects.get(name=billing_customer_city), city=City.objects.get(name=billing_customer_city),
postal_code=PostalCode.objects.get( postal_code=PostalCode.objects.get(code=billing_customer_postal_code),
code=billing_customer_postal_code), street=billing_customer_address_line,
street=billing_customer_address_line) )
shipping_customer_address = kwargs.pop("shipping_customer_address") shipping_customer_address = kwargs.pop("shipping_customer_address")
shipping_customer_city = shipping_customer_address.pop("customer_city") shipping_customer_city = shipping_customer_address.pop("customer_city")
@ -692,14 +708,14 @@ class Order(NiceModel):
shipping_address = billing_address shipping_address = billing_address
else: else:
shipping_address = Address.objects.get_or_create(user=None, shipping_address = Address.objects.get_or_create(
country=Country.objects.get( user=None,
code=shipping_customer_country), country=Country.objects.get(code=shipping_customer_country),
region=Region.objects.get(code=shipping_customer_city), region=Region.objects.get(code=shipping_customer_city),
city=City.objects.get(name=billing_customer_city), city=City.objects.get(name=billing_customer_city),
postal_code=PostalCode.objects.get( postal_code=PostalCode.objects.get(code=shipping_customer_postal_code),
code=shipping_customer_postal_code), street=shipping_customer_address_line,
street=shipping_customer_address_line) )
for product_uuid in products: for product_uuid in products:
self.add_product(product_uuid) self.add_product(product_uuid)
@ -709,9 +725,13 @@ class Order(NiceModel):
self.status = "CREATED" self.status = "CREATED"
self.shipping_address = shipping_address self.shipping_address = shipping_address
self.billing_address = billing_address self.billing_address = billing_address
self.attributes.update({"customer_name": customer_name, self.attributes.update(
{
"customer_name": customer_name,
"customer_email": customer_email, "customer_email": customer_email,
"customer_phone_number": customer_phone_number}) "customer_phone_number": customer_phone_number,
}
)
self.save() self.save()
return Transaction.objects.create( return Transaction.objects.create(
@ -991,13 +1011,11 @@ class PromoCode(NiceModel):
match self.discount_type: match self.discount_type:
case "percent": case "percent":
amount -= round(amount * (self.discount_percent / 100), 2) amount -= round(amount * (self.discount_percent / 100), 2)
order.attributes.update({"promocode": str(self.uuid), order.attributes.update({"promocode": str(self.uuid), "final_price": amount})
"final_price": amount})
order.save() order.save()
case "amount": case "amount":
amount -= round(float(self.discount_amount), 2) amount -= round(float(self.discount_amount), 2)
order.attributes.update({"promocode": str(self.uuid), order.attributes.update({"promocode": str(self.uuid), "final_price": amount})
"final_price": amount})
order.save() order.save()
case _: case _:
raise ValueError(_(f"invalid discount type for promocode {self.uuid}")) raise ValueError(_(f"invalid discount type for promocode {self.uuid}"))

View file

@ -28,6 +28,7 @@ CONSTANCE_CONFIG = {
"Abstract API Key, if empty - no Abstract features provided", "Abstract API Key, if empty - no Abstract features provided",
), ),
"HTTP_PROXY": (getenv("DJANGO_HTTP_PROXY", "http://username:password@proxy_address:port"), "HTTP Proxy"), "HTTP_PROXY": (getenv("DJANGO_HTTP_PROXY", "http://username:password@proxy_address:port"), "HTTP Proxy"),
"DISABLED_COMMERCE": (getenv("DISABLED_COMMERCE", False), "Disable buy functionality"),
} }
EXPOSABLE_KEYS = [ EXPOSABLE_KEYS = [