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.
473 lines
22 KiB
473 lines
22 KiB
# -*- coding: utf-8 -*-
|
|
"""
|
|
api.stock
|
|
~~~~~~~~~~~~~~
|
|
|
|
有关进出库的接口.
|
|
|
|
:copyright: 云南新八达科技有限公司.
|
|
:author: 李进才.
|
|
"""
|
|
import gevent
|
|
|
|
from diff.stock import getDiffStockList
|
|
from utils import instockHelper
|
|
from utils.PageHepler import db_page, entityDictToStringDict, db_page_entity
|
|
from utils.apiDoc import *
|
|
from models.stockListModel import *
|
|
from models.InStockModel import *
|
|
from utils.configOperatingTypeHelper import GetOperatingTypeInStock, GetOperatingTypeDelete, GetOperatingTypeUpdate, \
|
|
GetOperatingTypeEdit
|
|
from utils.entryHelper import get_entry_list
|
|
from utils.listHelper import *
|
|
from utils.BatchCode import *
|
|
from models.reagentTypeList import *
|
|
from pypinyin import lazy_pinyin, Style
|
|
from io import BytesIO
|
|
import pandas as pd
|
|
|
|
from utils.nativeDbHelper import HisMssqlConnect
|
|
from utils.outStockHelper import *
|
|
from sqlalchemy import or_, func
|
|
from utils.ReagentTypeListSort import *
|
|
from utils.pandasHelper import null_value
|
|
|
|
|
|
@stock.route('/list')
|
|
class StockList(Resource):
|
|
@staticmethod
|
|
def post():
|
|
"""
|
|
get stock info list
|
|
:return: stock list
|
|
"""
|
|
data = request.args
|
|
filterObject = getDiffStockList()
|
|
if data.get('query') is not None and data.get('query') != '':
|
|
filterObject = filterObject.filter(or_(ReagtStock.PinYinCode.contains(data['query']),
|
|
ReagtStock.Position.contains(data['query']),
|
|
ReagtReagent.Name.contains(data['query']),
|
|
ReagtStock.Code.contains(data['query'])))
|
|
if data.get('groupName') is not None and data.get('groupName') != '':
|
|
filterObject = filterObject.filter(ReagtReagent.GroupName == data['groupName'])
|
|
if data.get('reportItemName') is not None and data.get('reportItemName') != '':
|
|
filterObject = filterObject.filter(ReagtReagent.ReportItem == data.get('reportItemName'))
|
|
data_list = db_page(filterObject, ReagtStock.InTime, data, 10)
|
|
return SuccessResponse(ResultCode.SUCCESS, {'totalNumber': filterObject.count(), 'list': data_list}, None)
|
|
|
|
|
|
@stock.route('/add')
|
|
class StockAdd(Resource):
|
|
"""
|
|
试剂耗材入库
|
|
"""
|
|
|
|
@staticmethod
|
|
@stock.doc(body=[in_stock_model])
|
|
def post():
|
|
token = request.headers.get('X-Token')
|
|
batchCode = GetBatchCode()
|
|
inStockTime = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
for item in request.json['inStockData']:
|
|
data = Dict2Obj(item)
|
|
instockHelper.in_stock(data, batchCode, inStockTime, token, request.json)
|
|
try:
|
|
db.session.commit()
|
|
except gevent.Timeout:
|
|
db.session.invalidate()
|
|
raise
|
|
return SuccessResponse(ResultCode.ERROR, None, None)
|
|
except Exception:
|
|
db.session.rollback()
|
|
raise
|
|
return SuccessResponse(ResultCode.ERROR, None, None)
|
|
return SuccessResponse(ResultCode.SUCCESS,
|
|
{'inStockBatchCode': batchCode, 'verifyPeople': verify_jwt_username(token)}, None)
|
|
|
|
|
|
@stock.route('/hisOutCodeList')
|
|
class HisOutCodeList(Resource):
|
|
"""
|
|
his出库单列表
|
|
"""
|
|
|
|
@staticmethod
|
|
def get():
|
|
reagent_int_int_code = db.session.query(ReagtReceipt.ReceiptCode.label('ReceiptCode')) \
|
|
.filter(ReagtReceipt.ReceiptCode.contains('E')) \
|
|
.group_by(ReagtReceipt.ReceiptCode).all()
|
|
reagent_int_int_code_string = ','.join(F'\'{str(code)[2:-2]}' for code in reagent_int_int_code)
|
|
if reagent_int_int_code_string is '':
|
|
his_out_list_code = HisMssqlConnect() \
|
|
.query("LIS_OutSheet_CL", F"select 出库单号,出库日期 from LIS_OutSheet_CL(nolock) "
|
|
F"where 出库名称 = '检验科' "
|
|
F"group by 出库单号,出库日期 "
|
|
F"ORDER BY 出库日期 DESC", cols=['出库单号', '出库日期']) \
|
|
.drop_duplicates()
|
|
else:
|
|
his_out_list_code = HisMssqlConnect() \
|
|
.query("LIS_OutSheet_CL", F"select 出库单号,出库日期 from LIS_OutSheet_CL(nolock) "
|
|
F"where 出库名称 = '检验科' "
|
|
F"and 出库单号 not in ({reagent_int_int_code_string}) "
|
|
F"group by 出库单号,出库日期 "
|
|
F"ORDER BY 出库日期 DESC", cols=['出库单号', '出库日期']) \
|
|
.drop_duplicates()
|
|
if request.args.get('query') is not None:
|
|
his_out_list_code = HisMssqlConnect() \
|
|
.query("LIS_OutSheet_CL",
|
|
F"select * from LIS_OutSheet_CL(nolock) where "
|
|
F"出库名称 = '检验科' and 出库单号 like '%{str.strip(request.args.get('query'))}%'") \
|
|
.drop_duplicates()
|
|
return SuccessResponse(ResultCode.SUCCESS, {'totalNumber': len(his_out_list_code),
|
|
'list': dataFrame_paginate(his_out_list_code,
|
|
request.args.get('pageNumber'), 10, 10)
|
|
.to_dict()},
|
|
None)
|
|
|
|
|
|
@stock.route('/hisOutList')
|
|
class HisOutList(Resource):
|
|
"""
|
|
出库单对应的试剂或者耗材列表
|
|
"""
|
|
|
|
@staticmethod
|
|
def get():
|
|
his_out_list = HisMssqlConnect() \
|
|
.query("LIS_OutSheet_CL",
|
|
F"select * from LIS_OutSheet_CL(nolock) where 出库名称 = '检验科' and 出库单号='{request.args.get('outCode')}'")
|
|
his_out_list_page = dataFrame_paginate(his_out_list, request.args.get('pageNumber'), 10, 10).to_dict()
|
|
return SuccessResponse(ResultCode.SUCCESS, {'totalNumber': len(his_out_list),
|
|
'list': his_out_list_page}, None)
|
|
|
|
|
|
@stock.route('/hisListExport')
|
|
class HisListExport(Resource):
|
|
"""
|
|
his出库的文件下载
|
|
"""
|
|
|
|
@staticmethod
|
|
def get():
|
|
if request.args.get('outCode') is not None:
|
|
his_out_list = HisMssqlConnect() \
|
|
.query("LIS_OutSheet_CL",
|
|
F"select * from LIS_OutSheet_CL(nolock) "
|
|
F"where 出库名称 = '检验科' and 出库单号='{request.args.get('outCode')}'")
|
|
else:
|
|
reagent_int_int_code = db.session.query(ReagtReceipt.ReceiptCode.label('ReceiptCode')) \
|
|
.filter(ReagtReceipt.ReceiptCode.contains('E')) \
|
|
.group_by(ReagtReceipt.ReceiptCode).all()
|
|
reagent_int_int_code_string = ','.join(F'\'{str(code)[2:-2]}' for code in reagent_int_int_code)
|
|
his_out_list = HisMssqlConnect() \
|
|
.query("LIS_OutSheet_CL",
|
|
F"select * from LIS_OutSheet_CL(nolock) "
|
|
F"where 出库名称 = '检验科' and 出库单号 not in ({reagent_int_int_code_string})"
|
|
F"ORDER BY 出库日期 DESC")
|
|
his_out_list.drop(his_out_list.columns[[i for i in range(1, 5)]], axis=1, inplace=True)
|
|
bio = BytesIO()
|
|
his_out_list.style.applymap(null_value, subset=['耗材名称', '耗材规格', '生产厂家',
|
|
'存放位置', '耗材类型', '最大单位',
|
|
'进价(元) 批发价(批发单位)', '售价(元) 零售价(批发单位)',
|
|
'最大库存量(大单位为主)', '出库数量(批发单位)',
|
|
'有效期']) \
|
|
.to_excel(bio, index=False, encoding='utf-8')
|
|
bio.seek(0)
|
|
fileByte = bio.getvalue()
|
|
bio.close()
|
|
return Response(fileByte, content_type='application/vnd.ms-excel')
|
|
|
|
|
|
@stock.route('/delete')
|
|
class Delete(Resource):
|
|
"""
|
|
删除试剂或者耗材
|
|
"""
|
|
|
|
@staticmethod
|
|
def get():
|
|
token = request.headers.get('X-Token')
|
|
data = request.args
|
|
app.logger.info(data)
|
|
delete_stock = ReagtStock.query.filter_by(StockId=int(data.get('StockId'))).first()
|
|
if 'E' in delete_stock.Code:
|
|
return SuccessResponse(ResultCode.NOT_ALLOW_DELETE_HIS_IN_STOCK_INTO, None, None)
|
|
db.session.delete(delete_stock)
|
|
LogAdd(token, GetOperatingTypeDelete(), data, delete_stock.Code, data.get('Name'),
|
|
list2String(lazy_pinyin(data.get('Name') + data.get('Specification'), style=Style.FIRST_LETTER)),
|
|
data.get('LastNumber'), data.get('Specification'), data.get('Position'),
|
|
reagentId=delete_stock.ReagentId)
|
|
db.session.commit()
|
|
return SuccessResponse(ResultCode.SUCCESS, None, None)
|
|
|
|
|
|
@stock.route('/receiptDelete')
|
|
class ReceiptDelete(Resource):
|
|
"""
|
|
从入库单删除整个入库信息
|
|
"""
|
|
|
|
@staticmethod
|
|
def get():
|
|
token = request.headers.get('X-Token')
|
|
data = request.args
|
|
app.logger.info(data)
|
|
delete_stock_list = ReagtStock.query.filter_by(Code=data.get('Code')).all()
|
|
delete_receipt = ReagtReceipt.query.filter_by(ReceiptCode=data.get('Code')).first()
|
|
db.session.delete(delete_receipt)
|
|
for delete_stock in delete_stock_list:
|
|
db.session.delete(delete_stock)
|
|
reagent = ReagtReagent.query.filter_by(ReagentId=delete_stock.ReagentId).first()
|
|
LogAdd(token, GetOperatingTypeDelete(), data, delete_stock.Code, reagent.Name,
|
|
list2String(lazy_pinyin(reagent.Name + reagent.Specification, style=Style.FIRST_LETTER)),
|
|
delete_stock.LastNumber, reagent.Specification, delete_stock.Position,
|
|
reagentId=delete_stock.ReagentId, remark='删除his入库信息')
|
|
db.session.commit()
|
|
return SuccessResponse(ResultCode.SUCCESS, None, None)
|
|
|
|
|
|
@stock.route('/typeList')
|
|
class TypeList(Resource):
|
|
"""
|
|
按照汇总分类列表
|
|
"""
|
|
|
|
@staticmethod
|
|
def post():
|
|
data = request.args
|
|
filterObject = ReagtReagent.query.join(ReagtStock,
|
|
ReagtStock.ReagentId == ReagtReagent.ReagentId).distinct().order_by(
|
|
ReagtReagent.ReagentId.desc())
|
|
if data.get('query') is not None:
|
|
filterObject = ReagtReagent.query.join(ReagtStock,
|
|
ReagtStock.ReagentId == ReagtReagent.ReagentId) \
|
|
.filter(or_(ReagtStock.PinYinCode.contains(data['query']), ReagtReagent.Name.contains(data['query']))) \
|
|
.distinct().order_by(ReagtReagent.ReagentId.desc())
|
|
reagentBasicsPaginate = filterObject.paginate(
|
|
int(data['pageNumber']), 10,
|
|
error_out=False)
|
|
reagentTypeList = []
|
|
if reagentBasicsPaginate.items is not None:
|
|
for reagent in reagentBasicsPaginate.items:
|
|
reagentType = ReagentTypeList(ReagentId=reagent.ReagentId, Name=reagent.Name,
|
|
Specification=reagent.Specification,
|
|
Maker=reagent.Maker, CertificationCode=reagent.CertificationCode,
|
|
UnitPrice=reagent.UnitPrice, SellingPrice=reagent.SellingPrice,
|
|
MaxValue=reagent.MaxValue, MinValue=reagent.MinValue,
|
|
TypeName=reagent.TypeName, hasChildren=True)
|
|
reagentTypeList.append(reagentType.value())
|
|
return SuccessResponse(ResultCode.SUCCESS, {"totalNumber": filterObject.count(),
|
|
"list": ReagentTypeSort(reagentTypeList)}, None)
|
|
|
|
|
|
@stock.route('/typeInfo')
|
|
class TypeInfo(Resource):
|
|
"""
|
|
汇总分类下的子信息
|
|
"""
|
|
|
|
@staticmethod
|
|
def get():
|
|
data = request.args
|
|
reagentStockInfo = ReagtStock.query.filter_by(ReagentId=data['ReagentId']).all()
|
|
return SuccessResponse(ResultCode.SUCCESS, reagentStockInfo, None)
|
|
|
|
|
|
@stock.route('/outStockList')
|
|
class OutStockList(Resource):
|
|
"""
|
|
出库列表
|
|
"""
|
|
|
|
@staticmethod
|
|
def get():
|
|
data = request.args
|
|
outStockReagentFilter = db.session.query(ReagtReagent.Name.label('Name'),
|
|
ReagtReagent.Specification.label('Specification'),
|
|
ReagtStock.Position.label('Position'),
|
|
ReagtReagent.Unit.label('Unit'),
|
|
ReagtReagent.SmallestUnit.label('SmallestUnit'),
|
|
ReagtReagent.Ratio.label('Ratio'),
|
|
ReagtStock.ProductionBatch.label('ProductionBatch'),
|
|
func.sum(ReagtStock.LastNumber).label('TotalNumber'),
|
|
func.sum(ReagtStock.MinNumberUnit).label('MinNumberUnit')). \
|
|
join(ReagtReagent, ReagtStock.ReagentId == ReagtReagent.ReagentId). \
|
|
group_by(ReagtReagent.Name, ReagtStock.ReagentId, ReagtStock.Position, ReagtReagent.Specification,
|
|
ReagtReagent.Unit, ReagtReagent.SmallestUnit, ReagtReagent.Ratio, ReagtStock.ProductionBatch)
|
|
if data.get('query') is not None and data.get('query') != '':
|
|
outStockReagentFilter = outStockReagentFilter.filter(
|
|
or_(ReagtReagent.Name.contains(data['query']), ReagtStock.Position.contains(data['query']),
|
|
ReagtReagent.Specification.contains(data['query']), ReagtStock.PinYinCode.contains(data['query'])))
|
|
if data.get('groupName') is not None and data.get('groupName') != '':
|
|
outStockReagentFilter = outStockReagentFilter.filter(ReagtReagent.GroupName == data.get('groupName'))
|
|
if data.get('reportItemName') is not None and data.get('reportItemName') != '':
|
|
outStockReagentFilter = outStockReagentFilter.filter(ReagtReagent.ReportItem == data.get('reportItemName'))
|
|
outStockReagentPage = outStockReagentFilter.order_by(ReagtStock.Position.desc()).paginate(
|
|
int(data['pageNumber']), 10,
|
|
error_out=False)
|
|
resultList = [dict(zip(result.keys(), result)) for result in outStockReagentPage.items]
|
|
return SuccessResponse(ResultCode.SUCCESS, {'totalNumber': outStockReagentFilter.count(),
|
|
'list': resultList}, None)
|
|
|
|
|
|
@stock.route('/outStock')
|
|
class OutStock(Resource):
|
|
"""
|
|
出库试剂或者耗材
|
|
"""
|
|
|
|
@staticmethod
|
|
def post():
|
|
token = request.headers.get('X-Token')
|
|
for item in request.json['outStockData']:
|
|
priorityDelivery(item, 1, token, request.json)
|
|
return SuccessResponse(ResultCode.SUCCESS,
|
|
{'outStockBatchCode': GetBatchCode(), 'verifyPeople': verify_jwt_username(token)}, None)
|
|
|
|
|
|
@stock.route('/update')
|
|
class Update(Resource):
|
|
"""
|
|
调整库存信息
|
|
"""
|
|
|
|
@staticmethod
|
|
def post():
|
|
token = request.headers.get('X-Token')
|
|
reagent_stock = ReagtStock.query.filter_by(StockId=request.json.get('StockId')).first()
|
|
data = {'Remark': '库存数量调整,大单位剩余数量由' + str(reagent_stock.LastNumber) + '调整为' +
|
|
str(request.json.get('ChangeNumber')) + '小单位数量由' + str(
|
|
reagent_stock.MinNumberUnit) + '调整为' +
|
|
str(request.json.get('ChangeMinUnitNumber'))}
|
|
if request.json.get('ChangeNumber') is 0 and request.json.get('ChangeMinUnitNumber') is 0:
|
|
db.session.delete(reagent_stock)
|
|
db.session.commit()
|
|
else:
|
|
reagent_stock.LastNumber = request.json.get('ChangeNumber')
|
|
reagent_stock.MinNumberUnit = request.json.get('ChangeMinUnitNumber')
|
|
db.session.commit()
|
|
reagent_reagent = ReagtReagent.query.filter_by(ReagentId=reagent_stock.ReagentId).first()
|
|
LogAdd(token, GetOperatingTypeUpdate(), data, reagent_stock.Code, reagent_reagent.Name,
|
|
list2String(lazy_pinyin(reagent_reagent.Name + reagent_reagent.Specification, style=Style.FIRST_LETTER)),
|
|
request.json.get('ChangeNumber'), reagent_reagent.Specification, reagent_stock.Position)
|
|
db.session.commit()
|
|
return SuccessResponse(ResultCode.SUCCESS, None, None)
|
|
|
|
|
|
@stock.route('/barCode')
|
|
class BarCode(Resource):
|
|
"""
|
|
条码出库信息,根据条码查询当前试剂或者耗材信息
|
|
"""
|
|
|
|
@staticmethod
|
|
def get():
|
|
data = request.args
|
|
filterObject = getDiffStockList().filter(ReagtStock.BarCode == data.get('barCode'))
|
|
return SuccessResponse(ResultCode.SUCCESS, db_page(filterObject, ReagtStock.InTime, data, 1)
|
|
, None)
|
|
|
|
|
|
@stock.route('/barCodeHistory')
|
|
class BarCodeHistory(Resource):
|
|
"""
|
|
条码出库历史
|
|
"""
|
|
|
|
@staticmethod
|
|
def get():
|
|
data = request.args
|
|
filterObject = db.session.query(ReagtLog.OperatingTime,
|
|
ReagtLog.Code,
|
|
ReagtLog.BarCode,
|
|
ReagtLog.LogId,
|
|
ReagtLog.OperatingPeople,
|
|
ReagtLog.ReagentName,
|
|
ReagtLog.ReagentNumber,
|
|
ReagtLog.ReagentPosition,
|
|
ReagtLog.ReagentSpecification,
|
|
ReagtLog.Remark).filter(ReagtLog.OperatingType == 'OutStock')
|
|
return SuccessResponse(ResultCode.SUCCESS, db_page(filterObject, ReagtLog.OperatingTime, data, 5), None)
|
|
|
|
|
|
@stock.route('/barCodeOutStock')
|
|
class BarCodeOutStock(Resource):
|
|
"""
|
|
条码出库
|
|
"""
|
|
|
|
@staticmethod
|
|
def get():
|
|
date = request.args
|
|
outStockData = ReagtStock.query.filter_by(BarCode=date.get('barCode')).first()
|
|
if outStockData.LastNumber > date.get('outNumber'):
|
|
outStockData.LastNumber -= date.get('outNumber')
|
|
else:
|
|
db.session.delete(outStockData)
|
|
db.session.commit()
|
|
|
|
|
|
@stock.route('/editStock')
|
|
class EditStock(Resource):
|
|
"""
|
|
编辑库存
|
|
"""
|
|
|
|
@staticmethod
|
|
def post():
|
|
token = request.headers.get('X-Token')
|
|
log_info = ''
|
|
current_stock = ReagtStock.query.filter_by(StockId=request.json.get('StockId')).first()
|
|
current_reagent = ReagtReagent.query.filter_by(ReagentId=current_stock.ReagentId).first()
|
|
if current_stock.ProductionBatch != request.json.get('ProductionBatch'):
|
|
log_info += '将生产批次号从' + str(current_stock.ProductionBatch) + '修改为' + str(
|
|
request.json.get('ProductionBatch'))
|
|
current_stock.ProductionBatch = request.json.get('ProductionBatch')
|
|
if current_stock.Position != request.json.get('Position'):
|
|
log_info += '将耗材位置信息从' + str(current_stock.Position) + '修改为' + str(request.json.get('Position'))
|
|
current_stock.Position = request.json.get('Position')
|
|
data = {'Remark': log_info}
|
|
LogAdd(token, GetOperatingTypeEdit(), data, current_stock.Code, current_reagent.Name,
|
|
current_reagent.PinYinCode, 0, current_reagent.Specification,
|
|
current_stock.Position)
|
|
db.session.commit()
|
|
return SuccessResponse(ResultCode.SUCCESS, None, None)
|
|
|
|
|
|
@stock.route('/noGroupList')
|
|
class NoGroupList(Resource):
|
|
@staticmethod
|
|
def post():
|
|
"""
|
|
get no group stock info list
|
|
:return: no group stock list
|
|
"""
|
|
data = request.args
|
|
filterObject = ReagtReagent.query.filter(
|
|
or_(ReagtReagent.GroupName == None, ReagtReagent.GroupName == '')).filter(ReagtReagent.Using == True)
|
|
if data.get('query') is not None and data.get('query') != '':
|
|
filterObject = ReagtReagent.query.filter(or_(
|
|
ReagtReagent.Name.contains(data['query']),
|
|
ReagtReagent.PinYinCode.contains(data['query']))) \
|
|
.filter(ReagtReagent.GroupName == None).filter(ReagtReagent.Using == True)
|
|
if data.get('groupName') is not None and data.get('groupName') != '':
|
|
filterObject = ReagtReagent.query.filter(ReagtReagent.GroupName == data.get('groupName')).filter(ReagtReagent.Using == True)
|
|
data_list = db_page_entity(filterObject, data, 10)
|
|
return SuccessResponse(ResultCode.SUCCESS, {'totalNumber': filterObject.count(), 'list': data_list}, None)
|
|
|
|
|
|
@stock.route('/setGroup')
|
|
class SetGroup(Resource):
|
|
@staticmethod
|
|
def post():
|
|
for item in request.json['groupData']:
|
|
item = Dict2Obj(item)
|
|
reagent_info = ReagtReagent.query.filter_by(ReagentId=item.ReagentId).first()
|
|
reagent_all = ReagtReagent.query.filter_by(Name=item.Name).all()
|
|
for reagent_item in reagent_all:
|
|
reagent_item.GroupName = request.json['groupName']
|
|
reagent_item.ReportItem = request.json['reportName']
|
|
reagent_info.GroupName = request.json['groupName']
|
|
reagent_info.ReportItem = request.json['reportName']
|
|
db.session.commit()
|
|
return SuccessResponse(ResultCode.SUCCESS, None, None)
|
|
|