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 models.cabinet import Cabinet from transfer.basic import BasicStandard class Standard(BasicStandard): '''标准流转类''' def __init__(self, users: list[str]): self.users = users self.rfid = "" self.hole = None self.drug_obj = None 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): 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).prefetch_related("cabinet", "drawer", "board").first() self.template_obj = self.drug_obj.template self.terminal_obj = await Terminal.get_or_none(id=setting.TERMINAL_ID) self.cabinet_obj = await Cabinet.get_or_none(id=cabinet_id) return True def parse_position(self, hole): """ 解析位置信息 :return: """ # terminal_name = self.terminal_obj.name drawer_label = self.drawer_board_obj.drawer.label if self.drawer_board_obj else "" cabinet_location_label = f"{self.cabinet_obj.label}" board_hole = "" if self.drawer_board_obj: board_hole = self.drawer_board_obj.board.chip_dict.get(str(hole), "") if self.drawer_board_obj.board.chip_dict \ else "" position_str = f"{cabinet_location_label}-{drawer_label}" if self.drawer_board_obj and self.drawer_board_obj.label: position_str += f"-{self.drawer_board_obj.label}" if board_hole: position_str += f"-{board_hole}" return position_str async def return_drug(self): """ 归还药剂 归还输入用量 :return: """ if self.drug_obj.state == DrugStateEnum.EMPTY: operate_state = DrugUseStateEnum.EMPTY else: operate_state = DrugUseStateEnum.PUT operate_type = "return" response_info = { "operate_type": operate_type, "operate_state": operate_state, } return response_info async def in_drug(self): """ 入库药剂 :return: """ if self.drug_obj.state == DrugStateEnum.EMPTY: operate_state = DrugUseStateEnum.EMPTY else: operate_state = DrugUseStateEnum.IN operate_type = "in" response_info = { "operate_type": operate_type, "operate_state": operate_state, } return response_info async def put_in(self, rfid: str, cabinet_id: str, position): """ 归还/入库 :param rfid: rfid :param cabinet_id: 柜体id :param line_no: 接线号 :param hole: 孔位 :return: """ self.rfid = rfid # check = await self._get_drug_related(cabinet_id,) # if not check: # return False # 入库或归还 response_info = await self.in_return_func[self.drug_obj.state]() operate_state = response_info.get("operate_state") operate_type = response_info.get("operate_type") if operate_type == 'return': # 归还流转日志保存 user_id = self.users[0] peer_ids = ",".join(self.users[1:]) users_name = await User.parse_id_user(self.users) drug_use_dict = { "drug": self.drug_obj, "state": operate_state, "user_id": user_id, "peer_ids": peer_ids, "users": users_name, "cabinet_id": cabinet_id, # "drawer_id": self.drawer_board_obj.drawer_id if self.drawer_board_obj else None, # "drawer_board_id": self.drawer_board_obj.id if self.drawer_board_obj else None, "position": position, } else: # 入库流转日志保存 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": cabinet_id, # "drawer_id": self.drawer_board_obj.drawer_id if self.drawer_board_obj else None, # "drawer_board_id": self.drawer_board_obj.id if self.drawer_board_obj else None, "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_id=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, # "drawer_board": self.drawer_board_obj if self.drawer_board_obj else None, # "board_id": self.drawer_board_obj.board_id if self.drawer_board_obj else None, # "drawer_id": self.drawer_board_obj.drawer_id if self.drawer_board_obj else None, "cabinet_id": cabinet_id, # "position": position, } if operate_type == "in": drug_update_dict.update({ "storage_id": self.users[0], "storage_at": self._now_strftime(), }) else: drug_update_dict.update({ "last_return_at": self._now_strftime(), "last_return_id": self.users[0], "last_use_weight": None, }) 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"], # "unit_code": self.drug_obj.attribute("unit_code"), # 单位编码 # "expired_at": self.drug_obj.expired_at.strftime("%Y-%m-%d") if self.drug_obj.expired_at else None # 过期时间 # } # await self.write_log(operate_type, drug_use_dict) # return data async def take_out(self, rfid: str, cabinet_id: str, position): """ 领用 领用需称重的情况,关上柜门选择条目称重,更新重量。如果没有称,定时任务五分钟扫到后报警 领用的时候如果上一次归还必称重未称重,drug_use_log中weight为空,那么就必须称重,称重后更新上一次的归还记录重量与用量 :param rfid: :param cabinet_id: :param line_no: :return: 领用清单条目 """ self.rfid = rfid # check = await self._get_drug_related(cabinet_id, line_no) # if not check or self.drug_obj.state == 3: # self.drug_obj.position = None # await self.drug_obj.save() # return False # 领用是否需称重(上次归还未称重则本次领用需称重) # receive_require_weigh = await DrugUseLog.judge_receive_require_weigh(drug_id=self.drug_obj.id, # terminal_obj=self.terminal_obj) # # # 是否领用即空瓶 drug_obj = await Drug.get(rfid=rfid).prefetch_related('template','dictionary') # terminal_obj = await Template.get(id=drug_obj.template.id).prefetch_related('archive') # first_will_empty = terminal_obj.archive.params.get("first_will_empty", '') # first_will_open = terminal_obj.archive.params.get("first_will_open", '') # position = f"{self.parse_position(self.drug_obj.hole)}" 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": cabinet_id, # "drawer_id": self.drawer_board_obj.drawer_id, # "drawer_board_id": self.drawer_board_obj.id, "hole": self.drug_obj.hole, "position": position, } await DrugUseLog().create(**drug_use_dict) # 更新药剂信息 drug_update_dict = { "state": DrugStateEnum.OUT if self.drug_obj.state != DrugStateEnum.EMPTY else DrugStateEnum.EMPTY, # "last_weight": 0, # "drawer_board": self.drawer_board_obj, # "board_id": self.drawer_board_obj.board_id, "last_receive_at": self._now_strftime(), "last_receive_id": self.users[0], "position": position, } await self.drug_obj.update_from_dict(drug_update_dict) await self.drug_obj.save() dic_obj = await Dictionary.get(id=drug_obj.dictionary.id) dic_obj.use_count += 1 await dic_obj.save() # data = { # "drug_info": await self.drug_obj.attribute_drug_info(), # "position": 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"], # "unit_code": self.drug_obj.attribute("unit_code"), # 单位编码 # "expired_at": self.drug_obj.expired_at.strftime("%Y-%m-%d"), # 过期时间 # "fill_json_content": self.drug_obj.fill_json_content # } # await self.write_log("take_out", drug_use_dict) # # 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