From 241e373d15252d73d98d9aa4471a93ad53b5de45 Mon Sep 17 00:00:00 2001 From: Mojtaba-z Date: Tue, 22 Jul 2025 08:16:40 +0330 Subject: [PATCH] pos client & quota limit organization blank --- Rasaddam_Backend/urls.py | 1 + ...005_posclientattribute_choices_and_more.py | 66 +++++++++++++++++++ apps/pos_device/models.py | 45 ++++++++++++- apps/pos_device/urls.py | 2 +- .../{api/v1/serializers.py => __init__.py} | 0 .../v1/{views.py => serilaizers/__init__.py} | 0 .../web/api/v1/serilaizers/serializers.py | 46 +++++++++++++ apps/pos_device/web/api/v1/urls.py | 8 +++ .../web/api/v1/viewsets/__init__.py | 0 apps/pos_device/web/api/v1/viewsets/api.py | 40 +++++++++++ ...r_quota_limit_by_organizations_and_more.py | 29 ++++++++ ...0055_alter_quota_limit_by_organizations.py | 19 ++++++ apps/product/models.py | 10 ++- .../api/v1/serializers/product_serializers.py | 7 +- .../api/v1/serializers/quota_serializers.py | 4 ++ 15 files changed, 271 insertions(+), 6 deletions(-) create mode 100644 apps/pos_device/migrations/0005_posclientattribute_choices_and_more.py rename apps/pos_device/web/{api/v1/serializers.py => __init__.py} (100%) rename apps/pos_device/web/api/v1/{views.py => serilaizers/__init__.py} (100%) create mode 100644 apps/pos_device/web/api/v1/serilaizers/serializers.py create mode 100644 apps/pos_device/web/api/v1/viewsets/__init__.py create mode 100644 apps/pos_device/web/api/v1/viewsets/api.py create mode 100644 apps/product/migrations/0054_alter_quota_limit_by_organizations_and_more.py create mode 100644 apps/product/migrations/0055_alter_quota_limit_by_organizations.py diff --git a/Rasaddam_Backend/urls.py b/Rasaddam_Backend/urls.py index 3bca59d..f91782a 100644 --- a/Rasaddam_Backend/urls.py +++ b/Rasaddam_Backend/urls.py @@ -39,5 +39,6 @@ urlpatterns = [ path('search/', include('apps.search.urls')), path('product/', include('apps.product.urls')), path('warehouse/', include('apps.warehouse.urls')), + path('pos_device/', include('apps.pos_device.urls')), path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'), ] diff --git a/apps/pos_device/migrations/0005_posclientattribute_choices_and_more.py b/apps/pos_device/migrations/0005_posclientattribute_choices_and_more.py new file mode 100644 index 0000000..1796774 --- /dev/null +++ b/apps/pos_device/migrations/0005_posclientattribute_choices_and_more.py @@ -0,0 +1,66 @@ +# Generated by Django 5.0 on 2025-07-22 04:45 + +import django.contrib.postgres.fields +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('pos_device', '0004_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.AddField( + model_name='posclientattribute', + name='choices', + field=django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=150), null=True, size=None), + ), + migrations.AddField( + model_name='posclientattribute', + name='client_type', + field=models.CharField(choices=[('business', 'صنف'), ('person', 'شخص آزاد'), ('organization', 'سازمان')], max_length=25, null=True), + ), + migrations.AddField( + model_name='posclientattribute', + name='field_type', + field=models.CharField(choices=[('text', 'متن'), ('number', 'عدد'), ('date', 'تاریخ'), ('choice', 'چند کزینه ای')], max_length=20, null=True), + ), + migrations.AddField( + model_name='posclientattribute', + name='key', + field=models.CharField(max_length=100, null=True), + ), + migrations.AddField( + model_name='posclientattribute', + name='label', + field=models.CharField(max_length=255, null=True), + ), + migrations.AddField( + model_name='posclientattribute', + name='required', + field=models.BooleanField(default=False), + ), + migrations.CreateModel( + name='POSClientAttributeValue', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('create_date', models.DateTimeField(auto_now_add=True)), + ('modify_date', models.DateTimeField(auto_now=True)), + ('creator_info', models.CharField(max_length=100, null=True)), + ('modifier_info', models.CharField(max_length=100, null=True)), + ('trash', models.BooleanField(default=False)), + ('value', models.TextField(null=True)), + ('attribute', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='attribute_values', to='pos_device.posclientattribute')), + ('client', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='attribute_values', to='pos_device.posclient')), + ('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_createddby', to=settings.AUTH_USER_MODEL)), + ('modified_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_modifiedby', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/apps/pos_device/models.py b/apps/pos_device/models.py index 40efd77..6d2d36b 100644 --- a/apps/pos_device/models.py +++ b/apps/pos_device/models.py @@ -1,6 +1,7 @@ from django.db import models from apps.core.models import BaseModel from apps.authentication.models import Organization +from django.contrib.postgres.fields import ArrayField class ProviderCompany(BaseModel): @@ -111,4 +112,46 @@ class POSClient(BaseModel): class POSClientAttribute(BaseModel): - pass + client_type = models.CharField(max_length=25, choices=[ + ('business', 'صنف'), + ('person', 'شخص آزاد'), # noqa + ('organization', 'سازمان') # noqa + ], null=True) + key = models.CharField(max_length=100, null=True) + label = models.CharField(max_length=255, null=True) + field_type = models.CharField(max_length=20, choices=[ + ('text', 'متن'), + ('number', 'عدد'), + ('date', 'تاریخ'), # noqa + ('choice', 'چند کزینه ای'), # noqa + ], null=True) + required = models.BooleanField(default=False) + choices = ArrayField(base_field=models.CharField(max_length=150), null=True) + + def __str__(self): + return f'attribute: {self.key}-{self.field_type}' + + def save(self, *args, **kwargs): + return super(POSClientAttribute, self).save(*args, **kwargs) + + +class POSClientAttributeValue(BaseModel): + client = models.ForeignKey( + POSClient, + on_delete=models.CASCADE, + related_name='attribute_values', + null=True + ) + attribute = models.ForeignKey( + POSClientAttribute, + on_delete=models.CASCADE, + related_name='attribute_values', + null=True + ) + value = models.TextField(null=True) + + def __str__(self): + return f'Client Attribute: {self.client.name}-{self.attribute.key}' + + def save(self, *args, **kwargs): + return super(POSClientAttributeValue, self).save(*args, **kwargs) diff --git a/apps/pos_device/urls.py b/apps/pos_device/urls.py index c680368..9fbf25e 100644 --- a/apps/pos_device/urls.py +++ b/apps/pos_device/urls.py @@ -1,5 +1,5 @@ from django.urls import path, include urlpatterns = [ - path('', include('')) + path('web/', include('apps.pos_device.web.api.v1.urls')) ] diff --git a/apps/pos_device/web/api/v1/serializers.py b/apps/pos_device/web/__init__.py similarity index 100% rename from apps/pos_device/web/api/v1/serializers.py rename to apps/pos_device/web/__init__.py diff --git a/apps/pos_device/web/api/v1/views.py b/apps/pos_device/web/api/v1/serilaizers/__init__.py similarity index 100% rename from apps/pos_device/web/api/v1/views.py rename to apps/pos_device/web/api/v1/serilaizers/__init__.py diff --git a/apps/pos_device/web/api/v1/serilaizers/serializers.py b/apps/pos_device/web/api/v1/serilaizers/serializers.py new file mode 100644 index 0000000..3ce99a7 --- /dev/null +++ b/apps/pos_device/web/api/v1/serilaizers/serializers.py @@ -0,0 +1,46 @@ +from rest_framework.serializers import ModelSerializer +from apps.pos_device import models as pos_models + + +class ProviderCompanySerializer(ModelSerializer): + class Meta: + model = pos_models.ProviderCompany + fields = '__all__' + + +class DeviceSerializer(ModelSerializer): + class Meta: + model = pos_models.Device + fields = '__all__' + + +class DeviceVersionSerializer(ModelSerializer): + class Meta: + model = pos_models.DeviceVersion + fields = '__all__' + + +class SessionSerializer(ModelSerializer): + class Meta: + model = pos_models.Sessions + fields = '__all__' + + +class POSClientSerializer(ModelSerializer): + class Meta: + model = pos_models.POSClient + fields = '__all__' + + +class POSClientAttributeSerializer(ModelSerializer): + class Meta: + model = pos_models.POSClientAttribute + fields = '__all__' + + +class POSClientAttributeValueSerializer(ModelSerializer): + class Meta: + model = pos_models.POSClientAttributeValue + fields = '__all__' + + diff --git a/apps/pos_device/web/api/v1/urls.py b/apps/pos_device/web/api/v1/urls.py index e69de29..682a1b7 100644 --- a/apps/pos_device/web/api/v1/urls.py +++ b/apps/pos_device/web/api/v1/urls.py @@ -0,0 +1,8 @@ +from django.urls import path, include +from rest_framework.routers import DefaultRouter + +router = DefaultRouter() + +urlpatterns = [ + path('v1/pos/', include(router.urls)) +] \ No newline at end of file diff --git a/apps/pos_device/web/api/v1/viewsets/__init__.py b/apps/pos_device/web/api/v1/viewsets/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apps/pos_device/web/api/v1/viewsets/api.py b/apps/pos_device/web/api/v1/viewsets/api.py new file mode 100644 index 0000000..817208c --- /dev/null +++ b/apps/pos_device/web/api/v1/viewsets/api.py @@ -0,0 +1,40 @@ +from apps.pos_device.web.api.v1.serilaizers import serializers as pos_serializer +from apps.pos_device import models as pos_models +from rest_framework import viewsets +from rest_framework.response import Response +from rest_framework import status + + +class ProviderCompanyViewSet(viewsets.ModelViewSet): # noqa + queryset = pos_models.ProviderCompany.objects.all() + serializer_class = pos_serializer.ProviderCompanySerializer + + +class DeviceViewSet(viewsets.ModelViewSet): + queryset = pos_models.Device.objects.all() + serializer_class = pos_serializer.DeviceSerializer + + +class DeviceVersionViewSet(viewsets.ModelViewSet): + queryset = pos_models.DeviceVersion.objects.all() + serializer_class = pos_serializer.DeviceVersionSerializer + + +class SessionViewSet(viewsets.ModelViewSet): # noqa + queryset = pos_models.Sessions.objects.all() + serializer_class = pos_serializer.SessionSerializer + + +class POSClientViewSet(viewsets.ModelViewSet): + queryset = pos_models.POSClient.objects.all() + serializer_class = pos_serializer.POSClientSerializer + + +class POSClientAttributeViewSet(viewsets.ModelViewSet): + queryset = pos_models.POSClientAttribute.objects.all() + serializer_class = pos_serializer.POSClientAttributeSerializer + + +class POSClientAttributeValueViewSet(viewsets.ModelViewSet): + queryset = pos_models.POSClientAttributeValue.objects.all() + serializer_class = pos_serializer.POSClientAttributeValueSerializer diff --git a/apps/product/migrations/0054_alter_quota_limit_by_organizations_and_more.py b/apps/product/migrations/0054_alter_quota_limit_by_organizations_and_more.py new file mode 100644 index 0000000..fe3f3ff --- /dev/null +++ b/apps/product/migrations/0054_alter_quota_limit_by_organizations_and_more.py @@ -0,0 +1,29 @@ +# Generated by Django 5.0 on 2025-07-22 04:45 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('authentication', '0027_remove_organizationstats_total_buyers_and_more'), + ('product', '0053_attribute_required'), + ] + + operations = [ + migrations.AlterField( + model_name='quota', + name='limit_by_organizations', + field=models.ManyToManyField(blank=True, null=True, related_name='quota_limits', to='authentication.organization'), + ), + migrations.AlterField( + model_name='quotaincentiveassignment', + name='heavy_value', + field=models.PositiveBigIntegerField(default=0), + ), + migrations.AlterField( + model_name='quotaincentiveassignment', + name='light_value', + field=models.PositiveBigIntegerField(default=0), + ), + ] diff --git a/apps/product/migrations/0055_alter_quota_limit_by_organizations.py b/apps/product/migrations/0055_alter_quota_limit_by_organizations.py new file mode 100644 index 0000000..72c53bc --- /dev/null +++ b/apps/product/migrations/0055_alter_quota_limit_by_organizations.py @@ -0,0 +1,19 @@ +# Generated by Django 5.0 on 2025-07-22 04:45 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('authentication', '0027_remove_organizationstats_total_buyers_and_more'), + ('product', '0054_alter_quota_limit_by_organizations_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='quota', + name='limit_by_organizations', + field=models.ManyToManyField(blank=True, related_name='quota_limits', to='authentication.organization'), + ), + ] diff --git a/apps/product/models.py b/apps/product/models.py index 9d9afbf..8d7f8cc 100644 --- a/apps/product/models.py +++ b/apps/product/models.py @@ -341,7 +341,11 @@ class Quota(BaseModel): has_distribution_limit = models.BooleanField(default=False) distribution_mode = ArrayField(base_field=models.IntegerField(), blank=True, null=True) has_organization_limit = models.BooleanField(default=False) - limit_by_organizations = models.ManyToManyField(Organization, related_name='quota_limits') + limit_by_organizations = models.ManyToManyField( + Organization, + related_name='quota_limits', + blank=True + ) 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) @@ -431,8 +435,8 @@ class QuotaIncentiveAssignment(BaseModel): related_name='quota_assignment', null=True ) - heavy_value = models.DecimalField(max_digits=12, decimal_places=2) - light_value = models.DecimalField(max_digits=12, decimal_places=2) + heavy_value = models.PositiveBigIntegerField(default=0) + light_value = models.PositiveBigIntegerField(default=0) def __str__(self): return f"Quota ({self.quota.id}) for {self.incentive_plan.name}" diff --git a/apps/product/web/api/v1/serializers/product_serializers.py b/apps/product/web/api/v1/serializers/product_serializers.py index 2ca344c..61257d6 100644 --- a/apps/product/web/api/v1/serializers/product_serializers.py +++ b/apps/product/web/api/v1/serializers/product_serializers.py @@ -121,7 +121,12 @@ class SaleUnitSerializer(serializers.ModelSerializer): class Meta: model = product_models.SaleUnit - fields = '__all__' + fields = [ + "id", + "product", + "unit", + "required", + ] def to_representation(self, instance): representation = super().to_representation(instance) diff --git a/apps/product/web/api/v1/serializers/quota_serializers.py b/apps/product/web/api/v1/serializers/quota_serializers.py index e88b9f1..573e607 100644 --- a/apps/product/web/api/v1/serializers/quota_serializers.py +++ b/apps/product/web/api/v1/serializers/quota_serializers.py @@ -14,6 +14,10 @@ class QuotaSerializer(serializers.ModelSerializer): def to_representation(self, instance): representation = super().to_representation(instance) if isinstance(instance, product_models.Quota): + if instance.sale_unit: + representation['sale_unit'] = product_serializers.SaleUnitSerializer( + instance.sale_unit + ).data representation['incentive_plan'] = QuotaIncentiveAssignmentSerializer( instance.incentive_assignments.all(), many=True