Skip to content

Commit

Permalink
Merge pull request #4163 from mikhailprivalov/cash-register-
Browse files Browse the repository at this point in the history
Cash register
  • Loading branch information
urchinpro authored Aug 5, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
2 parents a8ba512 + d8b65ec commit a94e4e3
Showing 22 changed files with 653 additions and 0 deletions.
Empty file added api/cash_registers/__init__.py
Empty file.
9 changes: 9 additions & 0 deletions api/cash_registers/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from django.urls import path
from . import views

urlpatterns = [
path('get-cash-registers', views.get_cash_registers),
path('open-shift', views.open_shift),
path('close-shift', views.close_shift),
path('get-shift-data', views.get_shift_data),
]
35 changes: 35 additions & 0 deletions api/cash_registers/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import json
from django.contrib.auth.decorators import login_required
from django.http import JsonResponse
import cash_registers.views as cash_register_views
from cash_registers.models import Shift


@login_required
def get_cash_registers(request):
result = cash_register_views.get_cash_registers()
return JsonResponse({"result": result})


@login_required
def open_shift(request):
request_data = json.loads(request.body)
check_shift = Shift.check_shift(request_data["cashRegisterId"], request.user.doctorprofile.id)
if check_shift["ok"]:
result = cash_register_views.open_shift(request_data["cashRegisterId"], request.user.doctorprofile.id)
else:
result = check_shift
return JsonResponse(result)


@login_required
def close_shift(request):
request_data = json.loads(request.body)
result = cash_register_views.close_shift(request_data["cashRegisterId"], request.user.doctorprofile.id)
return JsonResponse(result)


@login_required
def get_shift_data(request):
result = cash_register_views.get_shift_data(request.user.doctorprofile.id)
return JsonResponse(result)
1 change: 1 addition & 0 deletions api/urls.py
Original file line number Diff line number Diff line change
@@ -105,6 +105,7 @@
path('hospitals/', include('api.hospitals.urls')),
path('cases/', include('api.cases.urls')),
path('construct/', include('api.construct.urls')),
path('cash-register/', include('api.cash_registers.urls')),
path('get-prices', views.get_prices),
path('get-price-data', views.get_price_data),
path('update-price', views.update_price),
4 changes: 4 additions & 0 deletions api/views.py
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@
import pytz_deprecation_shim as pytz

from api.models import ManageDoctorProfileAnalyzer, Analyzer
from cash_registers.models import Shift
from directions.views import create_case_by_cards
from directory.models import Researches, SetResearch, SetOrderResearch, PatientControlParam
from doctor_schedule.models import ScheduleResource
@@ -638,6 +639,7 @@ def current_user_info(request):
"modules": SettingManager.l2_modules(),
"user_services": [],
"loading": False,
"cashRegisterShift": {"cashRegisterId": None, "shiftId": None},
}
if ret["auth"]:
request.user.doctorprofile.mark_as_online()
@@ -684,6 +686,8 @@ def fill_user_data():
ret["groups"].append("Admin")
ret["eds_allowed_sign"] = doctorprofile.get_eds_allowed_sign() if ret["modules"].get("l2_eds") else []
ret["can_edit_all_department"] = doctorprofile.all_hospitals_users_control
shift_data = Shift.get_open_shift_by_operator(request.user.doctorprofile.id)
ret["cashRegisterShift"] = {"cashRegisterId": shift_data["cash_register_id"], "shiftId": shift_data["shift_id"]}

try:
connections.close_all()
1 change: 1 addition & 0 deletions appconf/manager.py
Original file line number Diff line number Diff line change
@@ -191,6 +191,7 @@ def l2_modules() -> dict:
"code_price",
"all_service",
"show_barcode_button_in_direction_history",
"cash",
]
},
"consults_module": SettingManager.get("consults_module", default='false', default_type='b'),
Empty file added cash_registers/__init__.py
Empty file.
22 changes: 22 additions & 0 deletions cash_registers/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from django.contrib import admin
from cash_registers.models import CashRegister, Shift


class CashRegisterAdmin(admin.ModelAdmin):
list_display = ['pk', 'title', 'ip_address', 'port', 'department', 'address']
search_fields = (
'pk',
'title',
)
raw_id_fields = ['department']


class ShiftAdmin(admin.ModelAdmin):
list_display = ['pk', 'cash_register', 'open_at', 'close_at', 'operator']
search_fields = ('pk', 'operator', 'cash_register')
list_filter = ('operator',)
raw_id_fields = ['operator', 'cash_register']


admin.site.register(CashRegister, CashRegisterAdmin)
admin.site.register(Shift, ShiftAdmin)
6 changes: 6 additions & 0 deletions cash_registers/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class CashRegistersConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'cash_registers'
Empty file.
139 changes: 139 additions & 0 deletions cash_registers/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import uuid
from django.db import models
from jsonfield import JSONField
from cash_registers import sql_func
from laboratory.utils import current_time
from podrazdeleniya.models import Podrazdeleniya
from users.models import DoctorProfile


class CashRegister(models.Model):
title = models.CharField(max_length=255, blank=True, null=True, verbose_name='Наименование')
ip_address = models.CharField(max_length=255, default="", verbose_name='IP адрес', help_text='192.168.10.10')
port = models.CharField(max_length=5, default="", verbose_name='Порт', help_text='16333')
login = models.CharField(max_length=255, default="", verbose_name='Логин', help_text='login')
password = models.CharField(max_length=255, default="", verbose_name='Пароль', help_text='123456')
hide = models.BooleanField(default=False, blank=True, verbose_name='Скрытие')
address = models.CharField(max_length=128, blank=True, default='', verbose_name="Адрес")
address_fias = models.CharField(max_length=128, blank=True, default=None, null=True, verbose_name="ФИАС Адрес")
address_details = JSONField(blank=True, null=True, verbose_name="Детали адреса")
department = models.ForeignKey(Podrazdeleniya, null=True, db_index=True, verbose_name="Подразделение", on_delete=models.SET_NULL)
location = models.CharField(max_length=255, default="", verbose_name="Местоположение", help_text="2 этаж регистратура")

class Meta:
verbose_name = "Касса"
verbose_name_plural = "Кассы"

def __str__(self):
return f"{self.title}"

def json(self):
return {
"id": self.id,
"label": self.title,
}

@staticmethod
def get_cash_registers():
result = [{"id": cash_register.id, "label": cash_register.title} for cash_register in sql_func.get_cash_registers()]
return result

@staticmethod
def get_meta_data(cash_register_id):
cash_register: CashRegister = CashRegister.objects.get(pk=cash_register_id)
cash_register_data = {"address": cash_register.ip_address, "port": cash_register.port, "login": cash_register.login, "password": cash_register.password}
return cash_register_data


class Shift(models.Model):
cash_register = models.ForeignKey(CashRegister, verbose_name='Касса', help_text='Касса 1', null=True, on_delete=models.SET_NULL, db_index=True)
open_at = models.DateTimeField(verbose_name='Время открытия', help_text='2024-07-28 16:00', null=True, blank=True, db_index=True)
close_at = models.DateTimeField(verbose_name='Время закрытия', help_text='2024-07-28 23:00', null=True, blank=True, db_index=True)
operator = models.ForeignKey(DoctorProfile, verbose_name='Оператор', help_text='Сидоров м.п', null=True, on_delete=models.SET_NULL, db_index=True)
open_uuid = models.UUIDField(verbose_name='UUID открытия', help_text='abbfg-45fsd2', null=True, blank=True)
close_uuid = models.UUIDField(verbose_name='UUID Закрытия', help_text='abbfg-45fsd2', null=True, blank=True)
open_status = models.BooleanField(verbose_name='Статус открытия смены', default=False)
close_status = models.BooleanField(verbose_name='Статус открытия смены', default=False)

class Meta:
verbose_name = "Кассовая смена"
verbose_name_plural = "Кассовые смены"

def __str__(self):
return f"{self.cash_register.title} - {self.open_at} - {self.close_at} - {self.operator}"

@staticmethod
def open_shift(uuid_data: str, cash_register_id: int, operator_id: int):
new_shift: Shift = Shift(cash_register_id=cash_register_id, operator_id=operator_id, open_uuid=uuid_data)
new_shift.save()
return {"cash_register_id": new_shift.cash_register_id, "shift_id": new_shift.pk}

def confirm_open_shift(self):
self.open_status = True
self.open_at = current_time()
self.save()
return True

@staticmethod
def close_shift(uuid_data: str, cash_register_id: int, operator_id: int):
shift: Shift = Shift.objects.filter(cash_register_id=cash_register_id, operator_id=operator_id, open_status=True, close_status=False).last()
shift.close_uuid = uuid_data
shift.save()
return True

def confirm_close_shift(self):
self.close_status = True
self.close_at = current_time()
self.save()
return True

@staticmethod
def get_open_shift_by_operator(operator_id: int):
shift: Shift = Shift.objects.filter(operator_id=operator_id, open_status=True, close_status=False).last()
if shift:
result = {"cash_register_id": shift.cash_register_id, "shift_id": shift.pk}
else:
result = {"cash_register_id": None, "shift_id": None}
return result

@staticmethod
def check_shift(cash_register_id: int, doctor_profile_id: int):
result_check = sql_func.check_shift(cash_register_id, doctor_profile_id)
if len(result_check) == 0:
result = {"ok": True, "message": ""}
elif result_check[0].operator_id == doctor_profile_id:
result = {"ok": False, "message": "У вас уже есть открытая смена"}
else:
result = {"ok": False, "message": "На этой кассе уже есть открытая смена"}
return result

@staticmethod
def get_shift_job_data(doctor_profile_id: int, cash_register_id):
operator: DoctorProfile = DoctorProfile.objects.get(pk=doctor_profile_id)
operator_data = {"name": operator.get_full_fio(), "vatin": operator.inn}
cash_register_data = CashRegister.get_meta_data(cash_register_id)
uuid_data = str(uuid.uuid4())
result = {"operator_data": operator_data, "cash_register_data": cash_register_data, "uuid_data": uuid_data}
return result

def get_shift_status(self):
uuid_data = None
if not self.open_status and self.open_uuid:
status = "Открывается"
uuid_data = self.open_uuid
elif self.open_status and not self.close_uuid:
status = "Открыта"
else:
status = "Закрывается"
uuid_data = self.close_uuid
return {"status": status, "uuid": uuid_data}

@staticmethod
def change_status(current_status, job_status, shift):
if current_status == "Открывается":
shift.confirm_open_shift()
result = "Открыта"
else:
shift.confirm_close_shift()
result = "Закрыта"
return result
75 changes: 75 additions & 0 deletions cash_registers/req.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import requests
from laboratory.settings import CASH_REGISTER_SERVER_ADDRESS, CASH_REGISTER_SERVER_TOKEN


def get_authorization_header():
headers = {"Authorization": f"Bearer {CASH_REGISTER_SERVER_TOKEN}"}
return headers


def check_cash_register_status(cash_register_data: dict) -> dict:
headers = get_authorization_header()
body = {"cashRegister": cash_register_data}
try:
response = requests.post(f"{CASH_REGISTER_SERVER_ADDRESS}get-cash-register-status", json=body, headers=headers, timeout=30)
response_data = response.json()
except Exception as e:
return {
"ok": False,
"connection_middle_server_error": True,
"data": f"{e}",
}
return response_data


def check_cash_register(cash_register_data: dict):
result = {"ok": True, "message": ""}
cash_register_check = check_cash_register_status(cash_register_data)
if cash_register_check["ok"]:
device_status = cash_register_check["data"]["deviceStatus"]
if not device_status["paperPresent"]:
result = {"ok": False, "message": "В кассе нет бумаги"}
elif device_status["blocked"]:
result = {"ok": False, "message": "Касса заблокирована"}
else:
if cash_register_check.get("connection_middle_server_error"):
result = {"ok": False, "message": "Кассовый middle сервер недоступен"}
elif cash_register_check.get("connectionWebRequestError"):
result = {"ok": False, "message": "Кассовый web-request atol сервер недоступен"}
elif cash_register_check.get("cashRegisterConnectionError"):
# todo - логировать ошибку из ключа "data"
result = {"ok": False, "message": "Ошибка при подключении к кассе"}
return result


def send_job(body: dict):
headers = get_authorization_header()
try:
response = requests.post(f"{CASH_REGISTER_SERVER_ADDRESS}push-job", json=body, headers=headers, timeout=5)
response_data = response.json()
except Exception as e:
return {"ok": False, "message": "Ошибка", "data": f"{e}", "connection_middle_server_error": True}
return response_data


def get_job_status(uuid: str, cash_register: dict):
body = {"cashRegister": cash_register, "uuid": uuid}
headers = get_authorization_header()
try:
response = requests.post(f"{CASH_REGISTER_SERVER_ADDRESS}get-job-status", json=body, headers=headers, timeout=5)
response_data = response.json()
except Exception as e:
return {"ok": False, "message": "Ошибка", "data": f"{e}", "connection_middle_server_error": True}
return response_data


def open_shift(uuid: str, cash_register: dict, operator: dict):
body = {"cashRegister": cash_register, "uuid": uuid, "job": [{"type": "openShift", "operator": operator}]}
result = send_job(body)
return result


def close_shift(uuid: str, cash_register: dict, operator: dict):
body = {"cashRegister": cash_register, "uuid": uuid, "job": [{"type": "closeShift", "operator": operator}]}
result = send_job(body)
return result
33 changes: 33 additions & 0 deletions cash_registers/sql_func.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from django.db import connection
from utils.db import namedtuplefetchall


def get_cash_registers():
with connection.cursor() as cursor:
cursor.execute(
"""
SELECT * FROM cash_registers_cashregister
""",
)
rows = namedtuplefetchall(cursor)
return rows


def check_shift(cash_register_id, doctor_profile_id):
with connection.cursor() as cursor:
cursor.execute(
"""
SELECT
operator_id,
cash_register_id,
close_status
FROM cash_registers_shift
WHERE
(operator_id=%(doctor_profile_id)s or cash_register_id=%(cash_register_id)s)
and
close_status = False
""",
params={"cash_register_id": cash_register_id, "doctor_profile_id": doctor_profile_id},
)
rows = namedtuplefetchall(cursor)
return rows
Loading

0 comments on commit a94e4e3

Please sign in to comment.