#!/usr/bin/env python # encoding: utf-8 """ @author: tx @file: warehouse.py @time: 2023/5/8 17:53 @desc: """ import re from datetime import datetime, timedelta from fastapi import APIRouter, Depends, Request from pydantic import BaseModel from tortoise.expressions import Q from helper import login_required, respond_to from helper.logger import logger from helper.utils import timezone_now from transfer.code_standard import CodeStandard from transfer.standard import Standard from models import Template from models.archive import Archive from models.dictionary import Dictionary from models.drawers import Drawer from models.drug import Drug from models.storage_form import StorageForm from models.cabinet import Cabinet router = APIRouter(prefix="/warehousing", dependencies=[Depends(login_required)]) class WarehouseingDrugBinding(BaseModel): drug_list: list @router.get('/item/{storageId}', summary='获取绑定入库可选条目') async def index(request: Request, storageId: str): """ 用户入库模板条目 :param storageId: 模板id :return: """ storage_form = await StorageForm.get_or_none(id=storageId).prefetch_related('template') template = await Template.get(id=storage_form.template.id) if not storage_form: return respond_to(404, desc="导入目标条目未查询到") if not template.xlsx: result = { "template_xlsx": {}, "data": [], } return result template_xlsx = template.parse_xlsx_transfer() archive_obj = await Archive.get(id=request.state.archive_id) return_require_weigh = archive_obj.params.get("return_require_weigh", '') resContent = list() for item in storage_form.fill_json_content: itemContent = item.get("fill_json_content") if not itemContent: continue itemNum = itemContent.get("import_count") if not itemNum: continue for i in range(int(itemNum)): resContent.append(item) data = { "id": storage_form.id, "return_require_weigh": return_require_weigh, "storage_fill_json_content": resContent } result = { "template_xlsx": template_xlsx, "data": data } return respond_to(data=result) @router.post('/binding', summary="入库绑定上传") async def binding_warehousing_drug(request: Request, body: WarehouseingDrugBinding): """ 绑定入库上传 already_import_count :param request: Request :param drug_list: [{"storage_item_id", str, "rfid": str, "gross_weight": float}] :return: {"abnormal_drugs": List[Dict], "normal_drugs": List[Dict]} """ drug_list = body.drug_list if not drug_list: return respond_to(code=400, desc="绑定药剂为空,上传数据有误") current_user = request.state.current_user normal_drugs, abnormal_drugs = list(), list() drug_data = list() archive_id = request.state.archive_id if not archive_id: return respond_to(code=400, desc="未获取大类信息") template_obj = await Template.get(archive_id=archive_id).prefetch_related('archive') is_in_weight = template_obj.archive.params.get("storage_require_weigh") print(drug_list) for drug in drug_list: if not drug.get("rfid") or not drug.get("fill_json_content"): abnormal_drugs.append(drug) continue fill_json_content = drug["fill_json_content"] drug_type = fill_json_content.get("drug_type", 'normal') # 如果字典不存在改试剂条目,则新增字典条目信息 if drug_type == "box": k_args = {"k1": fill_json_content.get("box_name")} query = Q(**k_args) else: k_args = {f'k{i}': fill_json_content.get(f'k{i}') for i in range(1, 7) if fill_json_content.get(f'k{i}')} k_args_with_null = {k: None for k, v in k_args.items() if v is None} query = Q(**k_args) & Q(**k_args_with_null) dictionary_obj = await Dictionary.filter(query).first() if not dictionary_obj: k_args["archive"] = template_obj.archive k_args["params"] = {"lack_stock_count": 10, "expiration_alert": 30} dictionary_obj = await Dictionary.create(**k_args) if is_in_weight and not drug.get("gross_weight"): abnormal_drugs.append(drug) logger.warning("[入库需称重]入库药剂条目未称重:{0}".format(drug)) continue rfid = drug.get("rfid").upper() # 过期日期如果有填写(生产日期保质期),则添加过期日期字段 if fill_json_content.get("expire_date"): expired_at = fill_json_content.get("expire_date") elif fill_json_content.get("lateDate"): expired_at = fill_json_content.get("lateDate") elif not fill_json_content.get("produce_date") or not fill_json_content.get("shelf_life"): expired_at = "" else: produce_date = fill_json_content.get("produce_date") shelf_life = fill_json_content.get("shelf_life") production_date = datetime.strptime(produce_date, '%Y-%m-%d') shelf_life_date = timedelta(days=int(shelf_life)) expired_at = production_date + shelf_life_date expired_at = expired_at.strftime('%Y-%m-%d') mill_gross_weight = drug.get("gross_weight") if mill_gross_weight is None and fill_json_content.get("gross_weight"): mill_gross_weight = fill_json_content.get("gross_weight") # 位置信息 cabinet = await Cabinet.get(id=drug.get("cabinet_id")) position_str = f"{cabinet.label}" if drug.get("drawer_id"): drawer_obj = await Drawer.get(id=drug.get("drawer_id")) position_str += f"-{drawer_obj.label}" now = timezone_now() drug_dict = { "dictionary_id": dictionary_obj.id, "rfid": rfid, "fill_json_content": fill_json_content, "bind_id": current_user.id, "bind_at": now, "storage_id": current_user.id, "storage_at": now, "template": template_obj, "cabinet_id": drug.get("cabinet_id"), "position": position_str, "state": 0 if len(rfid) >= 16 else 1, "barcode": rfid if len(rfid) < 16 else '', "taboo_species": fill_json_content.get("taboo_species", ""), # 药剂禁忌种类 "drug_type": drug_type, # 盒装药剂 普通药剂 } if mill_gross_weight: drug_dict.update({ "remain_gross_weight": convert_to_mg(mill_gross_weight) }) if drug.get("drawer_id"): drug_dict.update({ "drawer_id": drug.get("drawer_id"), }) if expired_at: drug_dict.setdefault("expired_at", expired_at) drug_data.append(drug_dict) # 药剂批量保存 except_info = "" for data in drug_data: try: print(data) drug_obj = await Drug.create(**data) normal_drugs.append(data) # 生成流转记录 if len(drug_obj.rfid) < 16: standard = CodeStandard(request.state.users, drug_obj) await standard.put_in(barcode=drug_obj.barcode) # 盒装药剂明细保存 if data.get("drug_type") == "box": await drug_obj.box_item_generate(drug_items=data.get("fill_json_content").get("drug_items")) except Exception as e: logger.error("药剂导入绑定异常:{0}".format(e)) except_info += "药剂导入绑定异常:{0}".format(e) abnormal_drugs.append(data) desc = except_info if abnormal_drugs else "药剂保存成功" return respond_to(code=200, desc=desc, data={"abnormal_drugs": abnormal_drugs, "normal_drugs": normal_drugs}) def convert_to_mg(value): # 如果是纯数字,则直接返回该数字 if isinstance(value, (int, float)): return value # 定义正则表达式,匹配以数字开头,可带小数点,后跟 g 或 mg 结尾的模式 pattern = r'^(\d+(\.\d+)?)(\s*)(g|mg)?$' # 使用正则表达式进行匹配 match = re.match(pattern, value) if match: # 获取匹配到的数值部分和单位 numeric_part = match.group(1) unit = match.group(4) # 如果有单位,并且单位是 'g',则转换为毫克 'mg' if unit == 'g': numeric_value = float(numeric_part) * 1000 # 将克转换为毫克 else: numeric_value = float(numeric_part) return int(numeric_value) # 返回整数型的毫克值 return None # 如果没有匹配成功,返回 None 或者你认为合适的默认值