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