304 lines
10 KiB
Python
304 lines
10 KiB
Python
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)
|