from apps.herd.services.services import get_rancher_statistics, rancher_quota_weight from apps.product.services.services import ( quota_live_stock_allocation_info, quota_incentive_plans_info, quota_brokers_value, quota_attribute_value ) from apps.pos_device.services.services import pos_organizations_sharing_information from apps.pos_device.pos.api.v1.serializers.device import DeviceSerializer from apps.product.exceptions import DistributionWeightException from apps.pos_device.models import POSFreeProducts from apps.warehouse.services.services import ( create_extra_sale, create_pre_sale ) from apps.herd.pos.api.v1.serializers import RancherSerializer from apps.product.models import QuotaDistribution, Product from apps.warehouse import models as warehouse_models from apps.core.models import SystemConfig from django.db.transaction import atomic from apps.warehouse.exceptions import ( TotalInventorySaleException ) from rest_framework import serializers from apps.herd.models import Rancher from django.db import models class InventoryEntrySerializer(serializers.ModelSerializer): class Meta: model = warehouse_models.InventoryEntry fields = [ "id", "entry_identity", "create_date", "modify_date", "organization", "distribution", "weight", "balance", "lading_number", "delivery_address", "is_confirmed", "notes", ] def to_representation(self, instance): """ custom output of inventory entry serializer """ representation = super().to_representation(instance) if instance.document: representation['document'] = instance.document if instance.distribution: # distribution data representation['distribution'] = { 'distribution_identity': instance.distribution.distribution_id, 'sale_unit': instance.distribution.quota.sale_unit.unit, 'id': instance.distribution.id } representation['quota'] = { 'quota_identity': instance.distribution.quota.quota_id, 'quota_weight': instance.distribution.quota.quota_weight, 'quota_livestock_allocations': quota_live_stock_allocation_info( instance.distribution.quota ), 'quota_incentive_plans': quota_incentive_plans_info(instance.distribution.quota) } representation['product'] = { 'image': instance.distribution.quota.product.img, 'name': instance.distribution.quota.product.name, 'id': instance.distribution.quota.product.id, } representation['pricing'] = { 'pricing_attributes': quota_attribute_value(instance.distribution.quota), 'sharing': pos_organizations_sharing_information( self.context['device'], instance.distribution.quota, instance.distribution ), 'base_prices': [ { "text": "درب کارخانه", # noqa "name": "base_price_factory", "value": instance.distribution.quota.base_price_factory }, { "text": "درب اتحادیه", # noqa "name": "base_price_cooperative", "value": instance.distribution.quota.base_price_cooperative } ] } if 'rancher' in self.context.keys(): # rancher herd & live stock statistics representation['rancher_statistics'] = get_rancher_statistics(self.context['rancher']) # rancher live stock statistics by inventory entry representation['rancher_quota_weight_statistics'] = rancher_quota_weight( self.context['rancher'], instance ) return representation class InventoryQuotaSaleTransactionSerializer(serializers.ModelSerializer): rancher_national_code = serializers.CharField(max_length=50, required=False) class Meta: # noqa model = warehouse_models.InventoryQuotaSaleTransaction fields = '__all__' depth = 0 def create(self, validated_data): items_data = self.context['request'].data['items'] with atomic(): # get rancher with national code rancher = Rancher.objects.get(national_code=validated_data.pop('rancher_national_code')) validated_data.update({'rancher': rancher}) # if transaction exists, update transaction status transaction = self.Meta.model.objects.filter( transaction_id=validated_data.get('transaction_id') ) if transaction.exists(): obj = transaction.first() obj.transaction_status = validated_data.get('transaction_status') obj.save(update_fields=['transaction_status']) return obj # create transaction record transaction = warehouse_models.InventoryQuotaSaleTransaction.objects.create( **validated_data ) # calculate total price of product items in shopping cart total_price = 0 for item_data in items_data: # get product by type gov_product = item_data.pop('gov_product') if 'gov_product' in item_data.keys() else None free_product = item_data.pop('free_product') if 'free_product' in item_data.keys() else None item = warehouse_models.InventoryQuotaSaleItem.objects.create( transaction=transaction, quota_distribution=QuotaDistribution.objects.get( id=item_data.pop('quota_distribution') ), gov_product=Product.objects.get( id=gov_product ) if Product.objects.filter(id=gov_product).exists() else None, free_product=POSFreeProducts.objects.get( id=free_product ) if POSFreeProducts.objects.filter(id=free_product).exists() else None, **item_data ) total_price += item.total_price # create extra sale for distribution create_extra_sale(transaction=transaction, sale_item=item) # create pre sale for distribution create_pre_sale(transaction=transaction, sale_item=item) transaction.transaction_price = total_price transaction.save() return transaction def validate(self, attrs): """ validate total inventory sale should be fewer than distribution weight """ items = self.context['request'].data['items'] for item in items: if 'quota_distribution' in item.keys(): distribution = QuotaDistribution.objects.get(id=item.get('quota_distribution')) total_sale_weight = distribution.sale_items.aggregate( total=models.Sum('weight') )['total'] or 0 if total_sale_weight + item.get('weight') > distribution.weight: raise DistributionWeightException() return attrs def to_representation(self, instance): """ customize output of transactions serializer """ representation = super().to_representation(instance) if instance.rancher: representation['rancher'] = RancherSerializer(instance.rancher).data representation['pos_device'] = DeviceSerializer(instance.pos_device).data if instance.seller_organization: representation['seller_organization'] = instance.seller_organization.name # get product items of transaction representation['items'] = InventoryQuotaSaleItemSerializer(instance.items.all(), many=True).data return representation class InventoryQuotaSaleItemSerializer(serializers.ModelSerializer): product_name = serializers.CharField(source='product.name', read_only=True) class Meta: model = warehouse_models.InventoryQuotaSaleItem fields = [ 'id', "transaction", "gov_product", "free_product", "product_name", "image", "name", "price_type", "delivery_type", "paid_type", "weight", "unit_price", "total_price", "livestock_statistic", ] class QuotaPreSaleItemSerializer(serializers.ModelSerializer): class Meta: model = warehouse_models.QuotaPreSaleItem fields = '__all__' def create(self, validated_data): with atomic(): pass