From 2482b9bc45f588dd3a7d699dfb6645d8f746bf50 Mon Sep 17 00:00:00 2001 From: Mojtaba-z Date: Tue, 10 Jun 2025 12:15:17 +0330 Subject: [PATCH] base of product-quota & list cities by province --- apps/authentication/api/v1/api.py | 10 + .../migrations/0021_city_province.py | 19 ++ apps/authentication/models.py | 6 + apps/authorization/api/v1/serializers.py | 2 + ...date_limit_incentiveplan_group_and_more.py | 48 +++++ .../0010_rename_quta_code_quota_quota_code.py | 18 ++ ...r_incentiveplan_end_date_limit_and_more.py | 33 +++ .../0012_alter_productcategory_type.py | 18 ++ .../migrations/0013_alter_product_type.py | 18 ++ .../migrations/0014_broker_broker_type.py | 18 ++ ..._incentiveplan_registering_organization.py | 20 ++ ...016_alter_incentiveplan_unique_together.py | 18 ++ ..._date_incentiveplan_created_by_and_more.py | 197 ++++++++++++++++++ apps/product/models.py | 65 ++++-- apps/product/web/api/v1/api.py | 38 +++- apps/product/web/api/v1/serializers.py | 23 +- apps/product/web/api/v1/urls.py | 2 + 17 files changed, 534 insertions(+), 19 deletions(-) create mode 100644 apps/authentication/migrations/0021_city_province.py create mode 100644 apps/product/migrations/0009_incentiveplan_end_date_limit_incentiveplan_group_and_more.py create mode 100644 apps/product/migrations/0010_rename_quta_code_quota_quota_code.py create mode 100644 apps/product/migrations/0011_alter_incentiveplan_end_date_limit_and_more.py create mode 100644 apps/product/migrations/0012_alter_productcategory_type.py create mode 100644 apps/product/migrations/0013_alter_product_type.py create mode 100644 apps/product/migrations/0014_broker_broker_type.py create mode 100644 apps/product/migrations/0015_incentiveplan_registering_organization.py create mode 100644 apps/product/migrations/0016_alter_incentiveplan_unique_together.py create mode 100644 apps/product/migrations/0017_incentiveplan_create_date_incentiveplan_created_by_and_more.py diff --git a/apps/authentication/api/v1/api.py b/apps/authentication/api/v1/api.py index 55e4992..0d92f77 100644 --- a/apps/authentication/api/v1/api.py +++ b/apps/authentication/api/v1/api.py @@ -161,6 +161,16 @@ class CityViewSet(ModelViewSet): queryset = City.objects.all() serializer_class = CitySerializer + def list(self, request, *args, **kwargs): + """ return list of cities by province """ + + serializer = self.serializer_class( + self.queryset.filter( + province_id=int(request.GET['province']) + ), many=True + ) + return Response(serializer.data, status=status.HTTP_200_OK) + class ProvinceViewSet(ModelViewSet): """ Crud operations for province model """ # diff --git a/apps/authentication/migrations/0021_city_province.py b/apps/authentication/migrations/0021_city_province.py new file mode 100644 index 0000000..5f71df9 --- /dev/null +++ b/apps/authentication/migrations/0021_city_province.py @@ -0,0 +1,19 @@ +# Generated by Django 5.0 on 2025-06-10 08:39 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('authentication', '0020_blacklistedaccesstoken'), + ] + + operations = [ + migrations.AddField( + model_name='city', + name='province', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='cities', to='authentication.province'), + ), + ] diff --git a/apps/authentication/models.py b/apps/authentication/models.py index 0edfa25..ccd4063 100644 --- a/apps/authentication/models.py +++ b/apps/authentication/models.py @@ -59,6 +59,12 @@ class Province(BaseModel): # noqa class City(BaseModel): name = models.CharField(max_length=50) + province = models.ForeignKey( + Province, + on_delete=models.CASCADE, + related_name='cities', + null=True + ) def __str__(self): return f'{self.name}' diff --git a/apps/authorization/api/v1/serializers.py b/apps/authorization/api/v1/serializers.py index 963f70f..d49d35b 100644 --- a/apps/authorization/api/v1/serializers.py +++ b/apps/authorization/api/v1/serializers.py @@ -125,6 +125,7 @@ class UserRelationSerializer(serializers.ModelSerializer): def to_representation(self, instance): """ custom output for serializer """ + representation = super().to_representation(instance) if isinstance(instance, UserRelations): if instance.user: @@ -142,6 +143,7 @@ class UserRelationSerializer(serializers.ModelSerializer): def update(self, instance, validated_data): """ update user relation object """ + if validated_data.get('role'): instance.role = validated_data.get('role', instance.role.id) if validated_data.get('organization'): diff --git a/apps/product/migrations/0009_incentiveplan_end_date_limit_incentiveplan_group_and_more.py b/apps/product/migrations/0009_incentiveplan_end_date_limit_incentiveplan_group_and_more.py new file mode 100644 index 0000000..26bc4d2 --- /dev/null +++ b/apps/product/migrations/0009_incentiveplan_end_date_limit_incentiveplan_group_and_more.py @@ -0,0 +1,48 @@ +# Generated by Django 5.0 on 2025-06-10 07:10 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('product', '0008_incentiveplan_remove_attributevalue_product_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='incentiveplan', + name='end_date_limit', + field=models.DateTimeField(null=True), + ), + migrations.AddField( + model_name='incentiveplan', + name='group', + field=models.CharField(choices=[('I', 'Industrial'), ('R', 'Rural'), ('N', 'Nomadic')], max_length=1, null=True), + ), + migrations.AddField( + model_name='incentiveplan', + name='is_time_unlimited', + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name='incentiveplan', + name='plan_type', + field=models.CharField(choices=[('ILQ', 'increasing livestock quotas'), ('SM', 'statistical/monitoring')], max_length=5, null=True), + ), + migrations.AddField( + model_name='incentiveplan', + name='start_date_limit', + field=models.DateTimeField(null=True), + ), + migrations.AddField( + model_name='quota', + name='quota_id', + field=models.CharField(max_length=15, null=True), + ), + migrations.AddField( + model_name='quota', + name='quta_code', + field=models.CharField(max_length=15, null=True), + ), + ] diff --git a/apps/product/migrations/0010_rename_quta_code_quota_quota_code.py b/apps/product/migrations/0010_rename_quta_code_quota_quota_code.py new file mode 100644 index 0000000..739dcb1 --- /dev/null +++ b/apps/product/migrations/0010_rename_quta_code_quota_quota_code.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0 on 2025-06-10 07:12 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('product', '0009_incentiveplan_end_date_limit_incentiveplan_group_and_more'), + ] + + operations = [ + migrations.RenameField( + model_name='quota', + old_name='quta_code', + new_name='quota_code', + ), + ] diff --git a/apps/product/migrations/0011_alter_incentiveplan_end_date_limit_and_more.py b/apps/product/migrations/0011_alter_incentiveplan_end_date_limit_and_more.py new file mode 100644 index 0000000..be8d09c --- /dev/null +++ b/apps/product/migrations/0011_alter_incentiveplan_end_date_limit_and_more.py @@ -0,0 +1,33 @@ +# Generated by Django 5.0 on 2025-06-10 07:23 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('product', '0010_rename_quta_code_quota_quota_code'), + ] + + operations = [ + migrations.AlterField( + model_name='incentiveplan', + name='end_date_limit', + field=models.DateField(blank=True, null=True), + ), + migrations.AlterField( + model_name='incentiveplan', + name='group', + field=models.CharField(choices=[('industrial', 'Industrial'), ('rural', 'Rural'), ('nomadic', 'Nomadic')], max_length=15, null=True), + ), + migrations.AlterField( + model_name='incentiveplan', + name='start_date_limit', + field=models.DateField(blank=True, null=True), + ), + migrations.AlterField( + model_name='quota', + name='group', + field=models.CharField(choices=[('rural', 'روستایی'), ('industrial', 'صنعتی'), ('nomadic', 'عشایری')], max_length=50), + ), + ] diff --git a/apps/product/migrations/0012_alter_productcategory_type.py b/apps/product/migrations/0012_alter_productcategory_type.py new file mode 100644 index 0000000..2491e80 --- /dev/null +++ b/apps/product/migrations/0012_alter_productcategory_type.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0 on 2025-06-10 07:32 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('product', '0011_alter_incentiveplan_end_date_limit_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='productcategory', + name='type', + field=models.CharField(choices=[('free', 'Free'), ('gov', 'Governmental')], default='empty', max_length=5), + ), + ] diff --git a/apps/product/migrations/0013_alter_product_type.py b/apps/product/migrations/0013_alter_product_type.py new file mode 100644 index 0000000..06b077b --- /dev/null +++ b/apps/product/migrations/0013_alter_product_type.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0 on 2025-06-10 07:34 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('product', '0012_alter_productcategory_type'), + ] + + operations = [ + migrations.AlterField( + model_name='product', + name='type', + field=models.CharField(choices=[('free', 'FREE'), ('gov', 'GOVERNMENTAL')], max_length=5), + ), + ] diff --git a/apps/product/migrations/0014_broker_broker_type.py b/apps/product/migrations/0014_broker_broker_type.py new file mode 100644 index 0000000..cda11f8 --- /dev/null +++ b/apps/product/migrations/0014_broker_broker_type.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0 on 2025-06-10 07:45 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('product', '0013_alter_product_type'), + ] + + operations = [ + migrations.AddField( + model_name='broker', + name='broker_type', + field=models.CharField(choices=[('public', 'PUBLIC'), ('exclusive', 'EXCLUSIVE')], max_length=20, null=True), + ), + ] diff --git a/apps/product/migrations/0015_incentiveplan_registering_organization.py b/apps/product/migrations/0015_incentiveplan_registering_organization.py new file mode 100644 index 0000000..4559b7c --- /dev/null +++ b/apps/product/migrations/0015_incentiveplan_registering_organization.py @@ -0,0 +1,20 @@ +# Generated by Django 5.0 on 2025-06-10 08:16 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('authorization', '0017_alter_permissions_name'), + ('product', '0014_broker_broker_type'), + ] + + operations = [ + migrations.AddField( + model_name='incentiveplan', + name='registering_organization', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='incentive_plans', to='authorization.userrelations'), + ), + ] diff --git a/apps/product/migrations/0016_alter_incentiveplan_unique_together.py b/apps/product/migrations/0016_alter_incentiveplan_unique_together.py new file mode 100644 index 0000000..d2ee159 --- /dev/null +++ b/apps/product/migrations/0016_alter_incentiveplan_unique_together.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0 on 2025-06-10 08:18 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('authorization', '0017_alter_permissions_name'), + ('product', '0015_incentiveplan_registering_organization'), + ] + + operations = [ + migrations.AlterUniqueTogether( + name='incentiveplan', + unique_together={('name', 'registering_organization')}, + ), + ] diff --git a/apps/product/migrations/0017_incentiveplan_create_date_incentiveplan_created_by_and_more.py b/apps/product/migrations/0017_incentiveplan_create_date_incentiveplan_created_by_and_more.py new file mode 100644 index 0000000..def69d7 --- /dev/null +++ b/apps/product/migrations/0017_incentiveplan_create_date_incentiveplan_created_by_and_more.py @@ -0,0 +1,197 @@ +# Generated by Django 5.0 on 2025-06-10 08:22 + +import django.db.models.deletion +import django.utils.timezone +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('product', '0016_alter_incentiveplan_unique_together'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.AddField( + model_name='incentiveplan', + name='create_date', + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), + preserve_default=False, + ), + migrations.AddField( + model_name='incentiveplan', + name='created_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_createddby', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='incentiveplan', + name='creator_info', + field=models.CharField(max_length=100, null=True), + ), + migrations.AddField( + model_name='incentiveplan', + name='modified_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_modifiedby', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='incentiveplan', + name='modifier_info', + field=models.CharField(max_length=100, null=True), + ), + migrations.AddField( + model_name='incentiveplan', + name='modify_date', + field=models.DateTimeField(auto_now=True), + ), + migrations.AddField( + model_name='incentiveplan', + name='trash', + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name='quota', + name='create_date', + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), + preserve_default=False, + ), + migrations.AddField( + model_name='quota', + name='created_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_createddby', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='quota', + name='creator_info', + field=models.CharField(max_length=100, null=True), + ), + migrations.AddField( + model_name='quota', + name='modified_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_modifiedby', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='quota', + name='modifier_info', + field=models.CharField(max_length=100, null=True), + ), + migrations.AddField( + model_name='quota', + name='modify_date', + field=models.DateTimeField(auto_now=True), + ), + migrations.AddField( + model_name='quota', + name='trash', + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name='quotabrokervalue', + name='create_date', + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), + preserve_default=False, + ), + migrations.AddField( + model_name='quotabrokervalue', + name='created_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_createddby', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='quotabrokervalue', + name='creator_info', + field=models.CharField(max_length=100, null=True), + ), + migrations.AddField( + model_name='quotabrokervalue', + name='modified_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_modifiedby', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='quotabrokervalue', + name='modifier_info', + field=models.CharField(max_length=100, null=True), + ), + migrations.AddField( + model_name='quotabrokervalue', + name='modify_date', + field=models.DateTimeField(auto_now=True), + ), + migrations.AddField( + model_name='quotabrokervalue', + name='trash', + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name='quotaincentiveassignment', + name='create_date', + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), + preserve_default=False, + ), + migrations.AddField( + model_name='quotaincentiveassignment', + name='created_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_createddby', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='quotaincentiveassignment', + name='creator_info', + field=models.CharField(max_length=100, null=True), + ), + migrations.AddField( + model_name='quotaincentiveassignment', + name='modified_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_modifiedby', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='quotaincentiveassignment', + name='modifier_info', + field=models.CharField(max_length=100, null=True), + ), + migrations.AddField( + model_name='quotaincentiveassignment', + name='modify_date', + field=models.DateTimeField(auto_now=True), + ), + migrations.AddField( + model_name='quotaincentiveassignment', + name='trash', + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name='quotalivestockallocation', + name='create_date', + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), + preserve_default=False, + ), + migrations.AddField( + model_name='quotalivestockallocation', + name='created_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_createddby', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='quotalivestockallocation', + name='creator_info', + field=models.CharField(max_length=100, null=True), + ), + migrations.AddField( + model_name='quotalivestockallocation', + name='modified_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_modifiedby', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='quotalivestockallocation', + name='modifier_info', + field=models.CharField(max_length=100, null=True), + ), + migrations.AddField( + model_name='quotalivestockallocation', + name='modify_date', + field=models.DateTimeField(auto_now=True), + ), + migrations.AddField( + model_name='quotalivestockallocation', + name='trash', + field=models.BooleanField(default=False), + ), + ] diff --git a/apps/product/models.py b/apps/product/models.py index b82d57e..7864573 100644 --- a/apps/product/models.py +++ b/apps/product/models.py @@ -27,10 +27,10 @@ class ProductCategory(BaseModel): name = models.CharField(max_length=250, default='empty') # noqa type_choices = ( - ('F', 'Free'), # free product - ('G', 'Governmental') # government product + ('free', 'Free'), # free product + ('gov', 'Governmental') # government product ) - type = models.CharField(max_length=3, choices=type_choices, default='empty') + type = models.CharField(max_length=5, choices=type_choices, default='empty') img = models.CharField(max_length=100, default='empty') parent = models.ForeignKey( 'self', @@ -50,10 +50,10 @@ class Product(BaseModel): """ Child of reference product - like: brown rice """ name = models.CharField(max_length=250, default='empty') # noqa type_choices = ( - ('F', 'Free'), # free product - ('G', 'Governmental') # government product + ('free', 'FREE'), # free product + ('gov', 'GOVERNMENTAL') # government product ) - type = models.CharField(max_length=3, choices=type_choices) + type = models.CharField(max_length=5, choices=type_choices) img = models.CharField(max_length=100, default='empty') category = models.ForeignKey( ProductCategory, @@ -130,6 +130,14 @@ class AttributeValue(BaseModel): class Broker(BaseModel): """ Broker for product """ + CALCULATION_CHOICES = ( + ('K', 'Per Kilo'), + ('', ''), + ) + BROKER_TYPES = ( + ('public', 'PUBLIC'), + ('exclusive', 'EXCLUSIVE') + ) product = models.ForeignKey( Product, on_delete=models.CASCADE, @@ -142,15 +150,13 @@ class Broker(BaseModel): related_name='product_organization', null=True ) - calculation_choices = ( - ('K', 'Per Kilo'), - ('', ''), - ) + calculation_strategy = models.CharField( max_length=3, - choices=calculation_choices, + choices=CALCULATION_CHOICES, default='empty' ) + broker_type = models.CharField(choices=BROKER_TYPES, max_length=20, null=True) required = models.BooleanField(default=False) def __str__(self): @@ -185,9 +191,32 @@ class SaleUnit(BaseModel): return super(SaleUnit, self).save(*args, **kwargs) -class IncentivePlan(models.Model): +class IncentivePlan(BaseModel): + PLAN_TYPE_CHOICES = ( + ('ILQ', 'increasing livestock quotas'), + ('SM', 'statistical/monitoring') + ) + GROUP_CHOICES = ( + ('industrial', 'Industrial'), + ('rural', 'Rural'), + ('nomadic', 'Nomadic') + ) name = models.CharField(max_length=255) description = models.TextField(blank=True, null=True) + registering_organization = models.ForeignKey( + UserRelations, + on_delete=models.CASCADE, + related_name='incentive_plans', + null=True + ) + plan_type = models.CharField(choices=PLAN_TYPE_CHOICES, max_length=5, null=True) + group = models.CharField(choices=GROUP_CHOICES, max_length=15, null=True) + is_time_unlimited = models.BooleanField(default=False) + start_date_limit = models.DateField(null=True, blank=True) + end_date_limit = models.DateField(null=True, blank=True) + + class Meta: + unique_together = ('name', 'registering_organization') def __str__(self): return self.name @@ -196,7 +225,9 @@ class IncentivePlan(models.Model): return super(IncentivePlan, self).save(*args, **kwargs) -class Quota(models.Model): +class Quota(BaseModel): + quota_id = models.CharField(max_length=15, null=True) + quota_code = models.CharField(max_length=15, null=True) product = models.ForeignKey( Product, on_delete=models.CASCADE, @@ -206,7 +237,7 @@ class Quota(models.Model): month_choices = ArrayField(base_field=models.IntegerField(), null=True) group = models.CharField( max_length=50, - choices=[("roostaei", "روستایی"), ("sanati", "صنعتی"), ("ashayeri", "عشایری")] # noqa + choices=[("rural", "روستایی"), ("industrial", "صنعتی"), ("nomadic", "عشایری")] # noqa ) has_distribution_limit = models.BooleanField(default=False) distribution_mode = models.CharField(max_length=50, blank=True, null=True) @@ -222,7 +253,7 @@ class Quota(models.Model): return super(Quota, self).save(*args, **kwargs) -class QuotaIncentiveAssignment(models.Model): +class QuotaIncentiveAssignment(BaseModel): quota = models.ForeignKey( Quota, on_delete=models.CASCADE, @@ -244,7 +275,7 @@ class QuotaIncentiveAssignment(models.Model): return super(QuotaIncentiveAssignment, self).save(*args, **kwargs) -class QuotaBrokerValue(models.Model): +class QuotaBrokerValue(BaseModel): quota = models.ForeignKey( Quota, on_delete=models.CASCADE, @@ -265,7 +296,7 @@ class QuotaBrokerValue(models.Model): return super(QuotaBrokerValue, self).save(*args, **kwargs) -class QuotaLivestockAllocation(models.Model): +class QuotaLivestockAllocation(BaseModel): quota = models.ForeignKey( "Quota", on_delete=models.CASCADE, diff --git a/apps/product/web/api/v1/api.py b/apps/product/web/api/v1/api.py index 5bbf5a7..baafb46 100644 --- a/apps/product/web/api/v1/api.py +++ b/apps/product/web/api/v1/api.py @@ -21,6 +21,42 @@ def delete(queryset, pk): obj.delete() +class ProductCategoryViewSet(viewsets.ModelViewSet): + queryset = product_models.ProductCategory.objects.all() + serializer_class = product_serializers.ProductCategorySerializer + + @action( + methods=['put'], + detail=True, + url_path='trash', + url_name='trash', + name='trash', + ) + @transaction.atomic + def trash(self, request, pk=None): + """ Sent product to trash """ + try: + trash(self.queryset, pk) + except APIException as e: + return Response(e, status.HTTP_204_NO_CONTENT) + + @action( + methods=['post'], + detail=True, + url_name='delete', + url_path='delete', + name='delete' + ) + @transaction.atomic + def delete(self, request, pk=None): + """ Full delete of product object """ + try: + delete(self.queryset, pk) + return Response(status=status.HTTP_200_OK) + except APIException as e: + return Response(e, status=status.HTTP_204_NO_CONTENT) + + class ProductViewSet(viewsets.ModelViewSet): queryset = product_models.Product.objects.all() serializer_class = product_serializers.ProductSerializer @@ -209,7 +245,7 @@ class SaleUnitViewSet(viewsets.ModelViewSet): return Response(e, status=status.HTTP_204_NO_CONTENT) -class IncentivePlanViewSet(viewsets.ModelViewSet): +class IncentivePlanViewSet(viewsets.ModelViewSet): # noqa """ apis for incentive plan """ queryset = product_models.IncentivePlan.objects.all() diff --git a/apps/product/web/api/v1/serializers.py b/apps/product/web/api/v1/serializers.py index 1dde421..8927da2 100644 --- a/apps/product/web/api/v1/serializers.py +++ b/apps/product/web/api/v1/serializers.py @@ -3,6 +3,12 @@ from apps.product import models as product_models from apps.authorization.api.v1 import serializers as authorize_serializers +class ProductCategorySerializer(serializers.ModelSerializer): + class Meta: + model = product_models.ProductCategory + fields = '__all__' + + class ProductSerializer(serializers.ModelSerializer): """ Serializer of product """ @@ -14,6 +20,11 @@ class ProductSerializer(serializers.ModelSerializer): """ Custom output of product serializer """ representation = super().to_representation(instance) + if instance.category: + representation['category'] = { + 'id': instance.category.id, + 'name': instance.category.name + } return representation @@ -27,6 +38,11 @@ class AttributeSerializer(serializers.ModelSerializer): def to_representation(self, instance): representation = super().to_representation(instance) + if instance.product: + representation['product'] = { + 'id': instance.product.id, + 'name': instance.product.name + } return representation @@ -75,13 +91,18 @@ class SaleUnitSerializer(serializers.ModelSerializer): def to_representation(self, instance): representation = super().to_representation(instance) + if instance.product: + representation['product'] = { + 'id': instance.product.id, + 'name': instance.product.name + } return representation class IncentivePlanSerializer(serializers.ModelSerializer): class Meta: model = product_models.IncentivePlan - fields = '__all_' + fields = '__all__' class QuotaSerializer(serializers.ModelSerializer): diff --git a/apps/product/web/api/v1/urls.py b/apps/product/web/api/v1/urls.py index d4f74f1..8eea23c 100644 --- a/apps/product/web/api/v1/urls.py +++ b/apps/product/web/api/v1/urls.py @@ -4,10 +4,12 @@ from django.urls import path, include router = DefaultRouter() router.register(r'product', api_views.ProductViewSet, basename='product') +router.register(r'category', api_views.ProductCategoryViewSet, basename='category') router.register(r'attribute', api_views.AttributeViewSet, basename='attribute') router.register(r'attribute_value', api_views.AttributeValueViewSet, basename='attribute_value') router.register(r'broker', api_views.BrokerViewSet, basename='broker') router.register(r'sale_unit', api_views.SaleUnitViewSet, basename='sale_unit') +router.register(r'incentive_plan', api_views.IncentivePlanViewSet, basename='incentive_plan') urlpatterns = [ path('v1/', include(router.urls))