# python from decimal import Decimal # django from django.db import transaction # rest framework from rest_framework import serializers # accounts from core.apps.accounts.models import User # counterparty from core.apps.counterparty.models import Counterparty from core.apps.counterparty.serializers.counterparty import CounterpartySerializer # finance from core.apps.finance.models import Expence # orders from core.apps.orders.models import DeletedParty, Order, Party, PartyAmount from core.apps.orders.serializers.order import ( MultipleOrderAddSerializer, OrderListSerializer, ) # products from core.apps.products.models import Product, Unity # projects from core.apps.projects.models import Project, ProjectFolder # shared from core.apps.shared.models import UsdCourse # wherehouse from core.apps.wherehouse.models import WhereHouse class PartyCreateSerializer(serializers.Serializer): resources = MultipleOrderAddSerializer(many=True) mediator_id = serializers.UUIDField() delivery_date = serializers.DateField() payment_date = serializers.DateField() comment = serializers.CharField(required=False) discount = serializers.DecimalField(max_digits=15, decimal_places=2, default=0.00, required=False) discount_currency = serializers.ChoiceField( choices=[("uzs", "uzs"), ("usd", "usd")], required=False ) audit = serializers.ChoiceField( choices=[("CHECKED", "tekshirildi"), ("PROCESS", "jarayonda")], required=False ) audit_comment = serializers.CharField(required=False) currency = serializers.ChoiceField(choices=[("uzs", "uzs"), ("usd", "usd")]) def validate(self, data): user = User.objects.filter(id=data["mediator_id"]).first() if not user: raise serializers.ValidationError("User not found") data["user"] = user return data def create(self, validated_data): with transaction.atomic(): resources = validated_data.pop("resources") orders = [] total_price = 0 for resource in resources: orders.append( Order( product=resource["product"], unity=resource["unity"], project_folder=resource.get("project_folder"), project=resource.get("project"), counterparty=resource.get("counterparty"), wherehouse=resource.get("wherehouse"), quantity=resource.get("quantity"), unit_amount=resource.get("unit_amount"), currency=resource.get("currency"), amount=resource.get("amount"), employee=self.context.get("user"), qqs_price=resource.get("qqs_price"), total_price=resource.get("total_price"), qqs=resource.get("qqs"), type="party" ) ) if resource.get("currency") == "usd": usd_value = UsdCourse.objects.first().value total_price += resource.get("amount") * usd_value else: total_price += resource.get("amount") created_orders = Order.objects.bulk_create(orders) party = Party.objects.create( mediator=validated_data.get("user"), delivery_date=validated_data.get("delivery_date"), payment_date=validated_data.get("payment_date"), comment=validated_data.get("comment"), audit=validated_data.get("audit"), audit_comment=validated_data.get("audit_comment"), discount=validated_data.get("discount"), discount_currency=validated_data.get("discount_currency"), currency=validated_data.get("currency"), ) party.orders.add(*created_orders) party.save() PartyAmount.objects.create( total_price=Decimal(total_price), party=party, payment_amount=Decimal(total_price) - Decimal(validated_data.get("discount", 0)), cost_amount=Decimal(total_price) - Decimal(validated_data.get("discount", 0)), ) return party class PartyAmountSerializer(serializers.ModelSerializer): class Meta: model = PartyAmount fields = [ "id", "total_price", "cost_amount", "calculated_amount", "paid_amount", "payment_amount", "debt_amount", "total_expense_amount", "overdue_amount" ] class PartyDetailSerializer(serializers.ModelSerializer): orders = OrderListSerializer(many=True) party_amount = PartyAmountSerializer() mediator = serializers.SerializerMethodField(method_name="get_mediator") counterparty = serializers.SerializerMethodField(method_name="get_counterparty") class Meta: model = Party fields = [ "id", "number", "delivery_date", "closed_date", "order_date", "payment_date", "status", "payment_status", "payment_percentage", "process", "confirmation", "comment", "audit", "audit_comment", "orders", "party_amount", "mediator", "currency", "counterparty", "discount", ] def get_mediator(self, obj): return {"id": obj.mediator.id, "full_name": obj.mediator.full_name} def get_counterparty(self, obj): counterparties = obj.orders.values( "counterparty__id", "counterparty__name" ).distinct() counterparties = [ {"id": c["counterparty__id"], "name": c["counterparty__name"]} for c in counterparties ] return CounterpartySerializer(counterparties, many=True).data class PartyListSerializer(serializers.ModelSerializer): party_amount = PartyAmountSerializer() mediator = serializers.SerializerMethodField(method_name="get_mediator") counterparty = serializers.SerializerMethodField(method_name="get_counterparty") class Meta: model = Party fields = [ "id", "number", "delivery_date", "closed_date", "order_date", "payment_date", "status", "payment_status", "payment_percentage", "process", "confirmation", "comment", "audit", "audit_comment", "party_amount", "mediator", "counterparty", "currency", "discount", ] def get_mediator(self, obj): return {"id": obj.mediator.id, "full_name": obj.mediator.full_name} def get_counterparty(self, obj): counterparties = obj.orders.values( "counterparty__id", "counterparty__name" ).distinct() counterparties = [ {"id": c["counterparty__id"], "name": c["counterparty__name"]} for c in counterparties ] return CounterpartySerializer(counterparties, many=True).data class DeletedPartyCreateSerializer(serializers.Serializer): comment = serializers.CharField(required=False) def validate(self, data): party = Party.objects.filter(id=self.context.get("party_id")).first() if not party: raise serializers.ValidationError("Party not found") data["party"] = party return data def create(self, validated_data): with transaction.atomic(): return DeletedParty.objects.create( comment=validated_data.get("comment"), party=validated_data.get("party"), user=self.context.get('user') ) class DeletedPartyListSerializer(serializers.ModelSerializer): party_number = serializers.IntegerField(source="party.number") party_total_price = serializers.IntegerField( source="party.party_amount.total_price" ) mediator = serializers.SerializerMethodField(method_name="get_mediator") party = PartyListSerializer() class Meta: model = DeletedParty fields = [ "id", "deleted_date", "party_number", "party_total_price", "mediator", 'created_at', 'comment', 'party', 'user', ] def get_user(self, obj): return { "id": obj.user.id, "full_name": obj.user.full_name, "profile_image": obj.user.profile_image.url or None, } if obj.user else {} def get_mediator(self, obj): return {"id": obj.party.mediator.id, "name": obj.party.mediator.full_name} class PartyOrderUpdateSerializer(serializers.Serializer): order_id = serializers.UUIDField() product_id = serializers.UUIDField() unity_id = serializers.UUIDField() project_folder_id = serializers.UUIDField(required=False) project_id = serializers.UUIDField(required=False) wherehouse_id = serializers.UUIDField() counterparty_id = serializers.UUIDField() quantity = serializers.IntegerField() unit_amount = serializers.DecimalField(max_digits=15, decimal_places=2, default=0.00) currency = serializers.ChoiceField(choices=[("uzs", "uzs"), ("usd", "usd")]) total_price = serializers.DecimalField(max_digits=15, decimal_places=2, default=0.00) def validate(self, data): order = Order.objects.filter(id=data["order_id"]).first() if not order: raise serializers.ValidationError("Order not found") product = Product.objects.filter(id=data["product_id"]).first() if not product: raise serializers.ValidationError(f"Product not found on {order.id}") unity = Unity.objects.filter(id=data["unity_id"]).first() if not unity: raise serializers.ValidationError(f"Unity not found on {order.id}") if data.get("project_folder_id"): project_folder = ProjectFolder.objects.filter( id=data["project_folder_id"] ).first() if not project_folder: raise serializers.ValidationError( f"Project Folder not found on {order.id}" ) data["project_folder"] = project_folder if data.get("project_id"): project = Project.objects.filter(id=data["project_id"]).first() if not project: raise serializers.ValidationError(f"Project not found on {order.id}") data["project"] = project wherehouse = WhereHouse.objects.filter(id=data["wherehouse_id"]).first() if not wherehouse: raise serializers.ValidationError(f"WhereHouse not found on {order.id}") counterparty = Counterparty.objects.filter(id=data["counterparty_id"]).first() if not counterparty: raise serializers.ValidationError(f"Counterparty not found on {order.id}") data["order"] = order data["product"] = product data["unity"] = unity data["wherehouse"] = wherehouse data["counterparty"] = counterparty return data class PartyUpdateSerializer(serializers.ModelSerializer): orders = PartyOrderUpdateSerializer(many=True, required=False) class Meta: model = Party fields = [ "mediator", "delivery_date", "payment_date", "orders", "comment", "audit", "audit_comment", "discount", "discount_currency", ] extra_kwargs = { "mediator": {"required": False}, "delivery_date": {"required": False}, "payment_date": {"required": False}, "comment": {"required": False}, "audit": {"required": False}, "audit_comment": {"required": False}, "discount": {"required": False}, "discount_currency": {"required": False}, } def update(self, instance, validated_data): total_price = 0 orders_data = validated_data.pop("orders") update_orders = [] with transaction.atomic(): instance.mediator = validated_data.get("mediator", instance.mediator) instance.delivery_date = validated_data.get( "delivery_date", instance.delivery_date ) instance.payment_date = validated_data.get( "payment_date", instance.payment_date ) instance.save() for order_data in orders_data: order = order_data["order"] order.product = order_data["product"] order.unity = order_data["unity"] order.wherehouse = order_data["wherehouse"] order.counterparty = order_data["counterparty"] order.quantity = order_data["quantity"] order.currency = order_data["currency"] order.unit_amount = order_data["unit_amount"] order.total_price = order_data["total_price"] total_price += order.total_price if "project_folder" in order_data: order.project_folder = order_data["project_folder"] if "project" in order_data: order.project = order_data["project"] update_orders.append(order) Order.objects.bulk_update( update_orders, fields=[ "product", "unity", "wherehouse", "counterparty", "quantity", "unit_amount", "currency", "total_price", "project_folder", "project", ], ) party_amount = PartyAmount.objects.get(party=instance) party_amount.total_price = total_price party_amount.cost_amount = ( total_price - instance.discount if instance.discount else 0.00 ) party_amount.payment_amount = ( total_price - instance.discount if instance.discount else 0.00 ) party_amount.save() return instance class PartyExpenceCreateSerializer(serializers.ModelSerializer): class Meta: model = Expence fields = [ "cash_transaction", "payment_type", "project_folder", "project", "counterparty", "price", "exchange_rate", "currency", "date", "comment", "party", ] def validate(self, data): price = data.get('price') exchange_rate = data.get('exchange_rate') party = data.get('party') currency = data.get('currency', 'uzs').lower() if price and price < 0: raise serializers.ValidationError("Narxi manfiy bo'lishi mumkin emas") if exchange_rate and exchange_rate < 0: raise serializers.ValidationError("Kurs manfiy bo'lishi mumkin emas") if not party: raise serializers.ValidationError("Party talab qilinadi") try: usd_course = UsdCourse.objects.first() if not usd_course or not usd_course.value: raise serializers.ValidationError("USD kursi topilmadi") except UsdCourse.DoesNotExist: raise serializers.ValidationError("USD kursi topilmadi") return data def create(self, validated_data): with transaction.atomic(): usd_course = UsdCourse.objects.first() if not usd_course: raise serializers.ValidationError("USD kursi topilmadi") usd_value = usd_course.value exchange_rate = validated_data.get("exchange_rate") or 1 final_price = validated_data.get("price") currency = validated_data.get("currency", "uzs").lower() expence = Expence.objects.create( cash_transaction=validated_data.get("cash_transaction"), payment_type=validated_data.get("payment_type"), project_folder=validated_data.get("project_folder"), project=validated_data.get("project"), counterparty=validated_data.get("counterparty"), price=final_price, exchange_rate=exchange_rate, currency=currency, date=validated_data.get("date"), comment=validated_data.get("comment"), party=validated_data.get("party"), user=self.context.get('user'), ) cash_transaction = expence.cash_transaction payment_type = expence.payment_type party = expence.party if currency == "uzs": cash_transaction.expence_balance_uzs += expence.price cash_transaction.total_balance_uzs = ( cash_transaction.income_balance_uzs - cash_transaction.expence_balance_uzs ) if payment_type.total_uzs > expence.price: payment_type.total_uzs -= expence.price if expence.counterparty: if expence.counterparty.kredit_uzs > 0: expence.counterparty.kredit_uzs -= expence.price expence.counterparty.total_kredit -= expence.price expence.counterparty.debit_uzs += expence.price expence.counterparty.total_debit += expence.price else: expence.counterparty.debit_uzs += expence.price expence.counterparty.total_debit += expence.price expence.counterparty.save() if party: if party.currency == "uzs": party.party_amount.payment_amount -= expence.price party.party_amount.paid_amount += expence.price party.party_amount.save() elif party.currency == 'usd': converted_price = round(expence.price / usd_value) party.party_amount.payment_amount -= converted_price party.party_amount.paid_amount += converted_price party.party_amount.save() party.save() elif currency == "usd": cash_transaction.expence_balance_usd += expence.price cash_transaction.total_balance_usd = ( cash_transaction.income_balance_usd - cash_transaction.expence_balance_usd ) if payment_type.total_usd > expence.price: payment_type.total_usd -= expence.price if expence.counterparty: if expence.counterparty.kredit_usd > 0: expence.counterparty.kredit_usd -= expence.price expence.counterparty.total_kredit -= expence.price expence.counterparty.debit_usd += expence.price expence.counterparty.total_debit += expence.price else: expence.counterparty.debit_usd += expence.price expence.counterparty.total_debit += expence.price expence.counterparty.save() if party: if party.currency == "usd": party.party_amount.payment_amount -= expence.price party.party_amount.paid_amount += expence.price party.party_amount.save() elif party.currency == "uzs": converted_price = expence.price * usd_value party.party_amount.payment_amount -= converted_price party.party_amount.paid_amount += converted_price party.party_amount.save() party.save() cash_transaction.save() payment_type.save() return expence class ReceivePartySerializer(serializers.Serializer): order_id = serializers.UUIDField() product_quantity = serializers.IntegerField() product_receive_date = serializers.DateField() class ReceiveMultipleOrderSerializer(serializers.Serializer): product = ReceivePartySerializer(many=True)