add purchace limitations system for rancher - add incentive plans to rancher entries data
This commit is contained in:
@@ -9,3 +9,11 @@ class TokenBlackListedException(APIException):
|
||||
status_code = status.HTTP_401_UNAUTHORIZED
|
||||
default_detail = _('unauthorized')
|
||||
default_code = 'unauthorized'
|
||||
|
||||
|
||||
class OrganizationBankAccountException(APIException):
|
||||
""" if organization does not have bank account """
|
||||
|
||||
status_code = status.HTTP_403_FORBIDDEN
|
||||
default_detail = "برای این سازمان حساب بانکی تعریف نشده است, ابتدا حساب بانکی تعریف کنید" # noqa
|
||||
default_code = "برای این سازمان حساب بانکی تعریف نشده است" # noqa
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
from rest_framework import viewsets
|
||||
from apps.core.models import MobileTest
|
||||
from apps.core.serializers import MobileTestSerializer, SystemConfigSerializer
|
||||
from apps.core.models import MobileTest, SystemConfig
|
||||
from rest_framework.response import Response
|
||||
from apps.core.serializers import MobileTestSerializer
|
||||
from rest_framework import viewsets
|
||||
|
||||
|
||||
class MobileTestViewSet(viewsets.ModelViewSet):
|
||||
queryset = MobileTest.objects.all()
|
||||
serializer_class = MobileTestSerializer
|
||||
|
||||
|
||||
class SystemConfigViewSet(viewsets.ModelViewSet):
|
||||
queryset = SystemConfig.objects.all()
|
||||
serializer_class = SystemConfigSerializer
|
||||
|
||||
34
apps/core/migrations/0007_systemconfig.py
Normal file
34
apps/core/migrations/0007_systemconfig.py
Normal file
@@ -0,0 +1,34 @@
|
||||
# Generated by Django 5.0 on 2025-08-26 07:49
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0006_mobiletest_creator_info_mobiletest_modifier_info'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='SystemConfig',
|
||||
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)),
|
||||
('key', models.CharField(max_length=100, null=True)),
|
||||
('value', models.CharField(max_length=100, null=True)),
|
||||
('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,
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -44,3 +44,15 @@ class MobileTest(BaseModel):
|
||||
longitude = models.DecimalField(max_digits=22, decimal_places=16)
|
||||
count = models.IntegerField(default=0)
|
||||
time = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
|
||||
class SystemConfig(BaseModel):
|
||||
key = models.CharField(max_length=100, null=True)
|
||||
value = models.CharField(max_length=100, null=True)
|
||||
|
||||
@classmethod
|
||||
def get(cls, key, default=None):
|
||||
try:
|
||||
return cls.objects.get(key=key).value
|
||||
except cls.DoesNotExist:
|
||||
return default
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from apps.core.models import MobileTest
|
||||
from apps.core.models import MobileTest, SystemConfig
|
||||
from rest_framework import serializers
|
||||
|
||||
|
||||
@@ -6,3 +6,9 @@ class MobileTestSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = MobileTest
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
class SystemConfigSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = SystemConfig
|
||||
fields = '__all__'
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
from apps.core.api import MobileTestViewSet, SystemConfigViewSet
|
||||
from rest_framework.routers import DefaultRouter
|
||||
from apps.core.api import MobileTestViewSet
|
||||
from django.urls import path, include
|
||||
|
||||
router = DefaultRouter()
|
||||
router.register('mobile_test', MobileTestViewSet, basename='mobile_test')
|
||||
router.register('system_config', SystemConfigViewSet, basename='system_config')
|
||||
app_name = "core"
|
||||
|
||||
urlpatterns = [
|
||||
|
||||
18
apps/herd/migrations/0017_rancher_ignore_purchase_limit.py
Normal file
18
apps/herd/migrations/0017_rancher_ignore_purchase_limit.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.0 on 2025-08-26 07:49
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('herd', '0016_rancher_activity_rancher_heavy_livestock_number_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='rancher',
|
||||
name='ignore_purchase_limit',
|
||||
field=models.BooleanField(default=False, help_text='if its true rancher has not buy limitations'),
|
||||
),
|
||||
]
|
||||
@@ -127,6 +127,9 @@ class Rancher(BaseModel):
|
||||
null=True
|
||||
)
|
||||
without_herd = models.BooleanField(default=False)
|
||||
ignore_purchase_limit = models.BooleanField(
|
||||
default=False, help_text="if its true rancher has not buy limitations"
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return f'rancher: {self.first_name} {self.last_name}'
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
from datetime import timedelta
|
||||
|
||||
from apps.pos_device.web.api.v1.serilaizers import device as device_serializer
|
||||
from apps.authentication.exceptions import OrganizationBankAccountException
|
||||
from apps.authorization.api.v1.serializers import UserRelationSerializer
|
||||
from apps.pos_device.web.api.v1.viewsets.client import POSClientViewSet
|
||||
from apps.authentication.api.v1.api import (
|
||||
UserViewSet,
|
||||
Organization,
|
||||
BankAccountInformation,
|
||||
OrganizationSerializer
|
||||
)
|
||||
from apps.core.mixins.search_mixin import DynamicSearchMixin
|
||||
@@ -176,10 +177,17 @@ class DeviceAssignmentViewSet(viewsets.ModelViewSet):
|
||||
|
||||
# if client will be an organization
|
||||
if request.data['client_data']['is_organization']:
|
||||
|
||||
# check if organization have bank account or raise exception
|
||||
if not BankAccountInformation.objects.filter(
|
||||
organization_id=request.data['client_data']['organization']
|
||||
).exists():
|
||||
raise OrganizationBankAccountException()
|
||||
|
||||
# check if organization is a client before
|
||||
client = pos_models.POSClient.objects.filter(
|
||||
organization_id=request.data['client_data']['organization']
|
||||
)
|
||||
|
||||
if client.exists():
|
||||
request.data.update({'client': client.first().id})
|
||||
|
||||
@@ -276,6 +284,13 @@ class StakeHoldersViewSet(viewsets.ModelViewSet, DynamicSearchMixin):
|
||||
|
||||
stakeholders_data = []
|
||||
for stakeholder in request.data['stakeholders']:
|
||||
|
||||
# check if organization have bank account or raise exception
|
||||
if not BankAccountInformation.objects.filter(
|
||||
organization_id=stakeholder['organization']
|
||||
).exists():
|
||||
raise OrganizationBankAccountException()
|
||||
|
||||
serializer = self.serializer_class(data=stakeholder)
|
||||
if serializer.is_valid():
|
||||
serializer.save()
|
||||
|
||||
@@ -22,6 +22,7 @@ def quota_live_stock_allocation_info(quota: Quota) -> typing.Any:
|
||||
|
||||
allocations = quota.livestock_allocations.filter(quota=quota)
|
||||
|
||||
if allocations:
|
||||
allocations_list = [{
|
||||
"name": alloc.livestock_type.name,
|
||||
"quantity": alloc.quantity_kg
|
||||
@@ -29,3 +30,17 @@ def quota_live_stock_allocation_info(quota: Quota) -> typing.Any:
|
||||
|
||||
return allocations_list
|
||||
|
||||
|
||||
def quota_incentive_plans_info(quota: Quota) -> typing.Any:
|
||||
""" information of quota incentive plans """
|
||||
|
||||
incentive_plans = quota.incentive_assignments.all()
|
||||
|
||||
if incentive_plans:
|
||||
incentive_plans_list = [{
|
||||
'name': plan.incentive_plan.name,
|
||||
'heavy_value': plan.heavy_value,
|
||||
'light_value': plan.light_value
|
||||
} for plan in incentive_plans]
|
||||
|
||||
return incentive_plans_list
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
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.product.services.services import (
|
||||
quota_live_stock_allocation_info,
|
||||
quota_incentive_plans_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 (
|
||||
@@ -46,7 +49,8 @@ class InventoryEntrySerializer(serializers.ModelSerializer):
|
||||
'quota_weight': instance.distribution.quota.quota_weight,
|
||||
'quota_livestock_allocations': quota_live_stock_allocation_info(
|
||||
instance.distribution.quota
|
||||
)
|
||||
),
|
||||
'quota_incentive_plans': quota_incentive_plans_info(instance.distribution.quota)
|
||||
}
|
||||
representation['product'] = {
|
||||
'name': instance.distribution.quota.product.name,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from apps.warehouse.models import InventoryEntry, InventoryQuotaSaleTransaction
|
||||
from apps.herd.services.services import rancher_quota_weight, get_rancher_statistics
|
||||
from apps.core.models import SystemConfig
|
||||
from django.db.models import Sum
|
||||
|
||||
|
||||
@@ -17,6 +18,12 @@ def get_total_sold(inventory_entry, rancher):
|
||||
def can_buy_from_inventory(rancher, inventory_entry: InventoryEntry):
|
||||
"""
|
||||
"""
|
||||
if SystemConfig.get("IGNORE_ALL_RANCHER_PURCHASE_LIMITS") == "true":
|
||||
return True
|
||||
|
||||
if rancher.ignore_purchase_limit:
|
||||
return True
|
||||
|
||||
quota_weight = rancher_quota_weight(rancher, inventory_entry) # {total, by_type}
|
||||
total_allowed = quota_weight['total']
|
||||
|
||||
|
||||
Reference in New Issue
Block a user