YiZhuCheckData.java 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. package thyyxxk.webserver.service.zhuyuanyisheng.yizhuverify;
  2. import lombok.Getter;
  3. import lombok.extern.slf4j.Slf4j;
  4. import thyyxxk.webserver.constants.Capacity;
  5. import thyyxxk.webserver.dao.his.zhuyuanyisheng.YiZhuLuRuDao;
  6. import thyyxxk.webserver.entity.login.UserInfo;
  7. import thyyxxk.webserver.entity.zhuyuanyisheng.yizhuluru.XinZhenYiZhu;
  8. import thyyxxk.webserver.entity.zhuyuanyisheng.yizhuluru.XinZhenYzActOrder;
  9. import thyyxxk.webserver.entity.zhuyuanyisheng.yizhuluru.YzZdOrderItemConfirm;
  10. import thyyxxk.webserver.service.redislike.RedisLikeService;
  11. import thyyxxk.webserver.utils.*;
  12. import java.math.BigDecimal;
  13. import java.util.*;
  14. import java.util.function.Consumer;
  15. @Slf4j
  16. public class YiZhuCheckData {
  17. private final YiZhuLuRuDao dao;
  18. /**
  19. * 医嘱数组
  20. */
  21. private List<XinZhenYzActOrder> list;
  22. /**
  23. * 药品
  24. */
  25. private final CacheOnce<XinZhenYzActOrder> drug = new CacheOnce<>();
  26. /**
  27. * 医生等级
  28. */
  29. private final CacheOnce<Integer> authorizedDoctorLevel = new CacheOnce<>();
  30. /**
  31. * 项目
  32. */
  33. private final CacheOnce<List<XinZhenYzActOrder>> project = new CacheOnce<>();
  34. /**
  35. * 患者信息
  36. */
  37. private XinZhenYiZhu patientInformation;
  38. private Boolean strictVerification = false;
  39. /**
  40. * 错误信息
  41. */
  42. List<String> errorMessage = new ArrayList<>();
  43. /**
  44. * 警告信息
  45. */
  46. List<String> warningMessage = new ArrayList<>();
  47. Map<String, Object> returnMap = new HashMap<>();
  48. private UserInfo userInfo;
  49. @Getter
  50. private Boolean passTheAudit = true;
  51. private final List<String> groupList = Arrays.asList("71", "73");
  52. /**
  53. * 全排斥医嘱
  54. */
  55. @Getter
  56. private Repel repel = null;
  57. private final String ONCE = "ONCE";
  58. public YiZhuCheckData(YiZhuLuRuDao dao) {
  59. this.dao = dao;
  60. }
  61. public YiZhuCheckData init(List<XinZhenYzActOrder> list, XinZhenYiZhu patientInformation) {
  62. userInfo = dao.selectedUserInfoByCode(TokenUtil.getInstance().getTokenUserId());
  63. this.list = list;
  64. this.patientInformation = patientInformation;
  65. strictVerification = patientInformation != null;
  66. return this;
  67. }
  68. public YiZhuCheckData init(XinZhenYzActOrder orderData, XinZhenYiZhu patientInformation) {
  69. List<XinZhenYzActOrder> temp = Collections.singletonList(orderData);
  70. init(temp, patientInformation);
  71. return this;
  72. }
  73. public void judgeExclusion() {
  74. repel = new Repel();
  75. }
  76. public Map<String, Object> startCheck(Consumer<XinZhenYzActOrder> action) {
  77. for (XinZhenYzActOrder item : list) {
  78. clearErrorMessage();
  79. if (strictVerification) {
  80. strictVerificationFunc(item);
  81. }
  82. publicCheck(item);
  83. String ITEM = "00";
  84. if (item.getSerial().equals(ITEM)) {
  85. itemCheck(item);
  86. } else {
  87. drugCheck(item);
  88. }
  89. if (action != null) {
  90. action.accept(item);
  91. }
  92. setReturnMap(item.getActOrderNo().stripTrailingZeros().toPlainString());
  93. }
  94. return getReturnMap();
  95. }
  96. /**
  97. * 公共校验
  98. *
  99. * @param item 医嘱
  100. */
  101. private void publicCheck(XinZhenYzActOrder item) {
  102. if (StringUtil.isBlank(item.getOrderCode())) {
  103. errorMessage.add("项目编码不能为空");
  104. }
  105. if (StringUtil.isBlank(item.getOrderName())) {
  106. errorMessage.add("项目名称不能为空");
  107. }
  108. if (StringUtil.isBlank(item.getExecUnit())) {
  109. errorMessage.add("执行科室不能为空");
  110. } else if (item.getExecUnit().startsWith("8")) {
  111. errorMessage.add("执行科室不能选择为病区");
  112. }
  113. if (StringUtil.isBlank(item.getFrequCode())) {
  114. errorMessage.add("频次不能为空");
  115. } else if (dao.getTheFrequency(item.getFrequCode()) == 0) {
  116. errorMessage.add("该执行频率已被停用,请更改,不然会导致无法执行。");
  117. }
  118. }
  119. private void itemCheck(XinZhenYzActOrder item) {
  120. List<XinZhenYzActOrder> projectDetails = project.get(item.getOrderCode(), dao::itemDataOne);
  121. String ZK_CODE = "06286";
  122. Map<String, YzZdOrderItemConfirm> specialMedicalAdvice = RedisLikeService.specialMedicalAdvice;
  123. if (strictVerification && specialMedicalAdvice.containsKey(item.getOrderCode())) {
  124. YzZdOrderItemConfirm confirm = specialMedicalAdvice.get(item.getOrderCode());
  125. if (confirm.getCount() > 0 && dao.selectCountByOrderCode(patientInformation.getInpatientNo(), patientInformation.getAdmissTimes(), item.getOrderCode()) > confirm.getCount()) {
  126. errorMessage.add("该医嘱只能开一条,请先作废上一条医嘱");
  127. }
  128. }
  129. if (ZK_CODE.equals(item.getOrderCode())) {
  130. if (StringUtil.isBlank(item.getZkWardCode())) {
  131. errorMessage.add("转科病房不能为空");
  132. }
  133. if (StringUtil.isBlank(item.getZkDeptCode())) {
  134. errorMessage.add("转科科室不能为空");
  135. }
  136. }
  137. // 如果这个项目下面没有费用明细,那么这就是一条口头医嘱,或者特殊医嘱
  138. if (ListUtil.notBlank(projectDetails)) {
  139. for (XinZhenYzActOrder detailed : projectDetails) {
  140. if (detailed.getDelFlag() == 1) {
  141. errorMessage.add(String.format("项目:【%s】,已经被物价停用了", detailed.getOrderName()));
  142. }
  143. if (StringUtil.isBlank(detailed.getNationalCode())) {
  144. warningMessage.add(String.format("项目:【%s】,没有匹配医保码", detailed.getOrderName()));
  145. }
  146. }
  147. }
  148. if (repel != null) {
  149. Integer paiChiYiZhu = dao.shiFouPaiChiYiZhu(item.getOrderCode());
  150. if (paiChiYiZhu != null && paiChiYiZhu.equals(1)) {
  151. repel.setCount(repel.getCount() + 1);
  152. repel.setOrderNo(item.getActOrderNo());
  153. repel.setDate(item.getStartTime());
  154. }
  155. }
  156. item.setDrugOcc(item.getDrugQuan());
  157. }
  158. private void drugCheck(XinZhenYzActOrder item) {
  159. if (StringUtil.isBlank(item.getGroupNo())) {
  160. errorMessage.add("没有药房请重新开。");
  161. return;
  162. }
  163. if (!groupList.contains(item.getGroupNo())) {
  164. errorMessage.add("药房错误,请重新选择药房。");
  165. }
  166. String key = item.getOrderCode().trim() + item.getSerial().trim() + item.getGroupNo().trim();
  167. XinZhenYzActOrder detailsOfDrugs = getDrugData(key, item.getSupplyCode());
  168. if (BigUtils.bigXiaoYu(item.getDose(), 0)) {
  169. errorMessage.add(String.format("医嘱:【%s】,计量不能开负数", item.getOrderName()));
  170. }
  171. if (StringUtil.isBlank(item.getDrugSpecification())) {
  172. errorMessage.add("药品规格不能为空");
  173. }
  174. if (StringUtil.isBlank(item.getSupplyCode())) {
  175. errorMessage.add("给药方式不能为空");
  176. } else if (detailsOfDrugs.getSupplyCode() == null || "1".equals(detailsOfDrugs.getSupplyCode())) {
  177. errorMessage.add("给药方式已被停用。");
  178. }
  179. if (item.getDose() == null || BigUtils.dengYu(item.getDose(), 0)) {
  180. errorMessage.add("一次计量不能为空");
  181. }
  182. if (StringUtil.isBlank(item.getDoseUnit())) {
  183. errorMessage.add("计量单位不能为空");
  184. }
  185. if (StringUtil.isBlank(item.getSerial())) {
  186. errorMessage.add("包装大小不能为空");
  187. }
  188. if (detailsOfDrugs == null) {
  189. errorMessage.add("没有找到对应的药品,请联系药房。");
  190. return;
  191. }
  192. if (StringUtil.isBlank(item.getMiniUnit())) {
  193. if (item.getSerial().equals("01")) {
  194. item.setMiniUnit(detailsOfDrugs.getMiniUnit());
  195. } else {
  196. item.setMiniUnit(detailsOfDrugs.getPackUnit());
  197. }
  198. }
  199. if (detailsOfDrugs.getDelFlag() == 1) {
  200. errorMessage.add("药品已经被停用了,请联系药剂科");
  201. }
  202. if (detailsOfDrugs.getYpLevel() > userInfo.getDoctorLevel()) {
  203. Integer superiorPhysicianRank = authorizedDoctorLevel.get(item.getSuperiorDoctor(), (code) -> {
  204. Integer yiShenDengJi = dao.huoQuYiShenDengJi(code);
  205. return yiShenDengJi == null ? 0 : yiShenDengJi;
  206. });
  207. if (detailsOfDrugs.getYpLevel() > superiorPhysicianRank) {
  208. errorMessage.add("您没有开此药品的权限");
  209. }
  210. }
  211. if (StringUtil.isBlank(detailsOfDrugs.getNationalCode())) {
  212. warningMessage.add("该药品没有医保编码");
  213. }
  214. if (BigUtils.bigXiaoYu(detailsOfDrugs.getStockAmount(), 10)) {
  215. warningMessage.add(String.format("该药品剩余数量为:【%s】", detailsOfDrugs.getStockAmount().stripTrailingZeros().toPlainString()));
  216. }
  217. if (BigUtils.bigDaYu(item.getDrugQuan(), detailsOfDrugs.getStockAmount())) {
  218. errorMessage.add("药品领量大于药品的库存,当前库存量" + detailsOfDrugs.getStockAmount().stripTrailingZeros().toPlainString());
  219. }
  220. if (strictVerification) {
  221. if (detailsOfDrugs.getDeptRestrictions() > 0) {
  222. errorMessage.add("该药品禁止在患者所在的科室使用。");
  223. }
  224. if (detailsOfDrugs.getVisibleFlagZy() == 1) {
  225. errorMessage.add("该药品禁止住院患者使用。");
  226. }
  227. item.setKjywFlag(detailsOfDrugs.getKjywFlag());
  228. if (detailsOfDrugs.getKjywFlag() == 1) {
  229. if (item.getYyfs() == null) {
  230. errorMessage.add("请填写抗菌药物医嘱附注信息录入");
  231. } else if (item.getYyfs() == 1 || item.getYyfs() == 2) {
  232. if (item.getSsqk() == null) {
  233. errorMessage.add("当用药方式为 1 或 2 时,手术切口和用药时间不能为空");
  234. }
  235. }
  236. }
  237. }
  238. String 出院带药 = "007";
  239. if (item.getSupplyCode() != null && 出院带药.equals(item.getSupplyCode())) {
  240. if (!ONCE.equals(item.getFrequCode())) {
  241. errorMessage.add("出院带药不能是长期医嘱。");
  242. }
  243. item.setDrugOcc(item.getDrugQuan());
  244. } else {
  245. // 计算普通药品的领量 durg_quan durg_occ
  246. calculateDrugAmount(item, detailsOfDrugs);
  247. if (item.getDrugOcc() == null) {
  248. errorMessage.add("医嘱领量错误,请重新选择【剂量单位】,或这可能药房剂量维护错误。");
  249. }
  250. }
  251. }
  252. private void strictVerificationFunc(XinZhenYzActOrder item) {
  253. if (item.getParentNo() != null && item.getActOrderNo() != null) {
  254. if (BigUtils.bigXiaoYu(item.getActOrderNo(), item.getParentNo())) {
  255. errorMessage.add("子医嘱的医嘱号,小于父医嘱号,无法成组。【原因如果子医嘱的医嘱号小于父医嘱,会导致打印乱码】");
  256. }
  257. }
  258. // 获取患者的入院时间
  259. if (item.getOrderTime() == null) {
  260. errorMessage.add("医嘱时间不能为空");
  261. } else if (item.getStartTime() == null) {
  262. errorMessage.add("开始时间不能为空");
  263. } else if (patientInformation.getAdmissDate() == null) {
  264. errorMessage.add("没有查询到患者的入院时间");
  265. } else if (DateUtil.shiJianDaXiao(item.getStartTime(), patientInformation.getAdmissDate(), "<")) {
  266. errorMessage.add("开始时间不能在患者入院之前,患者入院时间" + DateUtil.formatDatetime(patientInformation.getAdmissDate()));
  267. } else if (DateUtil.shiJianDaXiao(item.getStartTime(), item.getOrderTime(), "<") && !userInfo.getDeptCode().equals("1160000")) {
  268. errorMessage.add("开始时间不能在开医嘱之前");
  269. }
  270. if (item.getEndTime() != null) {
  271. if (ONCE.equals(item.getFrequCode().trim())) {
  272. item.setEndTime(null);
  273. } else {
  274. if (DateUtil.shiJianDaXiao(item.getEndTime(), item.getStartTime(), "<")) {
  275. errorMessage.add("结束时间不能在开始时间之前");
  276. } else {
  277. item.setModifier(TokenUtil.getInstance().getTokenUserId());
  278. }
  279. }
  280. } else {
  281. item.setModifier(null);
  282. }
  283. }
  284. public XinZhenYzActOrder getDrugData(String code) {
  285. return drug.get(code, (temp) -> dao.drugDataOne(temp, patientInformation != null ? patientInformation.getZkWard() : "", null));
  286. }
  287. public XinZhenYzActOrder getDrugData(String code, String supplyCode) {
  288. return drug.get(code, (temp) -> dao.drugDataOne(temp, patientInformation != null ? patientInformation.getZkWard() : "", supplyCode));
  289. }
  290. public static void calculateDrugAmount(XinZhenYzActOrder item, XinZhenYzActOrder feiYongXinXi) {
  291. if (feiYongXinXi == null) {
  292. return;
  293. }
  294. item.setDrugWeight(feiYongXinXi.getDrugWeight());
  295. item.setDrugWeightUnit(feiYongXinXi.getDrugWeightUnit());
  296. item.setDrugVolume(feiYongXinXi.getDrugVolume());
  297. item.setDrugVolUnit(feiYongXinXi.getDrugWeightUnit());
  298. String doseUnit = StringUtil.isBlank(item.getDoseUnit()) ? "" : item.getDoseUnit().trim();
  299. if (StringUtil.notBlank(feiYongXinXi.getDrugWeightUnit()) && doseUnit.equals(feiYongXinXi.getDrugWeightUnit().trim())) {
  300. item.setDrugOcc(DecimalUtil.divide(item.getDose(), feiYongXinXi.getDrugWeight(), 2));
  301. } else if (StringUtil.notBlank(feiYongXinXi.getDrugVolUnit()) && doseUnit.equals(feiYongXinXi.getDrugVolUnit().trim())) {
  302. item.setDrugOcc(DecimalUtil.divide(item.getDose(), feiYongXinXi.getDrugVolume(), 2));
  303. } else if (StringUtil.notBlank(feiYongXinXi.getPackUnit()) && doseUnit.equals(feiYongXinXi.getPackUnit().trim())) {
  304. item.setDrugOcc(DecimalUtil.divide(item.getDose(), feiYongXinXi.getPackSize(), 2));
  305. }
  306. }
  307. private void clearErrorMessage() {
  308. errorMessage.clear();
  309. warningMessage.clear();
  310. }
  311. private void setReturnMap(String orderNo) {
  312. Map<String, Object> map = new HashMap<>(Capacity.TWO);
  313. if (ListUtil.notBlank(errorMessage)) {
  314. List<String> list = new ArrayList<>(errorMessage);
  315. map.put("error", list);
  316. passTheAudit = false;
  317. }
  318. if (ListUtil.notBlank(warningMessage)) {
  319. List<String> list = new ArrayList<>(warningMessage);
  320. map.put("warning", list);
  321. }
  322. if (!map.isEmpty()) {
  323. returnMap.put(orderNo, map);
  324. }
  325. }
  326. private Map<String, Object> getReturnMap() {
  327. return returnMap;
  328. }
  329. public Boolean getFailed() {
  330. return !passTheAudit;
  331. }
  332. public Boolean multipleExclusions() {
  333. if (repel == null) {
  334. return false;
  335. }
  336. return repel.getCount() > 1;
  337. }
  338. }