diff --git a/apps/authentication/api/v1/serializers/serializer.py b/apps/authentication/api/v1/serializers/serializer.py index 564c25a..b9fac7d 100644 --- a/apps/authentication/api/v1/serializers/serializer.py +++ b/apps/authentication/api/v1/serializers/serializer.py @@ -3,7 +3,6 @@ from apps.authorization.api.v1.serializers import ( PermissionSerializer, RoleSerializer ) -from rest_framework.response import Response from rest_framework import serializers from apps.authentication.models import ( User, @@ -18,6 +17,8 @@ import typing class CitySerializer(serializers.ModelSerializer): + """ Serialize city data """ + class Meta: model = City fields = [ @@ -27,6 +28,8 @@ class CitySerializer(serializers.ModelSerializer): class ProvinceSerializer(serializers.ModelSerializer): + """ Serialize province data """ + class Meta: model = Province fields = [ @@ -36,6 +39,8 @@ class ProvinceSerializer(serializers.ModelSerializer): class BankAccountSerializer(serializers.ModelSerializer): + """ Serialize bank account data """ + class Meta: model = BankAccountInformation fields = [ @@ -63,23 +68,9 @@ class BankAccountSerializer(serializers.ModelSerializer): return instance -class UserDataRelationSerializer(serializers.ModelSerializer): - class Meta: - model = authorize_models.UserRelations - fields = '__all__' - - def to_representation(self, instance): - representation = super().to_representation(instance) - representation['role'] = RoleSerializer(instance.role).data - representation['organization'] = instance.organization.name - representation['permissions'] = PermissionSerializer().permissions_structure_output( - instance.permissions.all() - ) - - return representation - - class UserSerializer(serializers.ModelSerializer): + """ Serialize user data """ + class Meta: model = User fields = [ @@ -103,11 +94,9 @@ class UserSerializer(serializers.ModelSerializer): ] def to_representation(self, instance): + """ Custom output """ + representation = super().to_representation(instance) - if authorize_models.UserRelations.objects.filter(user=instance).exists(): - representation['relation_data'] = UserDataRelationSerializer( - authorize_models.UserRelations.objects.filter(user=instance).first() - ).data if instance.bank_information.all(): representation['bank_account'] = BankAccountSerializer( instance.bank_information.all(), many=True @@ -160,6 +149,8 @@ class UserSerializer(serializers.ModelSerializer): class OrganizationTypeSerializer(serializers.ModelSerializer): + """ Serialize organization type data """ + class Meta: model = OrganizationType fields = [ @@ -170,6 +161,8 @@ class OrganizationTypeSerializer(serializers.ModelSerializer): class OrganizationSerializer(serializers.ModelSerializer): + """ Serialize organization data """ + class Meta: model = Organization fields = [ @@ -184,14 +177,16 @@ class OrganizationSerializer(serializers.ModelSerializer): extra_kwargs = {} def to_representation(self, instance): + """ Custom output """ representation = super().to_representation(instance) if isinstance(instance, Organization): representation['province'] = ProvinceSerializer(instance.province).data representation['city'] = CitySerializer(instance.city).data representation['type'] = OrganizationTypeSerializer(instance.type).data if instance.parent_organization: - representation['parent_organization'] = OrganizationSerializer(instance.parent_organization).data - + representation['parent_organization'] = OrganizationSerializer( + instance.parent_organization + ).data return representation def update(self, instance, validated_data): diff --git a/apps/authorization/api/v1/serializers.py b/apps/authorization/api/v1/serializers.py index 5afbb0c..389ed46 100644 --- a/apps/authorization/api/v1/serializers.py +++ b/apps/authorization/api/v1/serializers.py @@ -111,6 +111,12 @@ class UserRelationSerializer(serializers.ModelSerializer): 'permissions', ] + extra_kwargs = { + 'organization': { + 'required': False + } + } + def to_representation(self, instance): """ custom output for serializer """ representation = super().to_representation(instance) diff --git a/apps/product/migrations/0007_remove_attribute_reference_product_and_more.py b/apps/product/migrations/0007_remove_attribute_reference_product_and_more.py new file mode 100644 index 0000000..fd8c1ef --- /dev/null +++ b/apps/product/migrations/0007_remove_attribute_reference_product_and_more.py @@ -0,0 +1,32 @@ +# Generated by Django 5.0 on 2025-06-09 10:13 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('product', '0006_alter_saleunit_unit_and_more'), + ] + + operations = [ + migrations.RemoveField( + model_name='attribute', + name='reference_product', + ), + migrations.RemoveField( + model_name='saleunit', + name='reference_product', + ), + migrations.RemoveField( + model_name='product', + name='reference', + ), + migrations.RemoveField( + model_name='broker', + name='reference_product', + ), + migrations.DeleteModel( + name='ReferenceProduct', + ), + ] diff --git a/apps/product/migrations/0008_incentiveplan_remove_attributevalue_product_and_more.py b/apps/product/migrations/0008_incentiveplan_remove_attributevalue_product_and_more.py new file mode 100644 index 0000000..0971a1e --- /dev/null +++ b/apps/product/migrations/0008_incentiveplan_remove_attributevalue_product_and_more.py @@ -0,0 +1,132 @@ +# Generated by Django 5.0 on 2025-06-09 12:38 + +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 = [ + ('product', '0007_remove_attribute_reference_product_and_more'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='IncentivePlan', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255)), + ('description', models.TextField(blank=True, null=True)), + ], + ), + migrations.RemoveField( + model_name='attributevalue', + name='product', + ), + migrations.AddField( + model_name='attribute', + name='is_global', + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name='attribute', + name='product', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='attributes', to='product.product'), + ), + migrations.AddField( + model_name='broker', + name='product', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='product_broker', to='product.product'), + ), + migrations.AddField( + model_name='saleunit', + name='product', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='sale_unit', to='product.product'), + ), + migrations.AlterField( + model_name='attributevalue', + name='attribute', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='values', to='product.attribute'), + ), + migrations.CreateModel( + name='ProductCategory', + 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)), + ('name', models.CharField(default='empty', max_length=250)), + ('type', models.CharField(choices=[('F', 'Free'), ('G', 'Governmental')], default='empty', max_length=3)), + ('img', models.CharField(default='empty', max_length=100)), + ('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)), + ('parent', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='parents', to='product.productcategory')), + ], + options={ + 'abstract': False, + }, + ), + migrations.AddField( + model_name='product', + name='category', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='products', to='product.productcategory'), + ), + migrations.CreateModel( + name='Quota', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('sale_type', models.CharField(choices=[('free', 'آزاد'), ('gov', 'دولتی')], max_length=50)), + ('month_choices', django.contrib.postgres.fields.ArrayField(base_field=models.IntegerField(), null=True, size=None)), + ('group', models.CharField(choices=[('roostaei', 'روستایی'), ('sanati', 'صنعتی'), ('ashayeri', 'عشایری')], max_length=50)), + ('has_distribution_limit', models.BooleanField(default=False)), + ('distribution_mode', models.CharField(blank=True, max_length=50, null=True)), + ('base_price_factory', models.DecimalField(decimal_places=2, max_digits=12)), + ('base_price_cooperative', models.DecimalField(decimal_places=2, max_digits=12)), + ('final_price', models.DecimalField(blank=True, decimal_places=2, max_digits=12, null=True)), + ('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='quota', to='product.product')), + ], + ), + migrations.AddField( + model_name='attributevalue', + name='quota', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='attribute_values', to='product.quota'), + ), + migrations.CreateModel( + name='QuotaBrokerValue', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('value', models.DecimalField(decimal_places=2, max_digits=12)), + ('broker', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='values', to='product.broker')), + ('quota', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='broker_values', to='product.quota')), + ], + ), + migrations.CreateModel( + name='QuotaIncentiveAssignment', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('heavy_value', models.DecimalField(decimal_places=2, max_digits=12)), + ('light_value', models.DecimalField(decimal_places=2, max_digits=12)), + ('incentive_plan', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='quota_assignment', to='product.incentiveplan')), + ('quota', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='incentive_assignments', to='product.quota')), + ], + ), + migrations.CreateModel( + name='QuotaLivestockAllocation', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('livestock_group', models.CharField(choices=[('roostaei', 'روستایی'), ('sanati', 'صنعتی'), ('ashayeri', 'عشایری')], max_length=20)), + ('livestock_type', models.CharField(choices=[('light', 'سبک'), ('heavy', 'سنگین')], max_length=20)), + ('livestock_subtype', models.CharField(choices=[('milking', 'شیری'), ('fattening', 'پرواری')], max_length=20)), + ('quantity_kg', models.DecimalField(decimal_places=2, max_digits=12)), + ('quota', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='livestock_allocations', to='product.quota')), + ], + options={ + 'unique_together': {('quota', 'livestock_group', 'livestock_type', 'livestock_subtype')}, + }, + ), + ] diff --git a/apps/product/models.py b/apps/product/models.py index 1f40982..b82d57e 100644 --- a/apps/product/models.py +++ b/apps/product/models.py @@ -1,26 +1,49 @@ from django.db import models from apps.core.models import BaseModel from apps.authorization.models import UserRelations +from django.contrib.postgres.fields import ArrayField + + +class LivestockGroup(models.TextChoices): + ROOSTAEI = "roostaei", "روستایی" # noqa + SANATI = "sanati", "صنعتی" # noqa + ASHAYERI = "ashayeri", "عشایری" # noqa + + +class LivestockType(models.TextChoices): + LIGHT = "light", "سبک" + HEAVY = "heavy", "سنگین" # noqa + + +class LivestockSubtype(models.TextChoices): + MILKING = "milking", "شیری" # noqa + FATTENING = "fattening", "پرواری" # noqa # Create your models here. -class ReferenceProduct(BaseModel): - """ Reference product - like: rice """ +class ProductCategory(BaseModel): + """ Category for products """ name = models.CharField(max_length=250, default='empty') # noqa type_choices = ( ('F', 'Free'), # free product ('G', 'Governmental') # government product ) - type = models.CharField(max_length=3, choices=type_choices) + type = models.CharField(max_length=3, choices=type_choices, default='empty') img = models.CharField(max_length=100, default='empty') + parent = models.ForeignKey( + 'self', + on_delete=models.CASCADE, + related_name='parents', + null=True + ) def __str__(self): return f'name: {self.name} - type: {self.type}' def save(self, *args, **kwargs): - super(ReferenceProduct, self).save(*args, **kwargs) + super(ProductCategory, self).save(*args, **kwargs) class Product(BaseModel): @@ -28,14 +51,14 @@ class Product(BaseModel): name = models.CharField(max_length=250, default='empty') # noqa type_choices = ( ('F', 'Free'), # free product - ('G', 'Governmental') # + ('G', 'Governmental') # government product ) type = models.CharField(max_length=3, choices=type_choices) img = models.CharField(max_length=100, default='empty') - reference = models.ForeignKey( - ReferenceProduct, + category = models.ForeignKey( + ProductCategory, on_delete=models.CASCADE, - related_name='reference_product', + related_name='products', null=True ) @@ -50,10 +73,10 @@ class Attribute(BaseModel): """ every reference product have multiple attributes """ - reference_product = models.ForeignKey( - ReferenceProduct, + product = models.ForeignKey( + Product, on_delete=models.CASCADE, - related_name='reference_attribute', + related_name='attributes', null=True ) name = models.CharField(max_length=100, default='empty') @@ -68,8 +91,10 @@ class Attribute(BaseModel): help_text='type of attribute like: calculate product by kilogram' ) + is_global = models.BooleanField(default=False) + def __str__(self): - return f'{self.reference_product.name} - {self.name}' + return f'{self.product.name} - {self.name}' def save(self, *args, **kwargs): return super(Attribute, self).save(*args, **kwargs) @@ -80,22 +105,23 @@ class AttributeValue(BaseModel): every child product should have attribute value for reference product attribute """ - product = models.ForeignKey( - Product, + + quota = models.ForeignKey( + 'Quota', on_delete=models.CASCADE, - related_name='product_attribute_value', + related_name='attribute_values', null=True ) attribute = models.ForeignKey( Attribute, on_delete=models.CASCADE, - related_name='attribute_value', + related_name='values', null=True ) value = models.IntegerField(default=0) def __str__(self): - return f'{self.product.name} - {self.attribute.name} - {self.value}' + return f'Quota({self.quota.id}) - {self.attribute.name} - {self.value}' def save(self, *args, **kwargs): return super(AttributeValue, self).save(*args, **kwargs) @@ -104,8 +130,8 @@ class AttributeValue(BaseModel): class Broker(BaseModel): """ Broker for product """ - reference_product = models.ForeignKey( - ReferenceProduct, + product = models.ForeignKey( + Product, on_delete=models.CASCADE, related_name='product_broker', null=True @@ -128,7 +154,7 @@ class Broker(BaseModel): required = models.BooleanField(default=False) def __str__(self): - return f'{self.organization_relations.organization.name} - {self.reference_product.name}' + return f'{self.organization_relations.organization.name} - {self.product.name}' def save(self, *args, **kwargs): return super(Broker, self).save(*args, **kwargs) @@ -137,8 +163,8 @@ class Broker(BaseModel): class SaleUnit(BaseModel): """ Units of product for sale """ - reference_product = models.ForeignKey( - ReferenceProduct, + product = models.ForeignKey( + Product, on_delete=models.CASCADE, related_name='sale_unit', null=True @@ -153,4 +179,109 @@ class SaleUnit(BaseModel): required = models.BooleanField(default=False) def __str__(self): - return f'{self.reference_product} - {self.unit} - {self.variation_coefficient}' + return f'{self.product.name} - {self.unit} - {self.variation_coefficient}' + + def save(self, *args, **kwargs): + return super(SaleUnit, self).save(*args, **kwargs) + + +class IncentivePlan(models.Model): + name = models.CharField(max_length=255) + description = models.TextField(blank=True, null=True) + + def __str__(self): + return self.name + + def save(self, *args, **kwargs): + return super(IncentivePlan, self).save(*args, **kwargs) + + +class Quota(models.Model): + product = models.ForeignKey( + Product, + on_delete=models.CASCADE, + related_name='quota' + ) + sale_type = models.CharField(max_length=50, choices=[("free", "آزاد"), ("gov", "دولتی")]) # noqa + month_choices = ArrayField(base_field=models.IntegerField(), null=True) + group = models.CharField( + max_length=50, + choices=[("roostaei", "روستایی"), ("sanati", "صنعتی"), ("ashayeri", "عشایری")] # noqa + ) + has_distribution_limit = models.BooleanField(default=False) + distribution_mode = models.CharField(max_length=50, blank=True, null=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) + + def __str__(self): + return f"Quota ({self.id}) for {self.product.name}" + + def save(self, *args, **kwargs): + return super(Quota, self).save(*args, **kwargs) + + +class QuotaIncentiveAssignment(models.Model): + quota = models.ForeignKey( + Quota, + on_delete=models.CASCADE, + related_name="incentive_assignments", + null=True + ) + incentive_plan = models.ForeignKey( + IncentivePlan, + on_delete=models.CASCADE, + related_name='quota_assignment' + ) + heavy_value = models.DecimalField(max_digits=12, decimal_places=2) + light_value = models.DecimalField(max_digits=12, decimal_places=2) + + def __str__(self): + return f"Quota ({self.quota.id}) for {self.incentive_plan.name}" + + def save(self, *args, **kwargs): + return super(QuotaIncentiveAssignment, self).save(*args, **kwargs) + + +class QuotaBrokerValue(models.Model): + quota = models.ForeignKey( + Quota, + on_delete=models.CASCADE, + related_name="broker_values", + null=True + ) + broker = models.ForeignKey( + Broker, + on_delete=models.CASCADE, + related_name='values' + ) + 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})" + + def save(self, *args, **kwargs): + return super(QuotaBrokerValue, self).save(*args, **kwargs) + + +class QuotaLivestockAllocation(models.Model): + quota = models.ForeignKey( + "Quota", + on_delete=models.CASCADE, + 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) + + 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" + + def save(self, *args, **kwargs): + return super(QuotaLivestockAllocation, self).save(*args, **kwargs) diff --git a/apps/product/web/api/v1/api.py b/apps/product/web/api/v1/api.py index 3e1aebd..5bbf5a7 100644 --- a/apps/product/web/api/v1/api.py +++ b/apps/product/web/api/v1/api.py @@ -57,42 +57,6 @@ class ProductViewSet(viewsets.ModelViewSet): return Response(e, status=status.HTTP_204_NO_CONTENT) -class ReferenceProductViewSet(viewsets.ModelViewSet): - queryset = product_models.ReferenceProduct.objects.all() - serializer_class = product_serializers.ReferenceProductSerializer - - @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 AttributeViewSet(viewsets.ModelViewSet): """ attributes of reference product """ @@ -243,3 +207,193 @@ class SaleUnitViewSet(viewsets.ModelViewSet): return Response(status=status.HTTP_200_OK) except APIException as e: return Response(e, status=status.HTTP_204_NO_CONTENT) + + +class IncentivePlanViewSet(viewsets.ModelViewSet): + """ apis for incentive plan """ + + queryset = product_models.IncentivePlan.objects.all() + serializer_class = product_serializers.IncentivePlanSerializer + + @action( + methods=['put'], + detail=True, + url_path='trash', + url_name='trash', + name='trash', + ) + @transaction.atomic + def trash(self, request, pk=None): + """ Sent incentive plan 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 incentive plan 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 QuotaViewSet(viewsets.ModelViewSet): + """ apis for product quota """ + + queryset = product_models.Quota.objects.all() + serializer_class = product_serializers.QuotaSerializer + + @action( + methods=['put'], + detail=True, + url_path='trash', + url_name='trash', + name='trash', + ) + @transaction.atomic + def trash(self, request, pk=None): + """ Sent quota 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 quota 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 QuotaIncentiveAssignmentViewSet(viewsets.ModelViewSet): + """ apis for incentive assignment """ + + queryset = product_models.QuotaIncentiveAssignment.objects.all() + serializer_class = product_serializers.QuotaIncentiveAssignmentSerializer + + @action( + methods=['put'], + detail=True, + url_path='trash', + url_name='trash', + name='trash', + ) + @transaction.atomic + def trash(self, request, pk=None): + """ Sent quota incentive assignment 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 quota incentive assignment 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 QuotaBrokerValueViewSet(viewsets.ModelViewSet): # noqa + """ apis for quota broker value """ + + queryset = product_models.QuotaBrokerValue.objects.all() + serializer_class = product_serializers.QuotaBrokerValueSerializer + + @action( + methods=['put'], + detail=True, + url_path='trash', + url_name='trash', + name='trash', + ) + @transaction.atomic + def trash(self, request, pk=None): + """ Sent quota broker value 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 quota broker value 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 QuotaLiveStockAllocationViewSet(viewsets.ModelViewSet): + """ apis for quota livestock allocation """ + + queryset = product_models.QuotaLivestockAllocation.objects.all() + serializer_class = product_serializers.QuotaLiveStockAllocationSerializer + + @action( + methods=['put'], + detail=True, + url_path='trash', + url_name='trash', + name='trash', + ) + @transaction.atomic + def trash(self, request, pk=None): + """ Sent quota livestock allocation 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 quota livestock allocation 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) diff --git a/apps/product/web/api/v1/serializers.py b/apps/product/web/api/v1/serializers.py index 6dc91a0..1dde421 100644 --- a/apps/product/web/api/v1/serializers.py +++ b/apps/product/web/api/v1/serializers.py @@ -3,14 +3,6 @@ from apps.product import models as product_models from apps.authorization.api.v1 import serializers as authorize_serializers -class ReferenceProductSerializer(serializers.ModelSerializer): - """ Serializer of reference product """ - - class Meta: - model = product_models.ReferenceProduct - fields = '__all__' - - class ProductSerializer(serializers.ModelSerializer): """ Serializer of product """ @@ -22,8 +14,6 @@ class ProductSerializer(serializers.ModelSerializer): """ Custom output of product serializer """ representation = super().to_representation(instance) - if instance.reference: - representation['reference'] = ReferenceProductSerializer(instance.reference).data return representation @@ -37,11 +27,6 @@ class AttributeSerializer(serializers.ModelSerializer): def to_representation(self, instance): representation = super().to_representation(instance) - if instance.reference_product: - representation['reference_product'] = ReferenceProductSerializer( - instance.reference_product - ).data - return representation @@ -73,10 +58,6 @@ class BrokerSerializer(serializers.ModelSerializer): def to_representation(self, instance): representation = super().to_representation(instance) - if instance.reference_product: - representation['reference_product'] = ReferenceProductSerializer( - instance.reference_product - ).data if instance.organization_relations: representation['organization_relations'] = authorize_serializers.UserRelationSerializer( instance.organization_relations @@ -94,9 +75,34 @@ class SaleUnitSerializer(serializers.ModelSerializer): def to_representation(self, instance): representation = super().to_representation(instance) - if instance.reference_product: - representation['reference_product'] = ReferenceProductSerializer( - instance.reference_product - ).data - return representation + + +class IncentivePlanSerializer(serializers.ModelSerializer): + class Meta: + model = product_models.IncentivePlan + fields = '__all_' + + +class QuotaSerializer(serializers.ModelSerializer): + class Meta: + model = product_models.Quota + fields = '__all__' + + +class QuotaIncentiveAssignmentSerializer(serializers.ModelSerializer): + class Meta: + model = product_models.QuotaIncentiveAssignment + fields = '__all__' + + +class QuotaBrokerValueSerializer(serializers.ModelSerializer): + class Meta: + model = product_models.QuotaBrokerValue + fields = '__all__' + + +class QuotaLiveStockAllocationSerializer(serializers.ModelSerializer): + class Meta: + model = product_models.QuotaLivestockAllocation + fields = '__all__' diff --git a/apps/product/web/api/v1/urls.py b/apps/product/web/api/v1/urls.py index 3f85369..d4f74f1 100644 --- a/apps/product/web/api/v1/urls.py +++ b/apps/product/web/api/v1/urls.py @@ -4,7 +4,6 @@ from django.urls import path, include router = DefaultRouter() router.register(r'product', api_views.ProductViewSet, basename='product') -router.register(r'reference', api_views.ReferenceProductViewSet, basename='reference') 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')