Files
RasadDam_Backend/apps/warehouse/models.py

316 lines
10 KiB
Python
Raw Normal View History

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
2025-09-22 09:55:14 +03:30
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"entry: {self.id}-{self.quota.quota_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)
2025-11-18 16:51:34 +03:30
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):
2025-08-20 14:44:43 +03:30
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)
2025-08-20 14:44:43 +03:30
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
)
2025-09-09 15:15:04 +03:30
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)
2025-09-22 09:55:14 +03:30
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)
2025-08-25 10:20:25 +03:30
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)
2025-09-20 16:58:24 +03:30
free_sale_state = models.BooleanField(default=False)
pre_sale_state = models.BooleanField(default=False)
additional = models.JSONField(default=dict)
2025-09-09 15:15:04 +03:30
@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):
2025-11-29 11:50:45 +03:30
return f"Inventory Sale: {self.transaction_id}"
def save(self, *args, **kwargs):
super(InventoryQuotaSaleTransaction, self).save(*args, **kwargs)
2025-09-09 15:15:04 +03:30
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
)
2025-09-22 09:55:14 +03:30
gov_product = models.ForeignKey(
2025-09-09 15:15:04 +03:30
product_models.Product,
on_delete=models.CASCADE,
related_name='sale_items',
null=True
)
2025-09-22 09:55:14 +03:30
free_product = models.ForeignKey(
POSFreeProducts,
on_delete=models.CASCADE,
related_name='sale_items',
null=True
)
2025-09-22 09:11:58 +03:30
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)
2025-09-22 10:41:53 +03:30
item_type = models.CharField(max_length=150, null=True)
unit = models.CharField(max_length=50, null=True)
2025-09-09 15:15:04 +03:30
weight = models.PositiveBigIntegerField(default=0)
unit_price = models.PositiveBigIntegerField(default=0)
total_price = models.PositiveBigIntegerField(default=0)
2025-09-22 10:41:53 +03:30
paid_price = models.PositiveBigIntegerField(default=0)
is_extra = models.BooleanField(default=False)
is_pre_sale = models.BooleanField(default=False)
2025-09-22 10:41:53 +03:30
additional = models.JSONField(default=dict)
2025-09-22 12:51:19 +03:30
livestock_statistic = models.JSONField(default=dict)
2025-09-30 15:16:06 +03:30
item_share = models.JSONField(default=list)
inventory_calculation = models.BooleanField(default=False)
base_price = models.PositiveBigIntegerField(default=0)
paid_tashim = models.PositiveBigIntegerField(default=0)
2025-09-09 15:15:04 +03:30
2025-09-22 09:55:14 +03:30
@property
def product(self):
return self.gov_product or self.free_product
2025-09-09 15:15:04 +03:30
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
)
quota_stat = models.ForeignKey(
product_models.OrganizationQuotaStats,
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)
2025-09-20 16:58:24 +03:30
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
)
quota_stat = models.ForeignKey(
product_models.OrganizationQuotaStats,
on_delete=models.CASCADE,
related_name='pre_sales',
null=True
)
2025-09-20 16:58:24 +03:30
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)