diff --git a/apps/pos_device/migrations/0008_device_device_identity_deviceassignment.py b/apps/pos_device/migrations/0008_device_device_identity_deviceassignment.py new file mode 100644 index 0000000..e315505 --- /dev/null +++ b/apps/pos_device/migrations/0008_device_device_identity_deviceassignment.py @@ -0,0 +1,40 @@ +# Generated by Django 5.0 on 2025-07-26 06:30 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('pos_device', '0007_providercompany_user_relation'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.AddField( + model_name='device', + name='device_identity', + field=models.CharField(max_length=25, null=True), + ), + migrations.CreateModel( + name='DeviceAssignment', + 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)), + ('client', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='assignment', to='pos_device.posclient')), + ('company', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='assignments', to='pos_device.providercompany')), + ('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)), + ('device', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='assignment', to='pos_device.device')), + ('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, + }, + ), + ] diff --git a/apps/pos_device/models.py b/apps/pos_device/models.py index 94d3adf..d60c2cf 100644 --- a/apps/pos_device/models.py +++ b/apps/pos_device/models.py @@ -46,9 +46,6 @@ class Device(BaseModel): def __str__(self): return f'Device: {self.serial} - {self.id}' - def save(self, *args, **kwargs): - return super(Device, self).save(*args, **kwargs) - def generate_device_identity(self): """ generate identity for every device """ prefix = "POS" @@ -58,6 +55,11 @@ class Device(BaseModel): if not self.objects.filter(short_code=code).exists(): return code + def save(self, *args, **kwargs): + if not self.device_identity: + self.device_identity = self.generate_device_identity() + return super(Device, self).save(*args, **kwargs) + class DeviceVersion(BaseModel): device = models.ForeignKey( @@ -175,3 +177,30 @@ class POSClientAttributeValue(BaseModel): def save(self, *args, **kwargs): return super(POSClientAttributeValue, self).save(*args, **kwargs) + + +class DeviceAssignment(BaseModel): + company = models.ForeignKey( + ProviderCompany, + on_delete=models.CASCADE, + related_name='assignments', + null=True + ) + client = models.ForeignKey( + POSClient, + on_delete=models.CASCADE, + related_name='assignment', + null=True + ) + device = models.ForeignKey( + Device, + on_delete=models.CASCADE, + related_name='assignment', + null=True + ) + + def __str__(self): + return f'Device: {self.device.serial} - Client: {self.client.name}' + + def save(self, *args, **kwargs): + return super(DeviceAssignment, self).save(*args, **kwargs) diff --git a/apps/pos_device/web/api/v1/serilaizers/client.py b/apps/pos_device/web/api/v1/serilaizers/client.py new file mode 100644 index 0000000..83e625d --- /dev/null +++ b/apps/pos_device/web/api/v1/serilaizers/client.py @@ -0,0 +1,20 @@ +from rest_framework.serializers import ModelSerializer +from apps.pos_device import models as pos_models + + +class POSClientSerializer(ModelSerializer): + class Meta: + model = pos_models.POSClient + fields = '__all__' + + +class POSClientAttributeSerializer(ModelSerializer): + class Meta: + model = pos_models.POSClientAttribute + fields = '__all__' + + +class POSClientAttributeValueSerializer(ModelSerializer): + class Meta: + model = pos_models.POSClientAttributeValue + fields = '__all__' diff --git a/apps/pos_device/web/api/v1/serilaizers/serializers.py b/apps/pos_device/web/api/v1/serilaizers/device.py similarity index 63% rename from apps/pos_device/web/api/v1/serilaizers/serializers.py rename to apps/pos_device/web/api/v1/serilaizers/device.py index 3ce99a7..e97102b 100644 --- a/apps/pos_device/web/api/v1/serilaizers/serializers.py +++ b/apps/pos_device/web/api/v1/serilaizers/device.py @@ -26,21 +26,7 @@ class SessionSerializer(ModelSerializer): fields = '__all__' -class POSClientSerializer(ModelSerializer): +class DeviceAssignmentSerializer(ModelSerializer): class Meta: - model = pos_models.POSClient + model = pos_models.DeviceAssignment fields = '__all__' - - -class POSClientAttributeSerializer(ModelSerializer): - class Meta: - model = pos_models.POSClientAttribute - fields = '__all__' - - -class POSClientAttributeValueSerializer(ModelSerializer): - class Meta: - model = pos_models.POSClientAttributeValue - fields = '__all__' - - diff --git a/apps/pos_device/web/api/v1/urls.py b/apps/pos_device/web/api/v1/urls.py index 5595926..00e9433 100644 --- a/apps/pos_device/web/api/v1/urls.py +++ b/apps/pos_device/web/api/v1/urls.py @@ -8,6 +8,7 @@ router.register(r'client', client_views.POSClientViewSet, basename='client') router.register(r'attributes', client_views.POSClientAttributeViewSet, basename='attributes') router.register(r'provider', device_views.ProviderCompanyViewSet, basename='provider') router.register(r'device', device_views.DeviceViewSet, basename='device') +router.register(r'device_assignment', device_views.DeviceAssignmentViewSet, basename='device_assignment') urlpatterns = [ path('v1/pos/', include(router.urls)) diff --git a/apps/pos_device/web/api/v1/viewsets/client.py b/apps/pos_device/web/api/v1/viewsets/client.py index 37a2103..1f8dc43 100644 --- a/apps/pos_device/web/api/v1/viewsets/client.py +++ b/apps/pos_device/web/api/v1/viewsets/client.py @@ -1,4 +1,4 @@ -from apps.pos_device.web.api.v1.serilaizers import serializers as pos_serializer +from apps.pos_device.web.api.v1.serilaizers import client as client_serializer from apps.pos_device import models as pos_models from rest_framework.response import Response from common.tools import CustomOperations @@ -8,7 +8,7 @@ from rest_framework import status class POSClientViewSet(viewsets.ModelViewSet): queryset = pos_models.POSClient.objects.all() - serializer_class = pos_serializer.POSClientSerializer + serializer_class = client_serializer.POSClientSerializer def create(self, request, *args, **kwargs): """ Custom create of pos client """ @@ -61,9 +61,9 @@ class POSClientViewSet(viewsets.ModelViewSet): class POSClientAttributeViewSet(viewsets.ModelViewSet): queryset = pos_models.POSClientAttribute.objects.all() - serializer_class = pos_serializer.POSClientAttributeSerializer + serializer_class = client_serializer.POSClientAttributeSerializer class POSClientAttributeValueViewSet(viewsets.ModelViewSet): queryset = pos_models.POSClientAttributeValue.objects.all() - serializer_class = pos_serializer.POSClientAttributeValueSerializer + serializer_class = client_serializer.POSClientAttributeValueSerializer diff --git a/apps/pos_device/web/api/v1/viewsets/device.py b/apps/pos_device/web/api/v1/viewsets/device.py index 5cb6287..91d6fe3 100644 --- a/apps/pos_device/web/api/v1/viewsets/device.py +++ b/apps/pos_device/web/api/v1/viewsets/device.py @@ -1,4 +1,4 @@ -from apps.pos_device.web.api.v1.serilaizers import serializers as pos_serializer +from apps.pos_device.web.api.v1.serilaizers import device as device_serializer from apps.authentication.api.v1.api import UserViewSet from apps.authorization.models import UserRelations from rest_framework.exceptions import APIException @@ -13,7 +13,7 @@ from rest_framework import status class ProviderCompanyViewSet(viewsets.ModelViewSet): # noqa queryset = pos_models.ProviderCompany.objects.all() - serializer_class = pos_serializer.ProviderCompanySerializer + serializer_class = device_serializer.ProviderCompanySerializer def create(self, request, *args, **kwargs): """ custom create of provider client """ @@ -43,7 +43,7 @@ class ProviderCompanyViewSet(viewsets.ModelViewSet): # noqa class DeviceViewSet(viewsets.ModelViewSet): queryset = pos_models.Device.objects.all() - serializer_class = pos_serializer.DeviceSerializer + serializer_class = device_serializer.DeviceSerializer def create(self, request, *args, **kwargs): """ Custom create of pos devices """ @@ -85,9 +85,58 @@ class DeviceViewSet(viewsets.ModelViewSet): class DeviceVersionViewSet(viewsets.ModelViewSet): queryset = pos_models.DeviceVersion.objects.all() - serializer_class = pos_serializer.DeviceVersionSerializer + serializer_class = device_serializer.DeviceVersionSerializer class SessionViewSet(viewsets.ModelViewSet): # noqa queryset = pos_models.Sessions.objects.all() - serializer_class = pos_serializer.SessionSerializer + serializer_class = device_serializer.SessionSerializer + + +class DeviceAssignmentViewSet(viewsets.ModelViewSet): + queryset = pos_models.DeviceAssignment.objects.all() + serializer_class = device_serializer.DeviceAssignmentSerializer + + @action( + methods=['post'], + detail=False, + url_path='assignment', + url_name='assignment', + name='assignment', + ) + @transaction.atomic + def device_assignment(self, request): + """ assign pos device to client by company """ + + company = pos_models.ProviderCompany.objects.get( + user_relation__user=request.user + ) + request.data.update({'company': company.id}) + + # create assignment + serializer = self.serializer_class(data=request.data) + if serializer.is_valid(): + assignment = 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_name='my_assignment', + url_path='my_assignments', + name='my_assignment' + ) + def my_assignment(self, request): + """ list of company device assignment to clients """ + + company = pos_models.ProviderCompany.objects.get( + user_relation__user=request.user + ) + + # get device assignment + assignments = self.queryset.filter(company=company) + + serializer = self.serializer_class(assignments, many=True) + return Response diff --git a/apps/product/web/api/v1/viewsets/quota_api.py b/apps/product/web/api/v1/viewsets/quota_api.py index d78586f..a43e619 100644 --- a/apps/product/web/api/v1/viewsets/quota_api.py +++ b/apps/product/web/api/v1/viewsets/quota_api.py @@ -307,7 +307,6 @@ class QuotaViewSet(viewsets.ModelViewSet): # noqa # paginate queryset page = self.paginate_queryset( self.queryset.filter( - Q(assigned_organizations=organization) | Q(registerer_organization=organization), Q(is_closed=False) ).order_by('-modify_date')