rancher incentive plan

This commit is contained in:
2025-09-23 15:46:05 +03:30
parent 607a59a900
commit 73111950b4
5 changed files with 92 additions and 9 deletions

View File

@@ -0,0 +1,39 @@
# Generated by Django 5.0 on 2025-09-23 12:12
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('herd', '0018_rancher_dhi_state'),
('livestock', '0015_livestocktype_en_name_alter_livestocktype_name'),
('product', '0075_historicalquotadistribution_free_sale_balance_and_more'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='IncentivePlanRancher',
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)),
('allowed_quantity', models.PositiveBigIntegerField(default=0)),
('used_quantity', models.PositiveBigIntegerField(default=0)),
('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)),
('livestock_type', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='rancher_plans', to='livestock.livestocktype')),
('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)),
('plan', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='rancher_plans', to='product.incentiveplan')),
('rancher', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='plans', to='herd.rancher')),
],
options={
'abstract': False,
},
),
]

View File

@@ -6,6 +6,7 @@ from apps.authorization.models import UserRelations
from apps.authentication.models import OrganizationType, Organization from apps.authentication.models import OrganizationType, Organization
from django.contrib.postgres.fields import ArrayField from django.contrib.postgres.fields import ArrayField
from apps.livestock.models import LiveStockType from apps.livestock.models import LiveStockType
from apps.herd.models import Rancher
from datetime import datetime from datetime import datetime
import jdatetime import jdatetime
@@ -312,6 +313,35 @@ class IncentivePlan(BaseModel):
return super(IncentivePlan, self).save(*args, **kwargs) return super(IncentivePlan, self).save(*args, **kwargs)
class IncentivePlanRancher(BaseModel):
plan = models.ForeignKey(
IncentivePlan,
on_delete=models.CASCADE,
related_name='rancher_plans',
null=True
)
rancher = models.ForeignKey(
Rancher,
on_delete=models.CASCADE,
related_name='plans',
null=True
)
livestock_type = models.ForeignKey(
LiveStockType,
on_delete=models.CASCADE,
related_name='rancher_plans',
null=True
)
allowed_quantity = models.PositiveBigIntegerField(default=0)
used_quantity = models.PositiveBigIntegerField(default=0)
def __str__(self):
return f'{self.plan.name}-{self.rancher.first_name}-{self.livestock_type.name}'
def save(self, *args, **kwargs):
return super(IncentivePlanRancher, self).save(*args, **kwargs)
class Quota(BaseModel): class Quota(BaseModel):
""" quota for product with some conditions """ """ quota for product with some conditions """
@@ -428,7 +458,7 @@ class QuotaStats(BaseModel):
def __str__(self): def __str__(self):
return f'Quota: {self.quota.quota_id} stats' return f'Quota: {self.quota.quota_id} stats'
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
return super(QuotaStats, self).save(*args, **kwargs) return super(QuotaStats, self).save(*args, **kwargs)

View File

@@ -155,3 +155,9 @@ class IncentivePlanSerializer(serializers.ModelSerializer): # noqa
class Meta: class Meta:
model = product_models.IncentivePlan model = product_models.IncentivePlan
fields = '__all__' fields = '__all__'
class IncentivePlanRancherSerializer(serializers.ModelSerializer):
class Meta:
model = product_models.IncentivePlanRancher
fields = '__all__'

View File

@@ -14,6 +14,7 @@ router.register(r'attribute_value', product_api.AttributeValueViewSet, basename=
router.register(r'broker', product_api.BrokerViewSet, basename='broker') router.register(r'broker', product_api.BrokerViewSet, basename='broker')
router.register(r'sale_unit', product_api.SaleUnitViewSet, basename='sale_unit') router.register(r'sale_unit', product_api.SaleUnitViewSet, basename='sale_unit')
router.register(r'incentive_plan', product_api.IncentivePlanViewSet, basename='incentive_plan') router.register(r'incentive_plan', product_api.IncentivePlanViewSet, basename='incentive_plan')
router.register(r'rancher_incentive_plan', product_api.IncentivePlanRancherViewSet, basename='rancher_incentive_plan')
router.register(r'stats', product_api.ProductStatsViewSet, basename='stats') router.register(r'stats', product_api.ProductStatsViewSet, basename='stats')
router.register(r'quota', quota_api.QuotaViewSet, basename='quota') router.register(r'quota', quota_api.QuotaViewSet, basename='quota')
router.register(r'quota_distribution', distribution_apis.QuotaDistributionViewSet, basename='quota_distribution') router.register(r'quota_distribution', distribution_apis.QuotaDistributionViewSet, basename='quota_distribution')

View File

@@ -2,12 +2,14 @@ import datetime
from apps.product.web.api.v1.serializers import product_serializers as product_serializers from apps.product.web.api.v1.serializers import product_serializers as product_serializers
from apps.product.web.api.v1.serializers import quota_serializers from apps.product.web.api.v1.serializers import quota_serializers
from apps.core.mixins.soft_delete_mixin import SoftDeleteMixin from apps.core.mixins.soft_delete_mixin import SoftDeleteMixin
from apps.core.mixins.search_mixin import DynamicSearchMixin
from common.helpers import get_organization_by_user from common.helpers import get_organization_by_user
from rest_framework.exceptions import APIException from rest_framework.exceptions import APIException
from apps.product import models as product_models from apps.product import models as product_models
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework import viewsets, filters from rest_framework import viewsets, filters
from common.tools import CustomOperations
from rest_framework import status from rest_framework import status
from django.db import transaction from django.db import transaction
from django.db.models import Q from django.db.models import Q
@@ -27,7 +29,7 @@ def delete(queryset, pk):
obj.delete() obj.delete()
class ProductCategoryViewSet(viewsets.ModelViewSet, SoftDeleteMixin): class ProductCategoryViewSet(viewsets.ModelViewSet, SoftDeleteMixin, DynamicSearchMixin):
queryset = product_models.ProductCategory.objects.all() queryset = product_models.ProductCategory.objects.all()
serializer_class = product_serializers.ProductCategorySerializer serializer_class = product_serializers.ProductCategorySerializer
filter_backends = [filters.SearchFilter] filter_backends = [filters.SearchFilter]
@@ -65,7 +67,7 @@ class ProductCategoryViewSet(viewsets.ModelViewSet, SoftDeleteMixin):
return Response(e, status=status.HTTP_204_NO_CONTENT) return Response(e, status=status.HTTP_204_NO_CONTENT)
class ProductViewSet(viewsets.ModelViewSet, SoftDeleteMixin): class ProductViewSet(viewsets.ModelViewSet, SoftDeleteMixin, DynamicSearchMixin):
queryset = product_models.Product.objects.all() queryset = product_models.Product.objects.all()
serializer_class = product_serializers.ProductSerializer serializer_class = product_serializers.ProductSerializer
filter_backends = [filters.SearchFilter] filter_backends = [filters.SearchFilter]
@@ -144,7 +146,7 @@ class ProductViewSet(viewsets.ModelViewSet, SoftDeleteMixin):
return Response(e, status=status.HTTP_204_NO_CONTENT) return Response(e, status=status.HTTP_204_NO_CONTENT)
class ProductStatsViewSet(viewsets.ModelViewSet, SoftDeleteMixin): class ProductStatsViewSet(viewsets.ModelViewSet, SoftDeleteMixin, DynamicSearchMixin):
""" product statistics by its quotas """ """ product statistics by its quotas """
queryset = product_models.ProductStats.objects.all() queryset = product_models.ProductStats.objects.all()
@@ -175,7 +177,7 @@ class ProductStatsViewSet(viewsets.ModelViewSet, SoftDeleteMixin):
raise e raise e
class AttributeViewSet(viewsets.ModelViewSet, SoftDeleteMixin): class AttributeViewSet(viewsets.ModelViewSet, SoftDeleteMixin, DynamicSearchMixin):
""" attributes of reference product """ # """ attributes of reference product """ #
queryset = product_models.Attribute.objects.select_related('product').all() queryset = product_models.Attribute.objects.select_related('product').all()
@@ -233,7 +235,7 @@ class AttributeViewSet(viewsets.ModelViewSet, SoftDeleteMixin):
return Response(e, status=status.HTTP_204_NO_CONTENT) return Response(e, status=status.HTTP_204_NO_CONTENT)
class AttributeValueViewSet(viewsets.ModelViewSet, SoftDeleteMixin): class AttributeValueViewSet(viewsets.ModelViewSet, SoftDeleteMixin, DynamicSearchMixin):
""" apis for attribute values of child products """ # noqa """ apis for attribute values of child products """ # noqa
queryset = product_models.AttributeValue.objects.all() queryset = product_models.AttributeValue.objects.all()
@@ -271,7 +273,7 @@ class AttributeValueViewSet(viewsets.ModelViewSet, SoftDeleteMixin):
return Response(e, status=status.HTTP_204_NO_CONTENT) return Response(e, status=status.HTTP_204_NO_CONTENT)
class BrokerViewSet(viewsets.ModelViewSet, SoftDeleteMixin): class BrokerViewSet(viewsets.ModelViewSet, SoftDeleteMixin, DynamicSearchMixin):
""" apis of product brokers """ # noqa """ apis of product brokers """ # noqa
queryset = product_models.Broker.objects.all() queryset = product_models.Broker.objects.all()
@@ -311,7 +313,7 @@ class BrokerViewSet(viewsets.ModelViewSet, SoftDeleteMixin):
return Response(e, status=status.HTTP_204_NO_CONTENT) return Response(e, status=status.HTTP_204_NO_CONTENT)
class SaleUnitViewSet(viewsets.ModelViewSet, SoftDeleteMixin): class SaleUnitViewSet(viewsets.ModelViewSet, SoftDeleteMixin, DynamicSearchMixin):
""" apis of unit of sale for products """ # noqa """ apis of unit of sale for products """ # noqa
queryset = product_models.SaleUnit.objects.all() queryset = product_models.SaleUnit.objects.all()
@@ -351,7 +353,7 @@ class SaleUnitViewSet(viewsets.ModelViewSet, SoftDeleteMixin):
return Response(e, status=status.HTTP_204_NO_CONTENT) return Response(e, status=status.HTTP_204_NO_CONTENT)
class IncentivePlanViewSet(viewsets.ModelViewSet, SoftDeleteMixin): # noqa class IncentivePlanViewSet(viewsets.ModelViewSet, SoftDeleteMixin, DynamicSearchMixin): # noqa
""" apis for incentive plan """ """ apis for incentive plan """
queryset = product_models.IncentivePlan.objects.all() queryset = product_models.IncentivePlan.objects.all()
@@ -439,3 +441,8 @@ class IncentivePlanViewSet(viewsets.ModelViewSet, SoftDeleteMixin): # noqa
return Response(status=status.HTTP_200_OK) return Response(status=status.HTTP_200_OK)
except APIException as e: except APIException as e:
return Response(e, status=status.HTTP_204_NO_CONTENT) return Response(e, status=status.HTTP_204_NO_CONTENT)
class IncentivePlanRancherViewSet(viewsets.ModelViewSet, SoftDeleteMixin, DynamicSearchMixin):
queryset = product_models.IncentivePlanRancher.objects.all()
serializer_class = product_serializers.IncentivePlanRancherSerializer