pos device login depoyment

This commit is contained in:
2025-08-17 15:11:58 +03:30
parent d2fa1b264f
commit c2318b45c5
11 changed files with 159 additions and 14 deletions

View File

@@ -48,7 +48,7 @@ class PosDeviceValidationMiddleware:
raise raise
def validate_request(self, request): def validate_request(self, request):
headers = request.headers.kiani headers = request.headers
data = {key: headers.get(key) for key in self.REQUIRED_HEADERS} data = {key: headers.get(key) for key in self.REQUIRED_HEADERS}
missing = [key for key, value in data.items() if not value] missing = [key for key, value in data.items() if not value]

View File

@@ -0,0 +1,28 @@
# Generated by Django 5.0 on 2025-08-17 11:41
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('pos_device', '0058_rename_assigned_device_assigned_state'),
]
operations = [
migrations.AddField(
model_name='device',
name='pre_registered',
field=models.BooleanField(default=False),
),
migrations.AlterField(
model_name='device',
name='acceptor',
field=models.CharField(max_length=50, null=True),
),
migrations.AlterField(
model_name='device',
name='terminal',
field=models.CharField(max_length=50, null=True),
),
]

View File

@@ -32,8 +32,8 @@ class ProviderCompany(BaseModel):
class Device(BaseModel): class Device(BaseModel):
device_identity = models.CharField(max_length=25, null=True) device_identity = models.CharField(max_length=25, null=True)
acceptor = models.CharField(max_length=50) acceptor = models.CharField(max_length=50, null=True)
terminal = models.CharField(max_length=50) terminal = models.CharField(max_length=50, null=True)
serial = models.TextField(null=True) serial = models.TextField(null=True)
password = models.CharField(max_length=25, null=True) password = models.CharField(max_length=25, null=True)
multi_device = models.BooleanField(default=False) multi_device = models.BooleanField(default=False)
@@ -41,7 +41,7 @@ class Device(BaseModel):
latitude = models.FloatField(default=0) latitude = models.FloatField(default=0)
longitude = models.FloatField(default=0) longitude = models.FloatField(default=0)
is_activated = models.BooleanField(default=False) is_activated = models.BooleanField(default=False)
# pre_registered = models.BooleanField(default=False) pre_registered = models.BooleanField(default=False)
organization = models.ForeignKey( organization = models.ForeignKey(
Organization, Organization,
on_delete=models.CASCADE, on_delete=models.CASCADE,
@@ -57,8 +57,8 @@ class Device(BaseModel):
""" generate identity for every device """ """ generate identity for every device """
prefix = "POS" prefix = "POS"
while True: while True:
number_part = ''.join(random.choices(string.digits, k=6)) number_part = ''.join(random.choices(string.digits, k=9))
code = f"{prefix}{number_part}" code = f"{number_part}"
if not Device.objects.filter(device_identity=code).exists(): if not Device.objects.filter(device_identity=code).exists():
return code return code

View File

@@ -0,0 +1,8 @@
from apps.pos_device import models as pos_models
from rest_framework import serializers
class DeviceSerializer(serializers.ModelSerializer):
class Meta:
model = pos_models.Device
fields = '__all__'

View File

@@ -1,9 +1,7 @@
from django.urls import path, include from django.urls import path, include
from rest_framework.routers import DefaultRouter from rest_framework.routers import DefaultRouter
from .viewsets.device import TestViewSet
router = DefaultRouter() router = DefaultRouter()
router.register('test', TestViewSet, basename='test')
urlpatterns = [ urlpatterns = [
path('v1/', include(router.urls)) path('v1/', include(router.urls))

View File

@@ -1,8 +1,108 @@
from rest_framework import viewsets from apps.pos_device.pos.api.v1.serializers.device import DeviceSerializer
from apps.pos_device import models as pos_models
from rest_framework.permissions import AllowAny
from rest_framework.decorators import action
from rest_framework.response import Response from rest_framework.response import Response
from common.generics import get_client_ip
from rest_framework import viewsets
from django.db import transaction
from rest_framework import status
class TestViewSet(viewsets.ModelViewSet): class POSDeviceViewSet(viewsets.ModelViewSet):
device_queryset = pos_models.Device.objects.all()
session_queryset = pos_models.Sessions.objects.all()
serializer_class = DeviceSerializer
HEADERS = [
'device-mac', 'device-serial', 'device-name',
'device-sdk', 'device-version',
'device-lng', 'device-lot', 'device-provider', # noqa
'device-vname', # noqa
]
permission_classes = [AllowAny]
def list(self, request, *args, **kwargs): @action(
return Response("Hello from the outsiiiiiiiiide") # noqa methods=['post'],
detail=False,
url_path='login',
url_name='login',
name='login'
)
@transaction.atomic
def login(self, request):
""" login of pos device """
# convert headers to dictionary
headers_data = {key: request.headers.get(key) for key in self.HEADERS}
serial = headers_data['device-serial']
sdk = headers_data['device-sdk']
psp_name = headers_data['device-provider']
organization = pos_models.Organization.objects.get(en_name=psp_name)
# check if device exists
if 'device_identity' in request.data.keys():
device = self.device_queryset.filter(device_identity=request.data['device_identity'])
else:
device = self.device_queryset.filter(serial=serial).first()
# activate device
if device:
if not device.is_activated:
device.is_activated = True
device.save()
session = pos_models.Sessions.objects.create(
device=device,
password=device.password,
version=headers_data['device-version'],
mac=headers_data['device-mac'],
ip=get_client_ip(request),
sdk=headers_data['device-sdk'],
serial=headers_data['device-serial'],
latitude=headers_data['device-lot'],
longitude=headers_data['device-lng'],
)
return Response({
"message": "login success - session activated",
"device_identity": device.device_identity,
"serial": device.serial
}, status=status.HTTP_200_OK)
pre_device = pos_models.Device.objects.create(
serial=serial,
sdk=sdk,
organization=organization,
pre_regitered=True,
is_activated=False
)
return Response({
"message": "device pre-registered",
"device_identity": pre_device.device_identity
}, status=status.HTTP_200_OK)
@action(
methods=['post'],
detail=False,
url_path='merge_devices',
url_name='merge_devices',
name='merge_devices'
)
@transaction.atomic
def merge_devices(self, request):
""" merge pre register device & device has registered by psp user """
pre_device = self.device_queryset.get(device_identity=request.data['pre_device'])
real_device = self.device_queryset.get(device_identity=request.data['real_device'])
real_device.device_identity = pre_device.device_identity
real_device.save()
pre_device.delete()
return Response({
"message": "device merged successfully",
"device_identity": real_device.device_identity,
"serial": real_device.serial
})

View File

@@ -1 +0,0 @@
# Your services go here

View File

@@ -0,0 +1 @@

View File

@@ -1,6 +1,12 @@
from django.urls import path, include from django.urls import path, include
from .pos.api.v1.viewsets import device
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'', device.POSDeviceViewSet, basename='auth')
urlpatterns = [ urlpatterns = [
path('web/', include('apps.pos_device.web.api.v1.urls')), path('web/', include('apps.pos_device.web.api.v1.urls')),
path('pos/', include('apps.pos_device.pos.api.v1.urls')) path('pos/', include('apps.pos_device.pos.api.v1.urls')),
path('auth/', include(router.urls)),
] ]

View File

@@ -9,3 +9,8 @@ def base64_to_image_file(base64_string, filename="image.jpg"):
img_format, img_str = base64_string.split(';base64,') # split before & after of ';base64,' img_format, img_str = base64_string.split(';base64,') # split before & after of ';base64,'
ext = img_format.split('/')[-1] # split format of file ext = img_format.split('/')[-1] # split format of file
return ContentFile(base64.b64decode(img_str), name=f"{filename}.{ext}"), ext return ContentFile(base64.b64decode(img_str), name=f"{filename}.{ext}"), ext
def get_client_ip(request): # noqa
forwarded = request.META.get('HTTP_X_FORWARDED_FOR')
return forwarded.split(',')[0] if forwarded else request.META.get('REMOTE_ADDR')