Index: ssts-web/src/main/webapp/mobileClient/SterileSupplySystem_Android_V4.7.21_20210604_v4_1_6p_release.apk =================================================================== diff -u Binary files differ Index: ssts-invoice/src/main/java/com/forgon/disinfectsystem/invoicemanager/service/InvoiceManagerImpl.java =================================================================== diff -u -r31419 -r31446 --- ssts-invoice/src/main/java/com/forgon/disinfectsystem/invoicemanager/service/InvoiceManagerImpl.java (.../InvoiceManagerImpl.java) (revision 31419) +++ ssts-invoice/src/main/java/com/forgon/disinfectsystem/invoicemanager/service/InvoiceManagerImpl.java (.../InvoiceManagerImpl.java) (revision 31446) @@ -7053,6 +7053,35 @@ return dataJSONObject; } + @Override + public JSONObject getDisposableGoodsStockByDepartCodingOrInvoicePlanId(Long warehouseId , String disposableGoodsBarcode) { + DisposableGoods disposableGoods = null; + DisposableGoodsBatch disposableGoodsBatch = null; + //条码对象 + Object barcodeDevice = null; + if(BarcodeUtils.isDisposableGoodsBarcode(disposableGoodsBarcode)){ + barcodeDevice = barcodeManager.getBarcodeEntityByPrefixBarcode(disposableGoodsBarcode); + }else{ + barcodeDevice = barcodeManager + .getBarcodeByBarcode(disposableGoodsBarcode); + } + if(barcodeDevice == null){ + throw new SystemException(String.format("条码【%s】不是条码对象",disposableGoodsBarcode)); + } + if(barcodeDevice instanceof DisposableGoods){ + disposableGoods = (DisposableGoods)barcodeDevice; + }else if(barcodeDevice instanceof DisposableGoodsBatch){ + disposableGoodsBatch = (DisposableGoodsBatch)barcodeDevice; + }else{ + + } + JSONObject result = JSONUtil.buildJsonObject(true); + JSONObject dataJSONObject = new JSONObject(); + dataJSONObject.put("stockAmount", getDisposableGoodsStock(warehouseId, disposableGoods , disposableGoodsBatch)); + JSONUtil.addDataProperty(result, dataJSONObject); + return dataJSONObject; + } + /** * 获取不追溯的包的库存 * @param invoicePlans 申请单集合 @@ -7113,7 +7142,43 @@ return result; } + /** + * 获取一次性物品的库存 + * @param warehouseId 申请单集合 + * @param disposableGoods 一次性物品定义 + * @param disposableGoodsBatch 一次性物品批次定义 + * @return + */ + private long getDisposableGoodsStock(Long warehouseId, DisposableGoods disposableGoods, DisposableGoodsBatch disposableGoodsBatch){ + long result = 0; + String condition = null; + if(disposableGoodsBatch != null){ + condition = " and batch.id = " + disposableGoodsBatch.getId(); + }else if(disposableGoods != null){ + condition = " and batch.diposablegoods_id = " + disposableGoods.getId(); + } + String queryStockSql = String.format("select sum(po.storage) cnt from %s po " + + " join %s batch on po.disposableGoodsBatchId=batch.id join %s bd on batch.id=bd.id" + + " where po.warehouseID=%s and po.storage > 0 and batch.expDate > %s %s ", + DisposableGoodsBatchStock.class.getSimpleName(),DisposableGoodsBatch.class.getSimpleName(), + BarcodeDevice.class.getSimpleName(), warehouseId , dateQueryAdapter.dateAdapter(new Date()) , condition); + ResultSet rs = null; + try{ + rs = objectDao.executeSql(queryStockSql); + while(rs.next()){ + Number cnt = (Number)rs.getObject("cnt"); + result = cnt == null ? 0 : cnt.intValue(); + } + }catch(Exception e){ + e.printStackTrace(); + }finally{ + DatabaseUtil.closeResultSetAndStatement(rs); + } + return result; + } + + /** * 根据申请单集合及包定义查询消毒物品包实例 * @param invoicePlans * @param tousseDefinition Index: ssts-web/src/main/webapp/mobileClient/SterileSupplySystem_Android_V4.7.21_20210604_v4_1_nologo_release.apk =================================================================== diff -u Binary files differ Index: ssts-web/src/main/webapp/mobileClient/SterileSupplySystem_Android_V4.7.21_20210604_v4_1_release.apk =================================================================== diff -u Binary files differ Index: ssts-web/src/main/webapp/mobileClient/clientForAndroid.json =================================================================== diff -u -r31311 -r31446 --- ssts-web/src/main/webapp/mobileClient/clientForAndroid.json (.../clientForAndroid.json) (revision 31311) +++ ssts-web/src/main/webapp/mobileClient/clientForAndroid.json (.../clientForAndroid.json) (revision 31446) @@ -1,7 +1,7 @@ { "success":"true", - "version":"4.7.20", - "urlSuffix":"/mobileClient/SterileSupplySystem_Android_V4.7.20_20210513_v4_1_release.apk", - "urlSuffix-nologo":"/mobileClient/SterileSupplySystem_Android_V4.7.20_20210513_v4_1_nologo_release.apk", - "urlSuffix-6p":"/mobileClient/SterileSupplySystem_Android_V4.7.20_20210513_v4_1_6p_release.apk", + "version":"4.7.21", + "urlSuffix":"/mobileClient/SterileSupplySystem_Android_V4.7.21_20210604_v4_1_release.apk", + "urlSuffix-nologo":"/mobileClient/SterileSupplySystem_Android_V4.7.21_20210604_v4_1_nologo_release.apk", + "urlSuffix-6p":"/mobileClient/SterileSupplySystem_Android_V4.7.21_20210604_v4_1_6p_release.apk", } \ No newline at end of file Index: ssts-webservice/src/main/java/com/forgon/disinfectsystem/webservice/service/ServiceManagerImpl.java =================================================================== diff -u -r31412 -r31446 --- ssts-webservice/src/main/java/com/forgon/disinfectsystem/webservice/service/ServiceManagerImpl.java (.../ServiceManagerImpl.java) (revision 31412) +++ ssts-webservice/src/main/java/com/forgon/disinfectsystem/webservice/service/ServiceManagerImpl.java (.../ServiceManagerImpl.java) (revision 31446) @@ -211,6 +211,7 @@ import com.forgon.tools.db.DatabaseUtil; import com.forgon.tools.db.InitDbConnection; import com.forgon.tools.hibernate.ObjectDao; +import com.forgon.tools.json.AESTest; import com.forgon.tools.json.DateJsonValueProcessor; import com.forgon.tools.json.JSONUtil; import com.forgon.tools.json.JsonPropertyFilter; @@ -572,8 +573,16 @@ if (CSSDConstants.SCAN_BARCODE_MODE.equalsIgnoreCase(loginType)) { // 扫描条码登陆,则不检查密码 String barcode = params.optString("barcode"); - if (StringUtils.isBlank(barcode)) + if (StringUtils.isBlank(barcode)){ + String encryptBarcodeBytesString = params.optString("encryptBarcodeBytesString"); + if(StringUtils.isNotBlank(encryptBarcodeBytesString)){ + //barcode = new String(AESTest.decryptAES(AESTest.stringToBytes(encryptBarcodeBytesString), AESTest.listence)); + barcode = new String(AESTest.stringToBytes(encryptBarcodeBytesString)); + } + } + if (StringUtils.isBlank(barcode)){ return JSONUtil.buildErrorMsgJsonResult("缺失参数barcode"); + } // 读取配置:是否启用条码登录 boolean enableScanBarcodeLogin = CssdUtils.getSystemSetConfigByNameBool("enableScanBarcodeLogin", true); if (!enableScanBarcodeLogin){ @@ -587,13 +596,27 @@ } String username = params.optString("username"); - if (StringUtils.isBlank(username)) + if (StringUtils.isBlank(username)){ + String encryptUsernameBytesString = params.optString("encryptUsernameBytesString"); + if(StringUtils.isNotBlank(encryptUsernameBytesString)){ + //username = new String(AESTest.decryptAES(AESTest.stringToBytes(encryptUsernameBytesString), AESTest.listence)); + username = new String(AESTest.stringToBytes(encryptUsernameBytesString)); + } + } + if (StringUtils.isBlank(username)){ return JSONUtil.buildErrorMsgJsonResult("username 为空"); - + } String password = params.optString("password"); - if (StringUtils.isBlank(password)) + if (StringUtils.isBlank(password)){ + String encryptPasswordBytesString = params.optString("encryptPasswordBytesString"); + if(StringUtils.isNotBlank(encryptPasswordBytesString)){ + //password = new String(AESTest.decryptAES(AESTest.stringToBytes(encryptPasswordBytesString), AESTest.listence)); + password = new String(AESTest.stringToBytes(encryptPasswordBytesString)); + } + } + if (StringUtils.isBlank(password)){ return JSONUtil.buildErrorMsgJsonResult("password 为空"); - + } User user = (User) sysUserManager.getUserByPropertyWithLower("name", username); if (user == null) return JSONUtil.buildErrorMsgJsonResult("用户名或密码有误"); @@ -6748,8 +6771,35 @@ JSONUtil.addDataProperty(result, dataJSONObject); return result.toString(); } + /** + * 根据申请单id,申请科室编码及一次性物品条码(可能是一次性物品固定条码、也可能是一次性物品批次条码)查询该物品可发货的库存) + * 用于科室的发货计划页面,修改一次性物品的数量时校验是否超过库存数量时调用 + * @param params:invoicePlanId:申请单id,departCoding:申请科室编码,disposableGoodsBarcode:一次性物品条码(可能是一次性物品固定条码、也可能是一次性物品批次条码) + * @return {"success":true,"data":{"stockAmount":3}} + */ + @SuppressWarnings("unused") + private String getDisposableGoodsStockByDepartCodingOrInvoicePlanId(JSONObject params){ + JSONObject result = JSONUtil.buildJsonObject(true); + JSONObject dataJSONObject = null; + try{ + dataJSONObject = invoiceManager.getDisposableGoodsStockByDepartCodingOrInvoicePlanId( + params.optLong("warehouseId") ,params.optString("disposableGoodsBarcode")); + }catch(RuntimeException e){ + dataJSONObject = JSONUtil.buildJsonObject(false, e.getMessage()); + }catch(Exception e){ + dataJSONObject = JSONUtil.buildJsonObject(false, "服务器正忙,请联系管理员"); + }finally{ + if(dataJSONObject == null){ + dataJSONObject = new JSONObject(); + } + } + JSONUtil.addDataProperty(result, dataJSONObject); + return result.toString(); + } + + /** * * @param params * @return Index: ssts-invoice/src/main/java/com/forgon/disinfectsystem/invoicemanager/service/InvoiceManager.java =================================================================== diff -u -r31077 -r31446 --- ssts-invoice/src/main/java/com/forgon/disinfectsystem/invoicemanager/service/InvoiceManager.java (.../InvoiceManager.java) (revision 31077) +++ ssts-invoice/src/main/java/com/forgon/disinfectsystem/invoicemanager/service/InvoiceManager.java (.../InvoiceManager.java) (revision 31446) @@ -362,5 +362,13 @@ * @return */ public JSONObject getUnTraceTousseStockByDepartCodingOrInvoicePlanId(Long invoicePlanId,String departCoding,String tousseFixBarcode); + + /** + * 根据申请单id,申请科室编码及一次性物品条码(可能是一次性物品固定条码、也可能是一次性物品批次条码)查询库存 + * @param warehouseId 仓库id + * @param disposableGoodsBarcode 一次性物品条码(可能是一次性物品固定条码、也可能是一次性物品批次条码) + * @return + */ + public JSONObject getDisposableGoodsStockByDepartCodingOrInvoicePlanId(Long warehouseId , String disposableGoodsBarcode); } Index: forgon-tools/src/main/java/com/forgon/tools/json/AESTest.java =================================================================== diff -u --- forgon-tools/src/main/java/com/forgon/tools/json/AESTest.java (revision 0) +++ forgon-tools/src/main/java/com/forgon/tools/json/AESTest.java (revision 31446) @@ -0,0 +1,167 @@ +package com.forgon.tools.json; + +import java.io.UnsupportedEncodingException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.KeyGenerator; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import org.apache.commons.lang3.StringUtils; + +/** + * 加密解密类 + * @author forgon + * @since 2020-06-01 + * + */ +public class AESTest { + /** + * 加/解密密钥 + */ + public final static String listence = "1234567890"; + /** + * 前缀 + */ + public final static String PREFIX = "PRE"; + /** + * 后缀 + */ + public final static String SUFFIX = "SUF"; + /** + * 分隔符 + */ + public final static String SPLIT = "-"; + /** + * AES加密 + * + * @param content + * 需要加密的内容 + * @param listence + * 加密密钥 + * @return + */ + public static byte[] encryptAES(String content, String listence) { + try { + KeyGenerator kgen = KeyGenerator.getInstance("AES"); + kgen.init(128, new SecureRandom(listence.getBytes())); + SecretKey secretKey = kgen.generateKey(); + byte[] enCodeFormat = secretKey.getEncoded(); + SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES"); + Cipher cipher = Cipher.getInstance("AES");// 创建密码器 + byte[] byteContent = content.getBytes("utf-8"); + cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化 + byte[] result = cipher.doFinal(byteContent); + return result; // 加密 + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (NoSuchPaddingException e) { + e.printStackTrace(); + } catch (InvalidKeyException e) { + e.printStackTrace(); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } catch (IllegalBlockSizeException e) { + e.printStackTrace(); + } catch (BadPaddingException e) { + e.printStackTrace(); + } + return null; + } + + /** + * AES解密 + * + * @param content + * 待解密内容 + * @param password + * 解密密钥 + * @return + */ + public static byte[] decryptAES(byte[] content, String listence) { + try { + KeyGenerator kgen = KeyGenerator.getInstance("AES"); + kgen.init(128, new SecureRandom(listence.getBytes())); + SecretKey secretKey = kgen.generateKey(); + byte[] enCodeFormat = secretKey.getEncoded(); + SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES"); + Cipher cipher = Cipher.getInstance("AES");// 创建密码器 + cipher.init(Cipher.DECRYPT_MODE, key);// 初始化 + byte[] result = cipher.doFinal(content); + return result; // 加密 + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (NoSuchPaddingException e) { + e.printStackTrace(); + } catch (InvalidKeyException e) { + e.printStackTrace(); + } catch (IllegalBlockSizeException e) { + e.printStackTrace(); + } catch (BadPaddingException e) { + e.printStackTrace(); + } + return null; + } + + public static String bytesToString(byte[] bytes){ + if(bytes != null && bytes.length > 0){ + StringBuffer buffer = new StringBuffer(); + buffer.append(PREFIX).append(SPLIT); + for(int i = 0;i < bytes.length;i++){ + byte b = bytes[i]; + buffer.append(b).append(SPLIT); + } + buffer.append(SUFFIX); + return buffer.toString(); + } + return null; + } + + public static byte[] stringToBytes(String bytesString){ + if(StringUtils.isNotBlank(bytesString)){ + bytesString = bytesString.replace(PREFIX + SPLIT, "").replace(SPLIT + SUFFIX, ""); + String[] bytesStringArray = StringUtils.split(bytesString,SPLIT); + byte[] bytes = new byte[bytesStringArray.length]; + for(int i = 0;i < bytes.length;i++){ + bytes[i] = Byte.parseByte(bytesStringArray[i]); + } + return bytes; + } + return null; + } + + public static void main(String[] args) { + String userName = "admin"; + System.out.println(bytesToString(encryptAES(userName, listence))); + System.out.println(AESTest.bytesToString(AESTest.encryptAES(userName,AESTest.listence))); + String test = AESTest.bytesToString(userName.getBytes()); + System.out.println("test1="+test); + System.out.println("test2="+new String(stringToBytes(test))); + //65,120,-95,-65,-24,2,-40,-104,-97,2,36,61,91,-96,-87,-95 + } + + public static void main1(String[] args) { + String content = "010000001"; + byte[] encryptBytes = encryptAES(content, listence); + String bytesString = bytesToString(encryptBytes); + System.out.println("bytesToString=" + bytesString); + byte[] decryptBytes = decryptAES(encryptBytes, listence); + System.out.println("length=" + decryptBytes.length); + for(byte b : decryptBytes){ + System.out.print(b+","); + } + System.out.println("\nfinish..."); + System.out.println("encryptString=" + new String(encryptBytes)); + System.out.println("decryptString=" + new String(decryptBytes)); + + String decryptBytesString = bytesToString(decryptBytes); + byte[] result = stringToBytes(decryptBytesString); + System.out.println("result=" + new String(result)); + } +} Index: ssts-diposablegoods/src/main/java/com/forgon/disinfectsystem/diposablegoods/service/DiposableGoodsManagerImpl.java =================================================================== diff -u -r30720 -r31446 --- ssts-diposablegoods/src/main/java/com/forgon/disinfectsystem/diposablegoods/service/DiposableGoodsManagerImpl.java (.../DiposableGoodsManagerImpl.java) (revision 30720) +++ ssts-diposablegoods/src/main/java/com/forgon/disinfectsystem/diposablegoods/service/DiposableGoodsManagerImpl.java (.../DiposableGoodsManagerImpl.java) (revision 31446) @@ -3267,17 +3267,21 @@ Map amountAndIdsMap, Long wareHouseId) { JSONObject returnObj = JSONUtil.buildJsonObject(true); String sql = null; + //查有效的批次库存数量 + String queryValidBatchStorage = String.format("(select sum(dgbs.storage) from %s dgbs join %s dgb on dgbs.disposableGoodsBatchId=dgb.id " + + " where dgbs.diposablegoods_id=dgs.id and dgb.expDate > %s)", + DisposableGoodsBatchStock.class.getSimpleName(),DisposableGoodsBatch.class.getSimpleName(),dateQueryAdapter.getTodayAdapter()); //类型为高值耗材的不处理 if(DatabaseUtil.isSqlServer(dbConnection.getDatabase())){ - sql = String.format("select dgs.id disposableGoodsStockId,dg.ttsName,dg.name showTousseName,dg.id,dg.applicationSpecification,dg.specification,dg.barcode,dg.referencePrice,dgs.amount from %s dg " + sql = String.format("select dgs.id disposableGoodsStockId,dg.ttsName,dg.name showTousseName,dg.id,dg.applicationSpecification,dg.specification,dg.barcode,dg.referencePrice,dgs.amount,%s storage from %s dg " + " join %s dgs on dg.id=dgs.disposableGoodsID" - + " where dg.goodsType='%s' and dgs.warehouseID= %s and %s " + + " where dg.goodsType='%s' and dgs.warehouseID= %s and %s ",queryValidBatchStorage , DisposableGoods.class.getSimpleName(),DisposableGoodsStock.class.getSimpleName(),DisposableGoods.TYPE_DIPOSABLEGOODS ,wareHouseId,SqlUtils.getStringFieldInLargeCollectionsPredicate("dg.id", amountAndIdsMap.keySet()));; }else if(DatabaseUtil.isOracle(dbConnection.getDatabase())){ - sql = String.format("select dgs.id disposableGoodsStockId,dg.ttsName,dg.applicationSpecification,dg.specification,dg.name showTousseName,dg.id,dg.barcode,dg.referencePrice,(case when dg.specification is null then dg.name else dg.name || '[' || dg.specification || ']' end) name,dgs.amount from %s dg " + sql = String.format("select dgs.id disposableGoodsStockId,dg.ttsName,dg.applicationSpecification,dg.specification,dg.name showTousseName,dg.id,dg.barcode,dg.referencePrice,(case when dg.specification is null then dg.name else dg.name || '[' || dg.specification || ']' end) name,dgs.amount,%s storage from %s dg " + " join %s dgs on dg.id=dgs.disposableGoodsID" - + " where dg.goodsType='%s' and dgs.warehouseID= %s and %s " + + " where dg.goodsType='%s' and dgs.warehouseID= %s and %s ",queryValidBatchStorage , DisposableGoods.class.getSimpleName(),DisposableGoodsStock.class.getSimpleName(),DisposableGoods.TYPE_DIPOSABLEGOODS ,wareHouseId,SqlUtils.getStringFieldInLargeCollectionsPredicate("dg.id", amountAndIdsMap.keySet()));; } @@ -3300,7 +3304,7 @@ continue; } - Long stockAmount = rs.getLong("amount");//库存数量 + Long stockAmount = rs.getLong("storage");//库存数量(未过期的批次库存数量) JSONObject typeInfoOnScannedObj = new JSONObject(); typeInfoOnScannedObj.put("disposableGoodsId", disposableGoodsId); typeInfoOnScannedObj.put("disposableGoodsStockId", disposableGoodsStockId);