You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
417 lines
16 KiB
417 lines
16 KiB
# -*- coding: utf-8 -*-
|
|
# @Time : 2023/8/16 11:17
|
|
# @Author : tx
|
|
# @File : code_standard.py
|
|
# @Description : 一维条码流转类
|
|
|
|
|
|
import datetime
|
|
from datetime import timedelta
|
|
from decimal import Decimal
|
|
|
|
from tortoise.queryset import Q
|
|
|
|
from conf.setting import setting
|
|
from helper.drug import milligram_to_gram, gram_to_milligram
|
|
from helper.log import record_log
|
|
from helper.logger import logger
|
|
from models.dictionary import Dictionary
|
|
from models.drawer_board import DrawerBoard
|
|
from models.drug import Drug, DrugStateEnum
|
|
from models.drug_use_log import DrugUseLog, DrugUseStateEnum
|
|
from models.template import Template
|
|
from models.terminal import Terminal
|
|
from models.user import User
|
|
from transfer.basic import BasicStandard
|
|
|
|
|
|
class CodeStandard(BasicStandard):
|
|
'''一维条码流转类'''
|
|
|
|
def __init__(self, users: list[str], drug_obj: Drug):
|
|
self.users = users
|
|
|
|
self.barcode = ""
|
|
|
|
self.rfid = ""
|
|
self.hole = None
|
|
self.drug_obj = drug_obj
|
|
self.drawer_board_obj = None
|
|
|
|
self.in_return_func = {
|
|
DrugStateEnum.OUT: self.return_drug,
|
|
DrugStateEnum.INITIAL: self.in_drug,
|
|
DrugStateEnum.IN: self.in_drug,
|
|
DrugStateEnum.EMPTY: None
|
|
}
|
|
|
|
async def _get_drug_related(self, cabinet_id, line_no):
|
|
drugs = await Drug.filter(rfid=self.rfid).prefetch_related("dictionary", "template")
|
|
if not drugs:
|
|
return False
|
|
self.drug_obj = drugs[0]
|
|
self.drawer_board_obj = await DrawerBoard.filter(cabinet_id=cabinet_id, line_no=
|
|
line_no).prefetch_related("cabinet", "drawer", "board").first()
|
|
self.template_obj = self.drug_obj.template
|
|
self.terminal_obj = await Terminal.get(id=setting.TERMINAL_ID)
|
|
return True
|
|
|
|
|
|
def parse_position(self, hole):
|
|
"""
|
|
解析位置信息
|
|
:return:
|
|
"""
|
|
terminal_name = self.terminal_obj.name
|
|
drawer_label = self.drawer_board_obj.drawer.label
|
|
cabinet_location_label = f"{self.drawer_board_obj.cabinet.label}"
|
|
board_hole = self.drawer_board_obj.board.chip_dict.get(str(hole), "") if self.drawer_board_obj.board.chip_dict \
|
|
else ""
|
|
position_str = f"{terminal_name}-{cabinet_location_label}-{drawer_label}"
|
|
if board_hole:
|
|
position_str += f"-{board_hole}"
|
|
return position_str
|
|
|
|
|
|
|
|
async def return_drug(self):
|
|
"""
|
|
归还药剂
|
|
归还输入用量
|
|
:return:
|
|
"""
|
|
input_use_weight = True
|
|
alarm_state, alarm_desc = 0, ""
|
|
if self.drug_obj.state == DrugStateEnum.EMPTY:
|
|
weight, use_weight = 0, 0
|
|
operate_state = DrugUseStateEnum.EMPTY
|
|
else:
|
|
if input_use_weight:
|
|
# 归还输入用量
|
|
if not self.drug_obj.last_use_weight:
|
|
self.drug_obj.last_use_weight = 0
|
|
print("remain_gross_weight_2", self.drug_obj.remain_gross_weight)
|
|
print("last_use_weight_2", self.drug_obj.last_use_weight)
|
|
|
|
weight = Decimal(self.drug_obj.remain_gross_weight) - Decimal(self.drug_obj.last_use_weight) if \
|
|
self.drug_obj.remain_gross_weight else 0
|
|
use_weight = self.drug_obj.last_use_weight
|
|
# else:
|
|
# # 归还输入余量
|
|
# weight = self.drug_obj.last_weight if self.drug_obj.last_weight else 0
|
|
# use_weight = Decimal(self.drug_obj.remain_gross_weight) - Decimal(weight) if \
|
|
# self.drug_obj.remain_gross_weight else 0
|
|
operate_state = DrugUseStateEnum.PUT
|
|
|
|
operate_type = "return"
|
|
|
|
# 归还入库是否需称重
|
|
template = await Template.get(id=self.drug_obj.template.id).prefetch_related('archive')
|
|
|
|
is_return_weight = template.archive.params.get('return_require_weigh', '')
|
|
if input_use_weight:
|
|
# 输入用量 需要称重未称重
|
|
if is_return_weight and not use_weight:
|
|
# 报警
|
|
logger.warning("[归还需称重]归还药剂条目未称重:{0}".format(self.rfid))
|
|
|
|
weight = None
|
|
use_weight = None
|
|
alarm_state = 1
|
|
alarm_desc = "[归还需称重]归还药剂条目未称重:{0}".format(self.drug_obj.fill_json_content.get("k1"))
|
|
# 不需要称重也未称重
|
|
# elif not is_return_weight and not use_weight:
|
|
# weight = Decimal(self.drug_obj.remain_gross_weight) - Decimal(self.drug_obj.last_weight) if \
|
|
# self.drug_obj.remain_gross_weight else 0
|
|
# use_weight = 0
|
|
else:
|
|
# 输入余量 需要称重未称重
|
|
if is_return_weight and not weight:
|
|
# 报警
|
|
logger.warning("[归还需称重]归还药剂条目未称重:{0}".format(self.rfid))
|
|
|
|
weight = None
|
|
use_weight = None
|
|
alarm_state = 1
|
|
alarm_desc = "[归还需称重]归还药剂条目未称重:{0}".format(self.drug_obj.fill_json_content.get("k1"))
|
|
# 不需要称重也未称重
|
|
elif not is_return_weight and not weight:
|
|
weight = 0
|
|
use_weight = Decimal(self.drug_obj.remain_gross_weight) - Decimal(weight) if \
|
|
self.drug_obj.remain_gross_weight else 0
|
|
|
|
response_info = {
|
|
"operate_type": operate_type,
|
|
"operate_state": operate_state,
|
|
"weight": weight,
|
|
"use_weight": use_weight,
|
|
"alarm_state": alarm_state,
|
|
"alarm_desc": alarm_desc
|
|
}
|
|
|
|
return response_info
|
|
|
|
async def in_drug(self):
|
|
"""
|
|
入库药剂
|
|
:return:
|
|
"""
|
|
alarm_state, alarm_desc = 0, ""
|
|
if self.drug_obj.state == DrugStateEnum.EMPTY:
|
|
weight, use_weight = 0, 0
|
|
operate_state = DrugUseStateEnum.EMPTY
|
|
else:
|
|
# 入库的重量,取药剂字段 remain_gross_weight
|
|
weight = self.drug_obj.remain_gross_weight if self.drug_obj.remain_gross_weight else 0
|
|
use_weight = None
|
|
operate_state = DrugUseStateEnum.IN
|
|
|
|
operate_type = "in"
|
|
template_obj = await Template.get(id=self.drug_obj.template_id).prefetch_related('archive')
|
|
is_in_weight = template_obj.archive.params.get("storage_require_weigh", '')
|
|
if is_in_weight and not self.drug_obj.remain_gross_weight:
|
|
logger.warning("[入库需称重]入库药剂条目未称重:{0}".format(template_obj))
|
|
alarm_state = 1
|
|
alarm_desc = "[入库需称重]入库药剂条目未称重:{0}".format(self.drug_obj.fill_json_content.get("k1"))
|
|
response_info = {
|
|
"operate_type": operate_type,
|
|
"operate_state": operate_state,
|
|
"weight": weight,
|
|
"use_weight": use_weight,
|
|
"alarm_state": alarm_state,
|
|
"alarm_desc": alarm_desc
|
|
}
|
|
return response_info
|
|
|
|
async def put_in(self, barcode: str):
|
|
"""
|
|
归还/入库
|
|
:param rfid: rfid
|
|
:param cabinet_id: 柜体id
|
|
:param line_no: 接线号
|
|
:param hole: 孔位
|
|
:return:
|
|
"""
|
|
self.barcode = barcode
|
|
|
|
position = self.drug_obj.position
|
|
if len(self.drug_obj.rfid) < 16 and self.drug_obj.drawer_board_id :
|
|
position = (await self.drug_obj.cabinet).label +"-"+ (await self.drug_obj.drawer).label
|
|
self.drug_obj.position = position
|
|
if self.drug_obj.state == DrugStateEnum.EMPTY:
|
|
drug_update_dict = {
|
|
"position": "",
|
|
}
|
|
await self.drug_obj.update_from_dict(drug_update_dict)
|
|
await self.drug_obj.save()
|
|
drug_log = await DrugUseLog.get_or_none(drug_id=self.drug_obj.id, state=3)
|
|
await drug_log.update_from_dict(drug_update_dict)
|
|
await drug_log.save()
|
|
return False
|
|
|
|
# 入库或归还
|
|
response_info = await self.in_return_func[self.drug_obj.state]()
|
|
|
|
operate_state = response_info.get("operate_state")
|
|
weight = response_info.get("weight")
|
|
use_weight = response_info.get("use_weight")
|
|
operate_type = response_info.get("operate_type")
|
|
|
|
# 流转日志保存
|
|
drug_use_dict = {
|
|
"drug": self.drug_obj,
|
|
"state": operate_state,
|
|
"user_id": self.users[0],
|
|
"peer_ids": ",".join(self.users[1:]),
|
|
"users": await User.parse_id_user(self.users),
|
|
"cabinet_id": self.drug_obj.cabinet_id,
|
|
"drawer_id": self.drug_obj.drawer_id,
|
|
"drawer_board_id": self.drug_obj.drawer_board_id,
|
|
"hole": self.drug_obj.hole,
|
|
"position": position,
|
|
"weight": weight,
|
|
"use_weight": use_weight,
|
|
"alarm_state": response_info.get("alarm_state"),
|
|
"alarm_desc": response_info.get("alarm_desc"),
|
|
}
|
|
if setting.TERMINAL_ID:
|
|
drug_use_dict.update({
|
|
"terminal_id": setting.TERMINAL_ID
|
|
})
|
|
|
|
return_obj = await DrugUseLog().create(**drug_use_dict)
|
|
if operate_type == 'return':
|
|
receive_obj = await DrugUseLog.filter(drug=self.drug_obj.id, state=2).order_by('-created_at').first()
|
|
if receive_obj:
|
|
# 更新return_log_id字段
|
|
receive_obj.return_log_id = return_obj.id
|
|
await receive_obj.save()
|
|
# 药剂更新
|
|
drug_update_dict = {
|
|
"state": DrugStateEnum.IN if self.drug_obj.state != DrugStateEnum.EMPTY else DrugStateEnum.EMPTY,
|
|
}
|
|
|
|
if response_info.get("weight"):
|
|
drug_update_dict.update({
|
|
"remain_gross_weight": weight,
|
|
})
|
|
if operate_type == "in":
|
|
drug_update_dict.update({
|
|
"storage_id": self.users[0],
|
|
"storage_at": self._now_strftime(),
|
|
})
|
|
else:
|
|
# 归还更新药剂总用量
|
|
receive_objs = await DrugUseLog.filter(drug=self.drug_obj.id)
|
|
total_use_weight = sum([i.use_weight for i in receive_objs if i.use_weight]) or 0
|
|
print("total_use_weight", total_use_weight)
|
|
drug_update_dict.update({
|
|
"last_return_at": self._now_strftime(),
|
|
"last_return_id": self.users[0],
|
|
"last_use_weight": None,
|
|
"total_use_weight": total_use_weight
|
|
})
|
|
await self.drug_obj.update_from_dict(drug_update_dict)
|
|
await self.drug_obj.save()
|
|
|
|
data = {
|
|
"drug_info": await self.drug_obj.attribute_drug_info(),
|
|
"position": position,
|
|
"operate_type": operate_type,
|
|
"remain_gross_weight": milligram_to_gram(self.drug_obj.remain_gross_weight),
|
|
"use_weight": milligram_to_gram(float(use_weight)) if use_weight else None,
|
|
"created_at": self._now_strftime(),
|
|
"state": drug_update_dict["state"]
|
|
}
|
|
await self.write_log(operate_type, drug_use_dict)
|
|
return data
|
|
|
|
async def take_out(self, barcode: str):
|
|
"""
|
|
领用
|
|
:param barcode: 条码编号
|
|
:return: 领用清单条目
|
|
"""
|
|
self.barcode = barcode
|
|
|
|
# 是否领用即空瓶
|
|
template_obj = await Template.get(id=self.drug_obj.template_id).prefetch_related('archive')
|
|
self.template_obj = template_obj
|
|
first_will_empty = template_obj.archive.params.get("first_will_empty", '') # 领用即空瓶
|
|
first_will_open = template_obj.archive.params.get("first_will_open", '') # 领用即开封
|
|
|
|
if self.drug_obj.state == DrugStateEnum.EMPTY:
|
|
self.drug_obj.position = None
|
|
await self.drug_obj.save()
|
|
return False
|
|
|
|
drug_use_dict = {
|
|
"drug": self.drug_obj,
|
|
"state": DrugUseStateEnum.TAKE,
|
|
"user_id": self.users[0],
|
|
"peer_ids": ",".join(self.users[1:]),
|
|
"users": await User.parse_id_user(self.users),
|
|
|
|
"terminal_id": setting.TERMINAL_ID,
|
|
"cabinet_id": self.drug_obj.cabinet_id,
|
|
"drawer_id": self.drug_obj.drawer_id,
|
|
"drawer_board_id": self.drug_obj.drawer_board_id,
|
|
"hole": self.drug_obj.hole,
|
|
"position": self.drug_obj.position,
|
|
|
|
"alerted": False,
|
|
"weight": self.drug_obj.remain_gross_weight,
|
|
}
|
|
if first_will_empty:
|
|
drug_use_dict.update({
|
|
"state": DrugUseStateEnum.EMPTY,
|
|
"weight": 0,
|
|
"use_weight": self.drug_obj.remain_gross_weight,
|
|
})
|
|
await DrugUseLog().create(**drug_use_dict)
|
|
|
|
# 更新药剂信息
|
|
drug_update_dict = {
|
|
"state": DrugStateEnum.OUT if self.drug_obj.state != DrugStateEnum.EMPTY else DrugStateEnum.EMPTY,
|
|
"last_receive_at": self._now_strftime(),
|
|
"last_receive_id": self.users[0],
|
|
}
|
|
# 首次领用开封
|
|
if first_will_open:
|
|
if not self.drug_obj.open_date:
|
|
drug_update_dict.update({
|
|
"open_date": datetime.datetime.now()
|
|
})
|
|
|
|
# 首次开瓶更新过期日期
|
|
new_expired_at = await self.open_update_expired_at(drug_update_dict.get("open_date"))
|
|
if new_expired_at:
|
|
drug_update_dict.update({
|
|
"expired_at": new_expired_at
|
|
})
|
|
# 领用即空瓶
|
|
if first_will_empty:
|
|
drug_update_dict.update({
|
|
"state": DrugStateEnum.EMPTY,
|
|
"remain_gross_weight": 0,
|
|
})
|
|
|
|
await self.drug_obj.update_from_dict(drug_update_dict)
|
|
await self.drug_obj.save()
|
|
|
|
data = {
|
|
"drug_info": await self.drug_obj.attribute_drug_info(),
|
|
"position": self.drug_obj.position,
|
|
"hole": self.drug_obj.hole,
|
|
"remain_gross_weight": await self.drug_obj.format_weight(), # 领用清单条目余重
|
|
"created_at": self._now_strftime(),
|
|
"state": drug_update_dict["state"]
|
|
}
|
|
await self.write_log("take_out", drug_use_dict)
|
|
dic_obj = await Dictionary.get(id=self.drug_obj.dictionary.id)
|
|
dic_obj.use_count += 1
|
|
await dic_obj.save()
|
|
return data
|
|
|
|
|
|
async def decap(self, rfid: str, cabinet_id: str, line_no: str, hole: int = 0):
|
|
'''报废处置 传入值是什么?'''
|
|
self.rfid = rfid
|
|
await self._get_drug_related(cabinet_id, line_no)
|
|
drug_use_dict = {
|
|
"drug": self.drug_obj,
|
|
"state": DrugUseStateEnum.SCRAP,
|
|
"user_id": self.users[0],
|
|
"peer_ids": ",".join(self.users[1:]),
|
|
"users": await User.parse_id_user(self.users),
|
|
|
|
"terminal_id": setting.TERMINAL_ID,
|
|
"cabinet_id": self.drawer_board_obj.cabinet_id,
|
|
"drawer_id": self.drawer_board_obj.drawer_id,
|
|
"drawer_board_id": self.drawer_board_obj.id,
|
|
"hole": hole,
|
|
"position": self.drug_obj.position,
|
|
"alerted": False,
|
|
"use_weight": 0,
|
|
}
|
|
drug_use_log_obj = await DrugUseLog().create(**drug_use_dict)
|
|
|
|
# 更新药剂信息
|
|
drug_update_dict = {
|
|
"state": DrugStateEnum.SCRAP,
|
|
"last_use_weight": 0,
|
|
"drawer_board_id": self.drawer_board_obj.id,
|
|
"hole": hole,
|
|
"board_id": self.drawer_board_obj.board_id,
|
|
}
|
|
|
|
await self.drug_obj.update_from_dict(drug_update_dict)
|
|
await self.drug_obj.save()
|
|
|
|
drug_use_dict.update({
|
|
"drug_use_log_id": drug_use_log_obj.id,
|
|
})
|
|
return drug_use_dict
|
|
|
|
|