quota, distribution, inventory entry, quota sale transaction, product informations, signals ,....
This commit is contained in:
@@ -1,7 +1,12 @@
|
||||
import datetime
|
||||
from simple_history.models import HistoricalRecords
|
||||
from django.db import models
|
||||
from apps.core.models import BaseModel
|
||||
from apps.authorization.models import UserRelations
|
||||
from apps.authentication.models import Organization
|
||||
from django.contrib.postgres.fields import ArrayField
|
||||
from datetime import datetime
|
||||
import jdatetime
|
||||
|
||||
|
||||
class LivestockGroup(models.TextChoices):
|
||||
@@ -74,6 +79,41 @@ class Product(BaseModel):
|
||||
next_code = 10
|
||||
return next_code
|
||||
|
||||
def quota_information(self):
|
||||
"""
|
||||
quotas information of product
|
||||
"""
|
||||
|
||||
# number of quotas
|
||||
quotas_count = self.quotas.filter(is_closed=False).count()
|
||||
|
||||
# total weight of product that assigned in quota
|
||||
total_quotas_weight = self.quotas.filter(is_closed=False).aggregate(
|
||||
total=models.Sum('quota_weight')
|
||||
)['total'] or 0
|
||||
|
||||
# total remaining weight of product quotas
|
||||
total_remaining_quotas_weight = self.quotas.filter(is_closed=False).aggregate(
|
||||
total=models.Sum('remaining_weight')
|
||||
)['total'] or 0
|
||||
|
||||
total_distributed_weight = QuotaDistribution.objects.filter(
|
||||
quota__product_id=self.id,
|
||||
quota__is_closed=False
|
||||
).aggregate(total_weight=models.Sum('weight'))['total_weight'] or 0
|
||||
|
||||
total_sold = QuotaDistribution.objects.filter(
|
||||
quota__product_id=self.id,
|
||||
quota__is_closed=False
|
||||
).aggregate(total_sold=models.Sum('been_sold'))['total_sold'] or 0
|
||||
|
||||
total_warehouse_entry = QuotaDistribution.objects.filter(
|
||||
quota__product_id=self.id,
|
||||
quota__is_closed=False
|
||||
).aggregate(total_entry=models.Sum('warehouse_entry'))['total_entry'] or 0
|
||||
|
||||
return {'quotas_count': quotas_count, 'total_quotas_weight': total_quotas_weight}
|
||||
|
||||
def __str__(self):
|
||||
return f'name: {self.name} - type: {self.type}'
|
||||
|
||||
@@ -159,8 +199,8 @@ class Broker(BaseModel):
|
||||
related_name='product_broker',
|
||||
null=True
|
||||
)
|
||||
organization_relations = models.ForeignKey(
|
||||
UserRelations,
|
||||
organization = models.ForeignKey(
|
||||
Organization,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='product_organization',
|
||||
null=True
|
||||
@@ -174,7 +214,7 @@ class Broker(BaseModel):
|
||||
required = models.BooleanField(default=False)
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.organization_relations.organization.name} - {self.product.name}'
|
||||
return f'{self.organization.name} - {self.product.name}'
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
return super(Broker, self).save(*args, **kwargs)
|
||||
@@ -245,13 +285,13 @@ class Quota(BaseModel):
|
||||
""" quota for product with some conditions """
|
||||
|
||||
registerer_organization = models.ForeignKey(
|
||||
UserRelations,
|
||||
Organization,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='quotas',
|
||||
null=True
|
||||
)
|
||||
assigned_organizations = models.ManyToManyField(
|
||||
UserRelations,
|
||||
Organization,
|
||||
related_name='assigned_quotas',
|
||||
blank=True
|
||||
)
|
||||
@@ -260,7 +300,6 @@ class Quota(BaseModel):
|
||||
quota_weight = models.PositiveIntegerField(default=0)
|
||||
remaining_weight = models.PositiveBigIntegerField(default=0)
|
||||
quota_distributed = models.PositiveIntegerField(default=0)
|
||||
quota_balance = models.PositiveIntegerField(default=0)
|
||||
product = models.ForeignKey(
|
||||
Product,
|
||||
on_delete=models.CASCADE,
|
||||
@@ -279,6 +318,8 @@ class Quota(BaseModel):
|
||||
base_price_factory = models.DecimalField(max_digits=12, decimal_places=2)
|
||||
base_price_cooperative = models.DecimalField(max_digits=12, decimal_places=2)
|
||||
final_price = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True)
|
||||
is_closed = models.BooleanField(default=False)
|
||||
closed_at = models.DateTimeField(null=True, blank=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"Quota ({self.id}) for {self.product.name}"
|
||||
@@ -313,6 +354,13 @@ class Quota(BaseModel):
|
||||
distributed_weight = self.distributions_assigned.aggregate(total=models.Sum("weight"))["total"] or 0
|
||||
return self.quota_weight - distributed_weight
|
||||
|
||||
def is_in_valid_time(self):
|
||||
""" check if quota allowed time for distribute, sale, etc is expired"""
|
||||
now = datetime.now()
|
||||
persian_date = jdatetime.datetime.fromgregorian(datetime=now)
|
||||
|
||||
return persian_date.month in self.month_choices
|
||||
|
||||
def save(self, calculate_final_price=None, *args, **kwargs):
|
||||
if not self.quota_id:
|
||||
self.quota_id = self.generate_quota_id()
|
||||
@@ -364,7 +412,7 @@ class QuotaBrokerValue(BaseModel):
|
||||
value = models.DecimalField(max_digits=12, decimal_places=2)
|
||||
|
||||
def __str__(self):
|
||||
return f"Quota ({self.quota.id}) for Broker({self.broker.organization_relations.organization.name})"
|
||||
return f"Quota ({self.quota.id}) for Broker({self.broker.organization.name})"
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
return super(QuotaBrokerValue, self).save(*args, **kwargs)
|
||||
@@ -379,13 +427,16 @@ class QuotaLivestockAllocation(BaseModel):
|
||||
related_name="livestock_allocations",
|
||||
null=True
|
||||
)
|
||||
livestock_group = models.CharField(max_length=20, choices=LivestockGroup.choices)
|
||||
livestock_type = models.CharField(max_length=20, choices=LivestockType.choices)
|
||||
livestock_subtype = models.CharField(max_length=20, choices=LivestockSubtype.choices)
|
||||
quantity_kg = models.DecimalField(max_digits=12, decimal_places=2)
|
||||
livestock_group = models.CharField(max_length=20, choices=LivestockGroup.choices, null=True)
|
||||
livestock_type = models.CharField(max_length=20, choices=LivestockType.choices, null=True)
|
||||
livestock_subtype = models.CharField(max_length=20, choices=LivestockSubtype.choices, null=True)
|
||||
quantity_kg = models.DecimalField(max_digits=12, decimal_places=2, null=True)
|
||||
|
||||
"""
|
||||
@using for set unique values between fields
|
||||
class Meta:
|
||||
unique_together = ('quota', 'livestock_group', 'livestock_type', 'livestock_subtype')
|
||||
"""
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.livestock_group} - {self.livestock_type}/{self.livestock_subtype}: {self.quantity_kg}kg"
|
||||
@@ -401,8 +452,8 @@ class QuotaLiveStockAgeLimitation(BaseModel):
|
||||
related_name='livestock_age_limitations',
|
||||
null=True
|
||||
)
|
||||
livestock_type = models.CharField(max_length=20, choices=LivestockType.choices)
|
||||
livestock_subtype = models.CharField(max_length=20, choices=LivestockSubtype.choices)
|
||||
livestock_type = models.CharField(max_length=20, choices=LivestockType.choices, null=True)
|
||||
livestock_subtype = models.CharField(max_length=20, choices=LivestockSubtype.choices, null=True)
|
||||
age_month = models.PositiveIntegerField(default=0)
|
||||
|
||||
def __str__(self):
|
||||
@@ -414,11 +465,17 @@ class QuotaLiveStockAgeLimitation(BaseModel):
|
||||
|
||||
class QuotaDistribution(BaseModel):
|
||||
assigner_organization = models.ForeignKey(
|
||||
UserRelations,
|
||||
Organization,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='distributions_assigner',
|
||||
null=True
|
||||
)
|
||||
assigned_organization = models.ForeignKey(
|
||||
Organization,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='distributions',
|
||||
null=True
|
||||
)
|
||||
description = models.TextField(max_length=1000, null=True)
|
||||
distribution_id = models.CharField(max_length=20, null=True)
|
||||
quota = models.ForeignKey(
|
||||
@@ -427,19 +484,32 @@ class QuotaDistribution(BaseModel):
|
||||
related_name='distributions_assigned',
|
||||
null=True
|
||||
)
|
||||
assigned_organization = models.ForeignKey(
|
||||
UserRelations,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='distributions',
|
||||
null=True
|
||||
)
|
||||
weight = models.PositiveBigIntegerField(default=0)
|
||||
warehouse_entry = models.PositiveBigIntegerField(default=0)
|
||||
warehouse_balance = models.PositiveBigIntegerField(default=0)
|
||||
been_sold = models.PositiveBigIntegerField(default=0)
|
||||
history = HistoricalRecords()
|
||||
|
||||
def generate_distribution_id(self):
|
||||
""" generate special id for quota distribution """
|
||||
|
||||
year = jdatetime.datetime.now().year
|
||||
month = jdatetime.datetime.now().month
|
||||
day = jdatetime.datetime.now().day
|
||||
product_id = self.quota.product.product_id
|
||||
quota_id = self.quota.quota_id
|
||||
|
||||
base_code = f"{str(year)[3]}{month}{day}{product_id}{quota_id}"
|
||||
|
||||
similar_codes = QuotaDistribution.objects.filter(distribution_id__startswith=base_code).count()
|
||||
counter = str(similar_codes + 1).zfill(4)
|
||||
|
||||
return f"{base_code}{counter}"
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.distribution_id}-{self.assigned_organization.organization.name}"
|
||||
return f"{self.distribution_id}-"
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.distribution_id:
|
||||
self.distribution_id = self.generate_distribution_id()
|
||||
return super(QuotaDistribution, self).save(*args, **kwargs)
|
||||
|
||||
Reference in New Issue
Block a user