from django.db import transaction from rest_framework import serializers from core.apps.orders.models import Party, PartyAmount, Order, DeletedParty from core.apps.orders.serializers.order import MultipleOrderAddSerializer, OrderListSerializer from core.apps.accounts.models import User from core.apps.counterparty.serializers.counterparty import CounterpartySerializer from core.apps.orders.tasks.order import create_inventory from core.apps.shared.models import UsdCourse from core.apps.products.models import Product, Unity from core.apps.projects.models import Project, ProjectFolder from core.apps.wherehouse.models import WhereHouse from core.apps.counterparty.models import Counterparty from core.apps.finance.models import Expence 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'), )) if validated_data.get('currency') == 'uzs': 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') class Meta: model = Party fields = [ 'id', 'number', 'delivery_date', 'closed_date', 'order_date', 'payment_date', 'status', 'payment_status', 'process', 'confirmation', 'comment', 'audit', 'audit_comment', 'orders', 'party_amount', 'mediator', 'currency' ] def get_mediator(self, obj): return { 'id': obj.mediator.id, 'full_name': obj.mediator.full_name } 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', 'process', 'confirmation', 'comment', 'audit', 'audit_comment', 'party_amount', 'mediator', 'counterparty', 'currency' ] 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): 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'] 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' ] ) 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(): 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'), ) 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.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() cash_transaction.save() payment_type.save() return expence