stake holders sharing & quota distribution to CMP - list of stake holder sharings
This commit is contained in:
@@ -3,12 +3,12 @@ from rest_framework.response import Response
|
|||||||
|
|
||||||
|
|
||||||
class SoftDeleteMixin:
|
class SoftDeleteMixin:
|
||||||
def destroy(self, request, *args, **kwargs):
|
def destroy(self, request, pk=None, *args, **kwargs):
|
||||||
""" override destroy -> soft delete """
|
""" override destroy -> soft delete """
|
||||||
|
|
||||||
instance = self.get_object() # noqa
|
instance = self.get_object() # noqa
|
||||||
instance.soft_delete()
|
instance.soft_delete()
|
||||||
return Response(
|
return Response(
|
||||||
{"detail": "رکورد با موفقیت حذف شد (Soft Delete)."},
|
{"detail": "رکورد با موفقیت حذف شد (Soft Delete)."}, # noqa
|
||||||
status=status.HTTP_200_OK
|
status=status.HTTP_200_OK
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# Generated by Django 5.0 on 2025-09-06 10:59
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('pos_device', '0066_stakeholders_stake_holder_type'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='stakeholders',
|
||||||
|
name='share_percent',
|
||||||
|
),
|
||||||
|
]
|
||||||
18
apps/pos_device/migrations/0068_stakeholders_share_amount.py
Normal file
18
apps/pos_device/migrations/0068_stakeholders_share_amount.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.0 on 2025-09-06 11:00
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('pos_device', '0067_remove_stakeholders_share_percent'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='stakeholders',
|
||||||
|
name='share_amount',
|
||||||
|
field=models.FloatField(default=0),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# Generated by Django 5.0 on 2025-09-06 11:42
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('pos_device', '0068_stakeholders_share_amount'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='stakeholders',
|
||||||
|
name='share_amount',
|
||||||
|
),
|
||||||
|
]
|
||||||
18
apps/pos_device/migrations/0070_stakeholders_share_amount.py
Normal file
18
apps/pos_device/migrations/0070_stakeholders_share_amount.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.0 on 2025-09-06 11:43
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('pos_device', '0069_remove_stakeholders_share_amount'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='stakeholders',
|
||||||
|
name='share_amount',
|
||||||
|
field=models.PositiveBigIntegerField(default=0),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
# Generated by Django 5.0 on 2025-09-06 13:25
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('pos_device', '0070_stakeholders_share_amount'),
|
||||||
|
('product', '0072_alter_quota_base_price_cooperative_and_more'),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='stakeholders',
|
||||||
|
name='broker_amount',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='stakeholders',
|
||||||
|
name='default',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='stakeholders',
|
||||||
|
name='share_amount',
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='StakeHolderShareAmount',
|
||||||
|
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)),
|
||||||
|
('share_amount', 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)),
|
||||||
|
('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)),
|
||||||
|
('quota_distribution', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='holders_share_amount', to='product.quotadistribution')),
|
||||||
|
('stakeholders', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='holders_share_amount', to='pos_device.stakeholders')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# Generated by Django 5.0 on 2025-09-07 10:19
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('authentication', '0036_organization_phone'),
|
||||||
|
('pos_device', '0071_remove_stakeholders_broker_amount_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='stakeholdershareamount',
|
||||||
|
name='registering_organization',
|
||||||
|
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='holders_share_amount', to='authentication.organization'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
from apps.product.models import Product, Broker, QuotaBrokerValue
|
from apps.product.models import Product, Broker, QuotaBrokerValue, QuotaDistribution
|
||||||
from django.contrib.postgres.fields import ArrayField
|
from django.contrib.postgres.fields import ArrayField
|
||||||
from apps.authorization.models import UserRelations
|
from apps.authorization.models import UserRelations
|
||||||
from apps.authentication.models import Organization
|
from apps.authentication.models import Organization
|
||||||
@@ -271,14 +271,6 @@ class StakeHolders(BaseModel):
|
|||||||
related_name='pos_stake_holders',
|
related_name='pos_stake_holders',
|
||||||
null=True
|
null=True
|
||||||
)
|
)
|
||||||
broker_amount = models.ForeignKey(
|
|
||||||
QuotaBrokerValue,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='pos_stake_holders',
|
|
||||||
null=True
|
|
||||||
)
|
|
||||||
share_percent = models.FloatField(default=0)
|
|
||||||
default = models.BooleanField(default=False)
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f'Device: {self.assignment.device.serial}-organization: {self.organization.name}'
|
return f'Device: {self.assignment.device.serial}-organization: {self.organization.name}'
|
||||||
@@ -287,6 +279,31 @@ class StakeHolders(BaseModel):
|
|||||||
return super(StakeHolders, self).save(*args, **kwargs)
|
return super(StakeHolders, self).save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class StakeHolderShareAmount(BaseModel):
|
||||||
|
quota_distribution = models.ForeignKey(
|
||||||
|
QuotaDistribution,
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
related_name='holders_share_amount',
|
||||||
|
null=True
|
||||||
|
)
|
||||||
|
stakeholders = models.ForeignKey(
|
||||||
|
StakeHolders,
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
related_name='holders_share_amount',
|
||||||
|
null=True
|
||||||
|
)
|
||||||
|
share_amount = models.PositiveBigIntegerField(default=0)
|
||||||
|
registering_organization = models.ForeignKey(
|
||||||
|
Organization,
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
related_name='holders_share_amount',
|
||||||
|
null=True
|
||||||
|
)
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
return super(StakeHolderShareAmount, self).save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class POSFreeProducts(BaseModel):
|
class POSFreeProducts(BaseModel):
|
||||||
product = models.ForeignKey(
|
product = models.ForeignKey(
|
||||||
Product,
|
Product,
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
from apps.pos_device.models import Device
|
from apps.pos_device.models import Device
|
||||||
|
from apps.product.models import Quota
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
|
|
||||||
def pos_organizations_sharing_information(device: Device) -> typing.Any:
|
def pos_organizations_sharing_information(device: Device, quota: Quota = None) -> typing.Any:
|
||||||
"""
|
"""
|
||||||
pos sharing organizations' information,
|
pos sharing organizations' information,
|
||||||
device have multiple organizations (sub_accounts) for sharing money
|
device have multiple organizations (sub_accounts) for sharing money
|
||||||
@@ -17,7 +18,9 @@ def pos_organizations_sharing_information(device: Device) -> typing.Any:
|
|||||||
"account": item.organization.bank_information.first().account,
|
"account": item.organization.bank_information.first().account,
|
||||||
} if item.organization.bank_information.exists() else {},
|
} if item.organization.bank_information.exists() else {},
|
||||||
"broker": item.broker.name if item.broker else None,
|
"broker": item.broker.name if item.broker else None,
|
||||||
"amount": item.broker_amount.value if item.broker else None
|
"amount": quota.broker_values.filter(
|
||||||
|
broker=item.broker
|
||||||
|
).first().value if quota and item.broker else item.share_amount
|
||||||
} for item in stake_holders]
|
} for item in stake_holders]
|
||||||
|
|
||||||
return sharing_information_list
|
return sharing_information_list
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
from apps.product.web.api.v1.serializers.quota_distribution_serializers import QuotaDistributionSerializer
|
||||||
from apps.authentication.api.v1.serializers.serializer import BankAccountSerializer
|
from apps.authentication.api.v1.serializers.serializer import BankAccountSerializer
|
||||||
from apps.pos_device.web.api.v1.serilaizers import client as client_serializer
|
from apps.pos_device.web.api.v1.serilaizers import client as client_serializer
|
||||||
from rest_framework.serializers import ModelSerializer
|
from rest_framework.serializers import ModelSerializer
|
||||||
@@ -85,4 +86,28 @@ class StakeHoldersSerializer(ModelSerializer):
|
|||||||
instance.organization.bank_information.all().first()
|
instance.organization.bank_information.all().first()
|
||||||
).data
|
).data
|
||||||
|
|
||||||
|
representation['organization'] = {
|
||||||
|
'name': instance.organization.name,
|
||||||
|
'id': instance.organization.id
|
||||||
|
}
|
||||||
|
|
||||||
|
return representation
|
||||||
|
|
||||||
|
|
||||||
|
class StakeHolderShareAmountSerializer(ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = pos_models.StakeHolderShareAmount
|
||||||
|
fields = '__all__'
|
||||||
|
|
||||||
|
def to_representation(self, instance):
|
||||||
|
representation = super().to_representation(instance)
|
||||||
|
|
||||||
|
# distribution information
|
||||||
|
representation['quota_distribution'] = QuotaDistributionSerializer(
|
||||||
|
instance.quota_distribution
|
||||||
|
).data
|
||||||
|
|
||||||
|
# stakeholders information
|
||||||
|
representation['stakeholders'] = StakeHoldersSerializer(instance.stakeholders).data
|
||||||
|
|
||||||
return representation
|
return representation
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ router.register(r'provider', device_views.ProviderCompanyViewSet, basename='prov
|
|||||||
router.register(r'device', device_views.DeviceViewSet, basename='device')
|
router.register(r'device', device_views.DeviceViewSet, basename='device')
|
||||||
router.register(r'device_assignment', device_views.DeviceAssignmentViewSet, basename='device_assignment')
|
router.register(r'device_assignment', device_views.DeviceAssignmentViewSet, basename='device_assignment')
|
||||||
router.register(r'stake_holders', device_views.StakeHoldersViewSet, basename='stake_holders')
|
router.register(r'stake_holders', device_views.StakeHoldersViewSet, basename='stake_holders')
|
||||||
|
router.register(r'holders_share', device_views.StakeHolderShareAmountViewSet, basename='holders_share')
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('v1/pos/', include(router.urls))
|
path('v1/pos/', include(router.urls))
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import random
|
import random
|
||||||
import string
|
import string
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
from apps.product.web.api.v1.viewsets.quota_distribution_api import QuotaDistributionViewSet
|
||||||
from apps.pos_device.web.api.v1.serilaizers import device as device_serializer
|
from apps.pos_device.web.api.v1.serilaizers import device as device_serializer
|
||||||
from apps.authentication.exceptions import OrganizationBankAccountException
|
from apps.authentication.exceptions import OrganizationBankAccountException
|
||||||
from apps.authorization.api.v1.serializers import UserRelationSerializer
|
from apps.authorization.api.v1.serializers import UserRelationSerializer
|
||||||
@@ -337,3 +337,102 @@ class StakeHoldersViewSet(viewsets.ModelViewSet, DynamicSearchMixin, SoftDeleteM
|
|||||||
serializer = self.get_serializer(page, many=True)
|
serializer = self.get_serializer(page, many=True)
|
||||||
return self.get_paginated_response(serializer.data)
|
return self.get_paginated_response(serializer.data)
|
||||||
|
|
||||||
|
@action(
|
||||||
|
methods=['get'],
|
||||||
|
detail=False,
|
||||||
|
url_path='list_by_organization',
|
||||||
|
url_name='list_by_organization',
|
||||||
|
name='list_by_organization',
|
||||||
|
)
|
||||||
|
def list_by_organization(self, request):
|
||||||
|
""" list of stakeholders by organization """
|
||||||
|
|
||||||
|
org = get_organization_by_user(request.user)
|
||||||
|
|
||||||
|
stakeholders = self.queryset.filter(
|
||||||
|
assignment__client__organization=org,
|
||||||
|
organization__type__key='CMP'
|
||||||
|
)
|
||||||
|
|
||||||
|
# paginate stakeholders
|
||||||
|
page = self.paginate_queryset(stakeholders)
|
||||||
|
if page is not None:
|
||||||
|
serializer = self.get_serializer(page, many=True)
|
||||||
|
return self.get_paginated_response(serializer.data)
|
||||||
|
|
||||||
|
|
||||||
|
class StakeHolderShareAmountViewSet(viewsets.ModelViewSet, DynamicSearchMixin, SoftDeleteMixin):
|
||||||
|
queryset = pos_models.StakeHolderShareAmount.objects.select_related('quota_distribution', 'stakeholders')
|
||||||
|
serializer_class = device_serializer.StakeHolderShareAmountSerializer
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
|
def create(self, request, *args, **kwargs):
|
||||||
|
""" create share amount for company stakeholders """
|
||||||
|
|
||||||
|
data = request.data.copy()
|
||||||
|
|
||||||
|
organization = get_organization_by_user(request.user)
|
||||||
|
data.update({'registering_organization': organization.id})
|
||||||
|
|
||||||
|
assigner_organization = get_organization_by_user(request.user)
|
||||||
|
data['distribution'].update({'assigner_organization': assigner_organization.id})
|
||||||
|
|
||||||
|
# create distribution
|
||||||
|
if 'distribution' in data.keys():
|
||||||
|
distribution = CustomOperations().custom_create(
|
||||||
|
request=request,
|
||||||
|
view=QuotaDistributionViewSet(),
|
||||||
|
data=data['distribution']
|
||||||
|
)
|
||||||
|
data.update({'quota_distribution': distribution['id']})
|
||||||
|
|
||||||
|
serializer = self.serializer_class(data=data)
|
||||||
|
if serializer.is_valid(raise_exception=True):
|
||||||
|
serializer.save()
|
||||||
|
|
||||||
|
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
||||||
|
return Response(serializer.errors, status=status.HTTP_403_FORBIDDEN)
|
||||||
|
|
||||||
|
@action(
|
||||||
|
methods=['get'],
|
||||||
|
detail=False,
|
||||||
|
url_path='my_sharing_distributes',
|
||||||
|
url_name='my_sharing_distributes',
|
||||||
|
name='my_sharing_distributes',
|
||||||
|
)
|
||||||
|
def my_shared_distributes(self, request):
|
||||||
|
""" list of my shared stakeholders with detail """
|
||||||
|
|
||||||
|
organization = get_organization_by_user(request.user)
|
||||||
|
|
||||||
|
stakeholders_sharing = self.queryset.filter(
|
||||||
|
registering_organization=organization
|
||||||
|
).order_by('-create_date')
|
||||||
|
|
||||||
|
# paginate stakeholders
|
||||||
|
page = self.paginate_queryset(stakeholders_sharing)
|
||||||
|
if page is not None:
|
||||||
|
serializer = self.get_serializer(page, many=True)
|
||||||
|
return self.get_paginated_response(serializer.data)
|
||||||
|
|
||||||
|
@action(
|
||||||
|
methods=['get'],
|
||||||
|
detail=True,
|
||||||
|
url_path='shared_by_distribution',
|
||||||
|
url_name='shared_by_distribution',
|
||||||
|
name='shared_by_distribution',
|
||||||
|
)
|
||||||
|
@transaction.atomic
|
||||||
|
def shared_by_distribution(self, request, pk=None):
|
||||||
|
""" list of shared stakeholder with distribution """
|
||||||
|
|
||||||
|
stakeholder_sharing = self.queryset.filter(
|
||||||
|
quota_distribution_id=pk
|
||||||
|
).order_by('-create_date')
|
||||||
|
|
||||||
|
# paginate stakeholders
|
||||||
|
page = self.paginate_queryset(stakeholder_sharing)
|
||||||
|
if page is not None:
|
||||||
|
serializer = self.get_serializer(page, many=True)
|
||||||
|
return self.get_paginated_response(serializer.data)
|
||||||
|
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ class QuotaDistributionSerializer(serializers.ModelSerializer):
|
|||||||
|
|
||||||
representation['pricing'] = { # noqa
|
representation['pricing'] = { # noqa
|
||||||
'pricing_attributes': quota_attribute_value(instance.quota),
|
'pricing_attributes': quota_attribute_value(instance.quota),
|
||||||
'sharing': pos_organizations_sharing_information(self.context['device']),
|
'sharing': pos_organizations_sharing_information(self.context['device'], instance.quota),
|
||||||
'base_prices': [
|
'base_prices': [
|
||||||
{
|
{
|
||||||
"text": "قیمت درب کارخانه", # noqa
|
"text": "قیمت درب کارخانه", # noqa
|
||||||
|
|||||||
Reference in New Issue
Block a user