import logging from datetime import timedelta from django.db import IntegrityError from django.db.models.signals import post_save from django.dispatch import receiver from django.utils.crypto import get_random_string from django.utils.http import urlsafe_base64_decode from django.utils.timezone import now from django.utils.translation import gettext_lazy as _ from sentry_sdk import capture_exception from core.models import Category, Order, Product, PromoCode, Wishlist from core.utils import generate_human_readable_id, resolve_translations_for_elasticsearch from core.utils.emailing import send_order_created_email, send_order_finished_email from evibes.utils.misc import create_object from vibes_auth.models import User logger = logging.getLogger(__name__) @receiver(post_save, sender=User) def create_order_on_user_creation_signal(instance, created, **kwargs): if created: try: Order.objects.create(user=instance, status="PENDING") except IntegrityError: human_readable_id = generate_human_readable_id() while True: if Order.objects.filter(human_readable_id=human_readable_id).exists(): human_readable_id = generate_human_readable_id() continue Order.objects.create(user=instance, status="PENDING", human_readable_id=human_readable_id) break @receiver(post_save, sender=User) def create_wishlist_on_user_creation_signal(instance, created, **kwargs): if created: Wishlist.objects.create(user=instance) @receiver(post_save, sender=User) def create_promocode_on_user_referring(instance, created, **kwargs): try: if created and instance.attributes.get("referrer", ""): referrer_uuid = urlsafe_base64_decode(instance.attributes.get("referrer", "")) referrer = User.objects.get(uuid=referrer_uuid) code = f"WELCOME-{get_random_string(6)}" PromoCode.objects.create( user=referrer, code=code if len(code) <= 20 else code[:20], discount_percent=10, start_time=now(), end_time=now() + timedelta(days=30), ) except Exception as e: capture_exception(e) logger.error(_(f"error during promocode creation: {e!s}")) @receiver(post_save, sender=Order) def process_order_changes(instance, created, **kwargs): if not created: if instance.status != "PENDING" and instance.user: pending_orders = Order.objects.filter(user=instance.user, status="PENDING") if not pending_orders.exists(): try: Order.objects.create(user=instance.user, status="PENDING") except IntegrityError: human_readable_id = generate_human_readable_id() while True: if Order.objects.filter(human_readable_id=human_readable_id).exists(): human_readable_id = generate_human_readable_id() continue Order.objects.create(user=instance, status="PENDING", human_readable_id=human_readable_id) break if instance.status in ["CREATED", "PAYMENT"]: if not instance.is_whole_digital: send_order_created_email.delay(instance.uuid) for order_product in instance.order_products.filter(status="DELIVERING"): if not order_product.product.is_digital: continue try: vendor_name = ( order_product.product.stocks.filter(price=order_product.buy_price).first().vendor.name.lower() ) vendor = create_object(f"core.vendors.{vendor_name}", f"{vendor_name.title()}Vendor") vendor.buy_order_product(order_product) except Exception as e: order_product.add_error(f"Failed to buy {order_product.uuid}. Reason: {e}...") else: instance.finalize() if instance.order_products.filter(status="FAILED").count() == instance.order_products.count(): instance.status = "FAILED" instance.save() if instance.status == "FINISHED": send_order_finished_email.delay(instance.uuid) @receiver(post_save, sender=Product) def update_product_name_lang(instance, created, **kwargs): resolve_translations_for_elasticsearch(instance, "name") resolve_translations_for_elasticsearch(instance, "description") @receiver(post_save, sender=Category) def update_category_name_lang(instance, created, **kwargs): resolve_translations_for_elasticsearch(instance, "name") resolve_translations_for_elasticsearch(instance, "description")