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.

355 lines
12 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#!/usr/bin/env python
# encoding: utf-8
"""
@author: tx
@file: drug.py
@time: 2023/5/11 11:04
@desc: 药剂领用归还
"""
from decimal import Decimal
from fastapi import APIRouter, Request, Depends
from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel
from tortoise.queryset import Q
from conf import setting
from helper.drug import drugs_except_info, drugs_list_info, gram_to_milligram, milligram_to_gram, open_update_expired_at
from helper import respond_to, login_required
from models import Dictionary
from models.drug import Drug, DrugStateEnum
from models.terminal import Terminal
from models.drawers import Drawer
from models.cabinet import Cabinet
from transfer.standard import Standard
from transfer.code_standard import CodeStandard
router = APIRouter(prefix='/drugs', dependencies=[Depends(login_required)])
class DrugUpdateRequest(BaseModel):
open_date: str = "" # 开封日期
weight: Decimal = 0.0 # 余量
use_weight: Decimal = 0.0 # 用量
rfid: str = ""
id: str = ""
class DrugUpdateExpired(BaseModel):
expired_at: str
rfid: str = ""
id: str = ""
class DrugRfids(BaseModel):
rfids: list
class DrugTakeOut(BaseModel):
terminal_id: str | None
page_no: int = 1
page_size: int = 20
class UpdateDictionary(BaseModel):
lack_stock_count: int = 0
expiration_alert: int = 0
class EmptyBottleDisposal(BaseModel):
rfid: str
weight: int | None
open_date: str | None
class ReturnForm(BaseModel):
# barcode: str
weight: Decimal = 0.0 # 余量
use_weight: Decimal = 0.0 # 用量
drawer_id: str = '' # 层id
@router.post('/empty', summary='试剂置为空瓶')
async def empty_bottle_disposal(request: Request, post: EmptyBottleDisposal):
"""
试剂置为空瓶
:param request: Request请求头信息
:param post: 空瓶信息的请求体
:return:
"""
users = request.state.users
standard = Standard(users)
rfid = post.rfid
# user_weight = post.weight
open_date = post.open_date
if open_date:
drug = await Drug.get(rfid=rfid)
drug.open_date = open_date
await drug.save()
await standard.empty(rfid)
return respond_to()
@router.post('/weight', summary="药剂用量或余量更新")
async def update(keyword: DrugUpdateRequest):
"""
药剂用量或余量更新
接收id或rfid都可以更新重量
余量与用量二选一,只有一个有值
:param keyword: 包含更新信息的请求体
:return:
"""
print("open_date", keyword.open_date)
rfid = keyword.rfid if keyword.rfid else ""
query_param = {"id": keyword.id} if keyword.id else {"rfid": rfid}
drug_obj = await Drug.get(**query_param).prefetch_related("template")
if keyword.weight:
mill_weight = keyword.weight
await drug_obj.update_last_weight(weight=mill_weight)
elif keyword.use_weight:
mill_weight = keyword.use_weight
await drug_obj.update_last_use_weight(weight=mill_weight)
if keyword.open_date:
if not drug_obj.open_date:
drug_obj.open_date = keyword.open_date
template_obj = await drug_obj.template
new_expired_at = open_update_expired_at(drug_obj, template_obj, keyword.open_date)
if new_expired_at:
drug_obj.expired_at = new_expired_at
await drug_obj.save()
return respond_to(code=200, desc="重量更新成功")
@router.post('/except', summary='RFID药剂异常信息')
async def index(request: DrugRfids):
"""
获取RFID药剂异常信息
:return:
"""
result = list()
drugs = await Drug.filter(rfid__in=request.rfids).prefetch_related('dictionary', 'template').all()
terminal_obj = await Terminal.get(id=setting.TERMINAL_ID)
for drug in drugs:
data = await drugs_except_info(drug, terminal_obj)
data["rfid"] = drug.rfid
result.append(data)
# 传入rfid与data所有rfid比较差集就是非法标签
post_rfid = set(request.rfids)
effective_rfid = set([i["rfid"] for i in result])
diff_rfid = post_rfid - effective_rfid
if diff_rfid:
result.extend([{
"rfid": rfid,
"is_rfid_except": True,
"sound": True,
"message": "非法标签",
"state": 0,
} for rfid in diff_rfid])
return respond_to(code=200, desc="获取RFID药剂信息成功", data=result)
@router.post('', summary='RFID药剂详情')
async def index(request: DrugRfids):
"""
获取RFID药剂信息 药剂信息详情
:return:
"""
drugs = list()
for rfid in request.rfids:
drug_obj = await Drug.get_or_none(rfid=rfid).prefetch_related('dictionary', 'template')
if drug_obj is None:
continue
result = jsonable_encoder(drug_obj)
template_obj = await drug_obj.template
terminal_obj = await Terminal.get(id=setting.TERMINAL_ID)
data = await drugs_except_info(drug_obj, terminal_obj)
drug_info = await drug_obj.attribute_drug_info()
parse_fill_json_content = await drug_obj.parse_fill_json_content()
parse_fill_json_content.update({f'余重': f'{milligram_to_gram(drug_obj.remain_gross_weight)}'})
return_require_weigh = template_obj.archive.params.get("return_require_weigh", '')
result.update({
"drugs_except_info": data,
"fill_json_content": parse_fill_json_content,
"rfid_drug": {drug_obj.rfid: f"[{drug_obj.rfid}]" + ",".join(list(map(lambda x:str(x), drug_info.values()))) + "," +
f"{drug_obj.remain_gross_weight}"},
"return_require_weigh": return_require_weigh
})
drugs.append(result)
return respond_to(code=200, desc="获取RFID药剂信息成功", data=drugs)
@router.get('', summary='药剂列表查询')
async def index(request: Request, drug_name: str = '', page_no: int = 1, page_size: int = 20):
"""
货架药剂列表查询
:return:
"""
query = Drug.filter()
cabinets_ids = await Cabinet.filter(type=3).values_list("id", flat=True)
if cabinets_ids:
query = query.filter(cabinet_id__in=cabinets_ids)
if drug_name:
query = query.filter(Q(dictionary__k1__contains=drug_name) | Q(dictionary__k2__contains=drug_name))
total_count = await query.count()
offset = (page_no - 1) * page_size
drugs = await query.offset(offset).limit(page_size).all()
result = await drugs_list_info(drugs)
return respond_to(200, data=dict(count=total_count, drugs=result))
@router.get('/take_out', summary='药剂领用查询')
async def index(request: Request, drug_name: str = '', take_out_type: int = 0, page_no: int = 1, page_size: int = 20):
"""
药剂领用列表查询
本终端的排前面
:return:
"""
terminal = await Terminal.get(id=setting.TERMINAL_ID)
query = Drug.filter(state=DrugStateEnum.IN).order_by('-drawer_board_id')
if not take_out_type:
query = query.filter(drawer_board__cabinet__terminal=terminal)
if drug_name:
query = query.filter(Q(dictionary__k1__contains=drug_name) | Q(dictionary__k2__contains=drug_name))
total_count = await query.count()
offset = (page_no - 1) * page_size
drugs = await query.offset(offset).limit(page_size).all()
result = await drugs_list_info(drugs)
return respond_to(200, data=dict(count=total_count, drugs=result))
@router.get('/put_in', summary='获取当前用户待归还清单')
async def index(request: Request):
"""
获取当前用户壁挂终端待归还清单
:return:
"""
current_user = request.state.current_user
terminal = await Terminal.get(id=setting.TERMINAL_ID)
# 当前柜体待归还清单
query = Drug.filter(last_receive_id=current_user.id, state=DrugStateEnum.OUT).filter(cabinet__terminal=terminal)
drugs = await query.all()
result = await drugs_list_info(drugs)
return respond_to(data=result)
@router.put('/expired_at', summary='药剂信息修改')
async def update(keyword: DrugUpdateExpired):
"""
药剂信息过期时间修改
:param id: 用户药剂模板条目id
:param keyword:
:return:
"""
rfid = keyword.rfid if keyword.rfid else ""
query_param = {"id": keyword.id} if keyword.id else {"rfid": rfid}
drug_obj = await Drug.get(**query_param)
drug_obj.expired_at = keyword.expired_at
await drug_obj.save()
return respond_to(code=200, desc="更新成功")
@router.get('/dictionaries', summary='获取药剂字典列表')
async def index(keyword: str = '', page_no: int = 1, page_size: int = 10):
"""
获取药剂字典列表
:param keyword: 按药剂信息搜索
:param page_no: 分页页码默认为1
:param page_size: 分页大小默认为10
:return:
"""
dictionaries = await Dictionary.all().offset((page_no - 1) * page_size).limit(page_size).values()
result_list = []
for dictionary in dictionaries:
drug_info = ",".join([value for key, value in dictionary.items() if key.startswith('k') and value is not None])
if keyword in drug_info:
dictionary['drug_info'] = drug_info
for k, v in dictionary['params'].items():
dictionary[k] = v
result_list.append(dictionary)
return respond_to(data={'data': result_list, 'count': len(result_list)})
@router.put('/dictionary/{id}', summary='编辑药剂字典')
async def update(id: str, post: UpdateDictionary):
"""
编辑药剂字典
:param id: id
:param post:
:return:
"""
dictionary = await Dictionary.get(id=id)
dictionary.params = post.dict()
await dictionary.save()
return respond_to()
@router.put('/receive/{bar_code}', summary='药剂领用')
async def update(request: Request, bar_code: str):
"""
药剂领用
每瓶药剂扫码即领用
:param request: request
:param bar_code: 药剂条码
:return:
"""
drug_obj = await Drug.get_or_none(Q(barcode=bar_code) | Q(rfid=bar_code)).prefetch_related('template', 'dictionary')
if not drug_obj:
return respond_to(code=404, desc="药剂未找到")
if drug_obj.state in [DrugStateEnum.OUT, DrugStateEnum.EMPTY]:
desc = "药剂不在库" if DrugStateEnum.OUT else "药剂已空瓶"
return respond_to(code=400, desc=desc)
users = request.state.users
standard = CodeStandard(users, drug_obj)
transfer_results = await standard.take_out(barcode=bar_code)
print('领用结果', transfer_results)
return respond_to(desc="领用完成", data=transfer_results)
@router.put('/return/{bar_code}', summary='药剂归还')
async def update(request: Request, bar_code: str, keyword: ReturnForm):
"""
药剂归还
药剂扫码后填入用量/余量,归还成功
:param bar_code: 药剂条码
:param post:
:return:
"""
# 如果调用保存已经保存过用量数据,则不再进行保存
drug_obj = await Drug.get_or_none(Q(barcode=bar_code) | Q(rfid=bar_code)).prefetch_related('template', 'dictionary')
if not drug_obj:
return respond_to(code=404, desc="药剂未找到")
if drug_obj.state == DrugStateEnum.IN:
return respond_to(code=401, desc="药剂已在库,请勿再次归还!")
if keyword.weight:
# 余量转用量,更新用量
mill_weight = drug_obj.remain_gross_weight - keyword.weight
await drug_obj.update_last_use_weight(weight=mill_weight)
elif keyword.use_weight:
mill_weight = keyword.use_weight
await drug_obj.update_last_use_weight(weight=mill_weight)
# 位置更新
if keyword.drawer_id:
drawer_obj = await Drawer.get(id=keyword.drawer_id).prefetch_related("cabinet")
cabinet = drawer_obj.cabinet
position_str = f"{cabinet.label}-{drawer_obj.label}"
drug_obj.drawer = drawer_obj
drug_obj.cabinet = cabinet
drug_obj.position = position_str
await drug_obj.save()
users = request.state.users
standard = CodeStandard(users, drug_obj)
transfer_results = await standard.put_in(barcode=bar_code)
print('归还结果', transfer_results)
return respond_to(desc="归还完成", data=transfer_results)