from django.db import transaction from rest_framework import serializers from core.apps.accounts.models import User from core.apps.counterparty.models import Counterparty from core.apps.counterparty.serializers.counterparty import CounterpartySerializer from core.apps.finance.models import Expence from core.apps.orders.models import DeletedParty, Order, Party, PartyAmount from core.apps.orders.serializers.order import ( MultipleOrderAddSerializer, OrderListSerializer, ) from core.apps.orders.tasks.order import create_inventory from core.apps.products.models import Product, Unity from core.apps.projects.models import Project, ProjectFolder from core.apps.shared.models import UsdCourse 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.IntegerField(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=total_price, party=party, payment_amount=total_price - validated_data.get("discount", 0), cost_amount=total_price - 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", ] 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") ) 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") class Meta: model = DeletedParty fields = ["id", "deleted_date", "party_number", "party_total_price", "mediator"] 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.IntegerField() currency = serializers.ChoiceField(choices=[("uzs", "uzs"), ("usd", "usd")]) total_price = serializers.IntegerField() 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 ) party_amount.payment_amount = ( total_price - instance.discount if instance.discount else 0 ) 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 create(self, validated_data): with transaction.atomic(): usd_value = UsdCourse.objects.first().value 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=( validated_data.get("price") * validated_data.get("exchange_rate") if validated_data.get("exchange_rate") else validated_data.get("price") ), exchange_rate=validated_data.get("exchange_rate"), currency=validated_data.get("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 if validated_data.get("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.counterparty.kredit_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 expence.party.currency == "uzs": expence.party.party_amount.payment_amount -= expence.price expence.party.party_amount.paid_amount += expence.price expence.party.party_amount.save() expence.party.save() elif expence.party.currency == 'usd': expence.party.party_amount.payment_amount -= round(expence.price / usd_value) expence.party.party_amount.paid_amount += round(expence.price / usd_value) expence.party.save() elif validated_data.get("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 -= validated_data.get("price") expence.counterparty.total_kredit -= expence.price expence.counterparty.debit_usd += ( expence.counterparty.kredit_usd - validated_data.get("price") ) expence.counterparty.total_debit += expence.price else: expence.counterparty.debit_usd += validated_data.get("price") expence.counterparty.total_debit += expence.price expence.counterparty.save() if expence.party.currency == "usd": expence.party.party_amount.payment_amount -= validated_data.get( "price" ) expence.party.party_amount.paid_amount += validated_data.get( "price" ) expence.party.save() elif expence.party.currency == "uzs": expence.party.party_amount.payment_amount -= validated_data.get( "price" ) * usd_value expence.party.party_amount.paid_amount += validated_data.get( "price" ) * usd_value expence.party.save() expence.party.party_amount.save() cash_transaction.save() payment_type.save() return expence class PartyPaymentHistorySerializer(serializers.ModelSerializer): counterparty = serializers.SerializerMethodField(method_name='get_counterparty') user = serializers.SerializerMethodField(method_name='get_user') class Meta: model = Expence fields = [ 'id', 'counterparty', 'price', 'created_at', 'date', 'user' ] def get_counterparty(self, obj): return { 'id': obj.counterparty.id, 'name': obj.counterparty.name, } if obj.counterparty else None def get_user(self, obj): return { 'id': obj.user.id, 'full_name': obj.user.full_name, 'profile_image': obj.user.profile_image.url if obj.user.profile_image else None } if obj.user else None