From 4146a669502c0c9ad8368a1f4ac1a20d03d854c9 Mon Sep 17 00:00:00 2001 From: Mojtaba-z Date: Mon, 25 Aug 2025 16:34:48 +0330 Subject: [PATCH] add some new fields to quota sale transaction model - add rancher information about live stocks & quota aalocations information --- .../migrations/0062_stakeholders_default.py | 18 +++++++ apps/product/models.py | 2 +- apps/product/services/services.py | 15 ++++++ .../0015_inventoryentry_entry_identity.py | 18 +++++++ ...uotasaletransaction_additional_and_more.py | 53 +++++++++++++++++++ apps/warehouse/models.py | 28 ++++++++++ apps/warehouse/pos/api/v1/serializers.py | 5 ++ 7 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 apps/pos_device/migrations/0062_stakeholders_default.py create mode 100644 apps/warehouse/migrations/0015_inventoryentry_entry_identity.py create mode 100644 apps/warehouse/migrations/0016_inventoryquotasaletransaction_additional_and_more.py diff --git a/apps/pos_device/migrations/0062_stakeholders_default.py b/apps/pos_device/migrations/0062_stakeholders_default.py new file mode 100644 index 0000000..90ebb7b --- /dev/null +++ b/apps/pos_device/migrations/0062_stakeholders_default.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0 on 2025-08-25 11:32 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('pos_device', '0061_posfreeproducts'), + ] + + operations = [ + migrations.AddField( + model_name='stakeholders', + name='default', + field=models.BooleanField(default=False), + ), + ] diff --git a/apps/product/models.py b/apps/product/models.py index 13aca3f..dd3b1a6 100644 --- a/apps/product/models.py +++ b/apps/product/models.py @@ -474,7 +474,7 @@ class QuotaBrokerValue(BaseModel): value = models.PositiveBigIntegerField(default=0) def __str__(self): - return f"Quota ({self.quota.id}) for Broker({self.broker.organization.name})" + return f"Quota ({self.quota.id}) for Broker({self.broker.organization_type.name})" def save(self, *args, **kwargs): return super(QuotaBrokerValue, self).save(*args, **kwargs) diff --git a/apps/product/services/services.py b/apps/product/services/services.py index 82ac14f..c277bd1 100644 --- a/apps/product/services/services.py +++ b/apps/product/services/services.py @@ -1,4 +1,6 @@ +from apps.product.models import Quota, QuotaLivestockAllocation from apps.warehouse.models import InventoryEntry +import typing def get_products_in_warehouse(organization_id): @@ -14,3 +16,16 @@ def get_products_in_warehouse(organization_id): return list(set(product_objects)) + +def quota_live_stock_allocation_info(quota: Quota) -> typing.Any: + """ information of quota live stock allocations """ + + allocations = quota.livestock_allocations.filter(quota=quota) + + allocations_list = [{ + "name": alloc.livestock_type.name, + "quantity": alloc.quantity_kg + } for alloc in allocations] + + return allocations_list + diff --git a/apps/warehouse/migrations/0015_inventoryentry_entry_identity.py b/apps/warehouse/migrations/0015_inventoryentry_entry_identity.py new file mode 100644 index 0000000..6e445ea --- /dev/null +++ b/apps/warehouse/migrations/0015_inventoryentry_entry_identity.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0 on 2025-08-25 11:32 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('warehouse', '0014_remove_inventoryquotasaletransaction_buyer_user_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='inventoryentry', + name='entry_identity', + field=models.CharField(max_length=50, null=True), + ), + ] diff --git a/apps/warehouse/migrations/0016_inventoryquotasaletransaction_additional_and_more.py b/apps/warehouse/migrations/0016_inventoryquotasaletransaction_additional_and_more.py new file mode 100644 index 0000000..ec30025 --- /dev/null +++ b/apps/warehouse/migrations/0016_inventoryquotasaletransaction_additional_and_more.py @@ -0,0 +1,53 @@ +# Generated by Django 5.0 on 2025-08-25 13:01 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('warehouse', '0015_inventoryentry_entry_identity'), + ] + + operations = [ + migrations.AddField( + model_name='inventoryquotasaletransaction', + name='additional', + field=models.JSONField(default=dict), + ), + migrations.AddField( + model_name='inventoryquotasaletransaction', + name='payer_cart', + field=models.CharField(max_length=50, null=True), + ), + migrations.AddField( + model_name='inventoryquotasaletransaction', + name='price_paid', + field=models.PositiveBigIntegerField(default=0), + ), + migrations.AddField( + model_name='inventoryquotasaletransaction', + name='price_type', + field=models.CharField(choices=[('card', 'CARD'), ('cash', 'CASH'), ('credit', 'CREDIT'), ('check', 'CHECK')], max_length=50, null=True), + ), + migrations.AddField( + model_name='inventoryquotasaletransaction', + name='ref_num', + field=models.CharField(max_length=50, null=True), + ), + migrations.AddField( + model_name='inventoryquotasaletransaction', + name='result_text', + field=models.TextField(null=True), + ), + migrations.AddField( + model_name='inventoryquotasaletransaction', + name='terminal', + field=models.CharField(max_length=50, null=True), + ), + migrations.AddField( + model_name='inventoryquotasaletransaction', + name='transaction_status_code', + field=models.IntegerField(default=0), + ), + ] diff --git a/apps/warehouse/models.py b/apps/warehouse/models.py index 8d0cd45..935ac38 100644 --- a/apps/warehouse/models.py +++ b/apps/warehouse/models.py @@ -1,3 +1,5 @@ +import string +import random from apps.product import models as product_models from apps.authentication.models import User from apps.pos_device.models import Device @@ -7,6 +9,7 @@ from django.db import models class InventoryEntry(BaseModel): + entry_identity = models.CharField(max_length=50, null=True) distribution = models.ForeignKey( product_models.QuotaDistribution, on_delete=models.CASCADE, @@ -27,6 +30,15 @@ class InventoryEntry(BaseModel): 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.distribution.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 @@ -39,6 +51,8 @@ class InventoryEntry(BaseModel): 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) @@ -83,6 +97,14 @@ class InventoryQuotaSaleTransaction(BaseModel): 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) herd_owners_number = models.PositiveBigIntegerField(default=0) transactions_number = models.PositiveBigIntegerField(default=0) @@ -92,6 +114,12 @@ class InventoryQuotaSaleTransaction(BaseModel): ('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) + ref_num = models.CharField(max_length=50, null=True) + terminal = models.CharField(max_length=50, null=True) + payer_cart = models.CharField(max_length=50, null=True) + additional = models.JSONField(default=dict) def buyers_count(self): """ number of buyers from specific inventory """ diff --git a/apps/warehouse/pos/api/v1/serializers.py b/apps/warehouse/pos/api/v1/serializers.py index 7cada61..ec5d67e 100644 --- a/apps/warehouse/pos/api/v1/serializers.py +++ b/apps/warehouse/pos/api/v1/serializers.py @@ -1,4 +1,5 @@ from apps.herd.services.services import get_rancher_statistics, rancher_quota_weight +from apps.product.services.services import quota_live_stock_allocation_info from apps.pos_device.pos.api.v1.serializers.device import DeviceSerializer from apps.herd.pos.api.v1.serializers import RancherSerializer from apps.warehouse.exceptions import ( @@ -14,6 +15,7 @@ class InventoryEntrySerializer(serializers.ModelSerializer): model = warehouse_models.InventoryEntry fields = [ "id", + "entry_identity", "create_date", "modify_date", "organization", @@ -42,6 +44,9 @@ class InventoryEntrySerializer(serializers.ModelSerializer): 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 + ) } representation['product'] = { 'name': instance.distribution.quota.product.name,