import random import string from django.db import models from apps.authentication.models import User, Organization from apps.core.models import BaseModel from apps.herd.models import Rancher from apps.pos_device.models import Device from apps.pos_device.models import POSFreeProducts from apps.product import models as product_models class InventoryEntry(BaseModel): entry_identity = models.CharField(max_length=50, null=True) distribution = models.ForeignKey( product_models.QuotaDistribution, on_delete=models.CASCADE, related_name='inventory_entry', null=True ) quota = models.ForeignKey( product_models.Quota, on_delete=models.CASCADE, related_name='inventory_entry', null=True ) organization = models.ForeignKey( product_models.Organization, on_delete=models.CASCADE, related_name="inventory", null=True ) org_quota_stat = models.ForeignKey( product_models.OrganizationQuotaStats, on_delete=models.CASCADE, related_name='inventory_entry', null=True ) weight = models.PositiveBigIntegerField(default=0) balance = models.PositiveBigIntegerField(default=0) lading_number = models.CharField(max_length=50, null=True) delivery_address = models.TextField(blank=True, null=True) document = models.CharField(max_length=250, null=True) is_confirmed = models.BooleanField(default=False) notes = models.TextField(blank=True, null=True) def generate_entry_identity(self): # noqa """ generate identity for every device """ # prefix = "POS" while True: number_part = ''.join(random.choices(string.digits, k=6)) code = f"{self.quota.quota_id}{number_part}" if not InventoryEntry.objects.filter(entry_identity=code).exists(): return code @property def total_sold(self): return self.inventory_sales.aggregate(total=models.Sum('weight'))['total'] or 0 @property def remaining_weight(self): return self.weight - self.total_sold def __str__(self): return f"distribution: {self.distribution.distribution_id}-{self.organization.name}" def save(self, *args, **kwargs): if not self.entry_identity: self.entry_identity = self.generate_entry_identity() super(InventoryEntry, self).save(*args, **kwargs) class InventoryEntryAllocation(BaseModel): inventory_entry = models.ForeignKey( InventoryEntry, on_delete=models.CASCADE, related_name='allocations', null=True ) distribution = models.ForeignKey( product_models.QuotaDistribution, on_delete=models.CASCADE, related_name='allocations', null=True ) weight = models.PositiveBigIntegerField(default=0) def __str__(self): return f"{self.weight} -> Distribution {self.distribution.id}" class InventoryQuotaSaleTransaction(BaseModel): rancher = models.ForeignKey( Rancher, on_delete=models.CASCADE, related_name='transactions', null=True ) rancher_fullname = models.CharField(max_length=150, null=True, blank=True) rancher_mobile = models.CharField(max_length=25, null=True, blank=True) pos_device = models.ForeignKey( Device, on_delete=models.CASCADE, related_name='transactions', null=True ) transaction_id = models.CharField(max_length=50, null=True) seller_organization = models.ForeignKey( product_models.Organization, on_delete=models.CASCADE, related_name='inventory_sales', null=True ) quota_distribution = models.ForeignKey( product_models.QuotaDistribution, on_delete=models.CASCADE, related_name='inventory_sales', null=True ) inventory_entry = models.ForeignKey( InventoryEntry, on_delete=models.CASCADE, related_name='inventory_sales', null=True ) weight = models.PositiveBigIntegerField(default=0) delivery_address = models.TextField(blank=True, null=True) transaction_price = models.PositiveBigIntegerField(default=0) price_paid = models.PositiveBigIntegerField(default=0) type_of_price = ( ('card', 'CARD'), ('cash', 'CASH'), ('credit', 'CREDIT'), ('check', 'CHECK'), ) price_type = models.CharField(choices=type_of_price, max_length=50, null=True) description = models.TextField(blank=True, null=True) product_type_choices = ( ('gov', 'government'), ('free', 'free'), ) product_type = models.CharField(max_length=20, choices=product_type_choices, default='free') herd_owners_number = models.PositiveBigIntegerField(default=0) transactions_number = models.PositiveBigIntegerField(default=0) status_type = ( ('success', 'SUCCESS'), ('waiting', 'WAITING'), ('failed', 'Failed'), ) transaction_status = models.CharField(choices=status_type, max_length=25, null=True) transaction_status_code = models.IntegerField(default=0) result_text = models.TextField(null=True, blank=True) ref_num = models.CharField(max_length=50, null=True, blank=True) terminal = models.CharField(max_length=50, null=True, blank=True) payer_cart = models.CharField(max_length=50, null=True, blank=True) pos_date = models.PositiveBigIntegerField(default=0) transaction_date = models.DateTimeField(auto_now_add=True, null=True) free_sale_state = models.BooleanField(default=False) pre_sale_state = models.BooleanField(default=False) additional = models.JSONField(default=dict) @property def total_weight(self): """ summation of total sold product weight """ return sum(item.weight for item in self.items.all) # noqa def __str__(self): return f"Inventory Sale: {self.transaction_id}-{self.quota_distribution.distribution_id}" def save(self, *args, **kwargs): super(InventoryQuotaSaleTransaction, self).save(*args, **kwargs) class InventoryQuotaSaleItem(BaseModel): transaction = models.ForeignKey( InventoryQuotaSaleTransaction, on_delete=models.CASCADE, related_name='items', null=True ) quota_distribution = models.ForeignKey( product_models.QuotaDistribution, on_delete=models.CASCADE, related_name='sale_items', null=True ) quota_stat = models.ForeignKey( product_models.OrganizationQuotaStats, on_delete=models.CASCADE, related_name='sale_items', null=True ) gov_product = models.ForeignKey( product_models.Product, on_delete=models.CASCADE, related_name='sale_items', null=True ) free_product = models.ForeignKey( POSFreeProducts, on_delete=models.CASCADE, related_name='sale_items', null=True ) image = models.CharField(max_length=150, null=True) name = models.CharField(max_length=150, null=True) price_type = models.CharField(max_length=150, null=True) delivery_type = models.CharField(max_length=150, null=True) paid_type = models.CharField(max_length=150, null=True) item_type = models.CharField(max_length=150, null=True) unit = models.CharField(max_length=50, null=True) weight = models.PositiveBigIntegerField(default=0) unit_price = models.PositiveBigIntegerField(default=0) total_price = models.PositiveBigIntegerField(default=0) paid_price = models.PositiveBigIntegerField(default=0) is_extra = models.BooleanField(default=False) is_pre_sale = models.BooleanField(default=False) additional = models.JSONField(default=dict) livestock_statistic = models.JSONField(default=dict) item_share = models.JSONField(default=list) inventory_calculation = models.BooleanField(default=False) base_price = models.PositiveBigIntegerField(default=0) paid_tashim = models.PositiveBigIntegerField(default=0) @property def product(self): return self.gov_product or self.free_product def __str__(self): return f'Item {self.product} - {self.weight} Kg - {self.total_price}' def save(self, *args, **kwargs): return super(InventoryQuotaSaleItem, self).save(*args, **kwargs) class ExtraSale(BaseModel): organization = models.ForeignKey( Organization, on_delete=models.CASCADE, related_name='extra_sales', null=True ) distribution = models.ForeignKey( product_models.QuotaDistribution, on_delete=models.CASCADE, related_name='extra_sales', null=True ) transaction = models.ForeignKey( InventoryQuotaSaleTransaction, on_delete=models.CASCADE, related_name='transactions', null=True ) sale_item = models.ForeignKey( InventoryQuotaSaleItem, on_delete=models.CASCADE, related_name='sale_items', null=True ) weight = models.IntegerField(default=0) def __str__(self): return f'Extra Sale on {self.organization.name} - {self.distribution.distribution_id}' def save(self, *args, **kwargs): return super(ExtraSale, self).save(*args, **kwargs) class QuotaPreSaleItem(BaseModel): organization = models.ForeignKey( Organization, on_delete=models.CASCADE, related_name='pre_sales', null=True ) distribution = models.ForeignKey( product_models.QuotaDistribution, on_delete=models.CASCADE, related_name='pre_sales', null=True ) transaction = models.ForeignKey( InventoryQuotaSaleTransaction, on_delete=models.CASCADE, related_name='pre_sales', null=True ) sale_item = models.ForeignKey( InventoryQuotaSaleItem, on_delete=models.CASCADE, related_name='pre_sale', null=True ) weight = models.IntegerField(default=0) settlement_state = models.BooleanField(default=False) def __str__(self): return f'Distribution {self.distribution.distribution_id} - Transaction {self.transaction.transaction_id}' def save(self, *args, **kwargs): return super(QuotaPreSaleItem, self).save(*args, **kwargs)