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

# -*- 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