# -*- 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)