|
|
#!/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)
|