XiangMuLuRuService.java 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. package thyyxxk.webserver.service.yibao;
  2. import com.alibaba.fastjson.JSON;
  3. import lombok.extern.slf4j.Slf4j;
  4. import org.apache.commons.collections4.ListUtils;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.stereotype.Service;
  7. import org.springframework.transaction.annotation.Transactional;
  8. import thyyxxk.webserver.config.exception.ExceptionEnum;
  9. import thyyxxk.webserver.dao.his.yibao.TransferInOfExpensesDao;
  10. import thyyxxk.webserver.dao.his.yibao.XiangMuLuRuDao;
  11. import thyyxxk.webserver.entity.ResultVo;
  12. import thyyxxk.webserver.entity.datamodify.FeiYongLeiXin;
  13. import thyyxxk.webserver.entity.datamodify.GetDropdownBox;
  14. import thyyxxk.webserver.entity.datamodify.ZyDetailCharge;
  15. import thyyxxk.webserver.utils.*;
  16. import java.math.BigDecimal;
  17. import java.util.ArrayList;
  18. import java.util.HashMap;
  19. import java.util.List;
  20. import java.util.Map;
  21. /**
  22. * <p>
  23. * 描述: 项目录入
  24. * </p>
  25. *
  26. * @author xc
  27. * @date 2021-08-02 10:37
  28. */
  29. @Service
  30. @Slf4j
  31. public class XiangMuLuRuService {
  32. private final XiangMuLuRuDao dao;
  33. private final TransferInOfExpensesDao transferInOfExpensesDao;
  34. @Autowired
  35. public XiangMuLuRuService(XiangMuLuRuDao dao, TransferInOfExpensesDao transferInOfExpensesDao) {
  36. this.dao = dao;
  37. this.transferInOfExpensesDao = transferInOfExpensesDao;
  38. }
  39. /**
  40. * 获取患者费用
  41. *
  42. * @param param 查询条件
  43. * @return 返回患者费用
  44. */
  45. public ResultVo<List<ZyDetailCharge>> getHuanZheFeiYong(ZyDetailCharge param) {
  46. log.info("查询患者费用==》住院号{},住院次数:{},项目名称:{},录入日期:{},费用类型:{},科室:{}", param.getInpatientNo(), param.getAdmissTimes(),
  47. param.getChargeCode(), param.getStartTime(), param.getOrderNo(), param.getDept());
  48. int infantFlag = 0;
  49. // 如果是婴儿的话那么就需要截取 字符串了 在通过婴儿标识来判断
  50. if (param.getInpatientNo().contains("$")) {
  51. param.setInpatientNo(param.getInpatientNo().split("\\$")[0]);
  52. infantFlag = 1;
  53. }
  54. List<ZyDetailCharge> list = dao.getHuanZheFeiYong(param.getInpatientNo(), param.getAdmissTimes(), param.getChargeCode(), infantFlag,
  55. param.getStartTime(), param.getOrderNo(), param.getDept());
  56. List<ZyDetailCharge> tuiFeiList = dao.tuiFeiList(param.getInpatientNo(), param.getAdmissTimes());
  57. Map<Integer, Integer> map = new HashMap<>();
  58. for (ZyDetailCharge zyDetailCharge : tuiFeiList) {
  59. map.put(zyDetailCharge.getOriDetailSn(), zyDetailCharge.getDetailSn());
  60. }
  61. for (ZyDetailCharge zyDetailCharge : list) {
  62. // 判断 退费的数据
  63. if (map.containsKey(zyDetailCharge.getDetailSn())) {
  64. zyDetailCharge.setTuiFeiFlag(1);
  65. }
  66. if (zyDetailCharge.getOriDetailSn() != null) {
  67. zyDetailCharge.setTuiFeiFlag(1);
  68. }
  69. }
  70. return ResultVoUtil.success(list);
  71. }
  72. /**
  73. * 搜索项目信息
  74. *
  75. * @param pyCode 拼音码
  76. * @return 返回项目信息
  77. */
  78. public ResultVo<List<GetDropdownBox>> getChargeCode(String pyCode) {
  79. return ResultVoUtil.success(dao.getChargeCode(StringUtil.isContainChinese(pyCode)));
  80. }
  81. /**
  82. * @param param 需要生成退费 的数据
  83. * @return 返回
  84. */
  85. @Transactional(rollbackFor = Exception.class)
  86. public ResultVo<String> xiangMuTuiFei(ZyDetailCharge param) {
  87. if (param.getList().isEmpty()) {
  88. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "请先选择需要退费的数据,一次性退费不得超过100条");
  89. } else if (param.getList().size() > 100) {
  90. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "项目退费一次性大于100条数据");
  91. }
  92. if (StringUtil.isBlank(param.getInpatientNo()) || param.getAdmissTimes() == null || param.getList().size() == 0) {
  93. return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "患者信息不全");
  94. }
  95. // 判断数据是否为 退费数据
  96. List<ZyDetailCharge> chaKanSFtuiFei = dao.chaKanSFYiJingTuiFeiLe(param.getInpatientNo(), param.getAdmissTimes(), param.getList());
  97. for (ZyDetailCharge charge : chaKanSFtuiFei) {
  98. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, String.format("流水号为:【%s】已退费,请勿重复退费", charge.getOriDetailSn()));
  99. }
  100. // 判断是否为婴儿
  101. if (param.getInpatientNo().contains("$")) {
  102. param.setInpatientNo(param.getInpatientNo().split("\\$")[0]);
  103. }
  104. // 获取到用户角色
  105. List<Integer> yongHuJueSe = dao.huoQuJueSe(TokenUtil.getTokenUserId());
  106. //获取到这个人是否属于这个科室
  107. List<String> zhiXinKeShi = dao.chaXunZhiZXinKeShi(param.getDeptCode());
  108. // 获取原来的数据
  109. List<ZyDetailCharge> yuanTuiFeiList = dao.huoQuJuTiFeiYong(param.getInpatientNo(), param.getAdmissTimes(), param.getList());
  110. // 获取患者的总费用
  111. BigDecimal sum = new BigDecimal(0);
  112. // 退费的list
  113. // 获取最大值
  114. Integer maxDetailSn = transferInOfExpensesDao.getMaxDetailSn(param.getInpatientNo(), param.getAdmissTimes());
  115. List<ZyDetailCharge> tuiFeiList = new ArrayList<>();
  116. for (ZyDetailCharge pojo : yuanTuiFeiList) {
  117. // 判断患者的费用是否存在负数
  118. if (pojo.getChargeFee().signum() == -1 || pojo.getChargeAmount().signum() == -1) {
  119. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, String.format("患者费用存在负数,流水号:【%s】,该数据为退费数据", pojo.getDetailSn()));
  120. }
  121. // 管理员角色可以无视
  122. if (!yongHuJueSe.contains(1)) {
  123. // 人员角色为 3 就不是医技科室 只有医技科室可以退药品
  124. if (yongHuJueSe.contains(3)) {
  125. if (!zhiXinKeShi.contains(pojo.getExecUnit())) {
  126. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, String.format("流水号为【%s】,请对应的执行科室进行退费。", pojo.getDetailSn()));
  127. }
  128. // 护士是不可以退药品的
  129. if (pojo.getChargeCode().equals("BILL01") || pojo.getChargeCode().equals("BILL02")) {
  130. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, String.format("流水号为【%s】,中草药费或西药费,无法退费。", pojo.getDetailSn()));
  131. }
  132. } else if (!param.getDeptCode().equals(pojo.getExecUnit())) {
  133. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, String.format("流水号为【%s】,请对应的执行科室进行退费。", pojo.getDetailSn()));
  134. }
  135. }
  136. sum = sum.add(pojo.getChargeFee().multiply(pojo.getChargeAmount()));
  137. pojo.setChargeFee(pojo.getChargeFee().negate());
  138. pojo.setChargeAmount(pojo.getChargeAmount().negate());
  139. pojo.setOpIdCode(TokenUtil.getTokenUserId());
  140. pojo.setOriDetailSn(pojo.getDetailSn());
  141. pojo.setDetailSn(maxDetailSn += 1);
  142. pojo.setOldGenTime(DateUtil.formatDatetime(pojo.getGenTime(), DateUtil.DEFAULT_PATTERN));
  143. // 向退费 list 里面添加
  144. tuiFeiList.add(pojo);
  145. }
  146. // 总费用计算
  147. FeiYongLeiXin fy = JiSuanFeiYong.jiSuan(yuanTuiFeiList, false);
  148. // 计算出这一次 总退的费用
  149. fy.setTotalCharge(sum.negate());
  150. // 执行退费的操作 20 条的退费
  151. if (tuiFeiList.isEmpty()) {
  152. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "查询不到患者原数据,请联系管理员。");
  153. } else {
  154. List<List<ZyDetailCharge>> fenGe = ListUtils.partition(tuiFeiList, 20);
  155. fenGe.forEach(dao::xiangMuTuiFei);
  156. dao.huanZheZongFeiYong(fy, param.getInpatientNo(), param.getAdmissTimes(), "zy_actpatient");
  157. log.info("操作项目退费 ==》 操作人:{},数据:{}", TokenUtil.getTokenUserId(), JSON.toJSONString(tuiFeiList));
  158. return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_NOTIFICATION, "项目退费操作成功。");
  159. }
  160. }
  161. /**
  162. * 获取模板
  163. *
  164. * @param deptCode 根据科室搜索
  165. * @return 返回模板
  166. */
  167. public ResultVo<List<ZyDetailCharge>> getMuBan(String deptCode) {
  168. return ResultVoUtil.success(dao.getMuBan(deptCode, 1));
  169. }
  170. /**
  171. * 获取模板的具体信息
  172. *
  173. * @param patternName 模板名称
  174. * @param opIdCode 存模板的人
  175. * @return 返回具体的模板
  176. */
  177. public ResultVo<List<ZyDetailCharge>> getMuBanXinXi(String patternName, String opIdCode) {
  178. return ResultVoUtil.success(dao.getMuBanXinXi(patternName, opIdCode));
  179. }
  180. /**
  181. * 获取科室
  182. *
  183. * @return 返回科室信息
  184. */
  185. public ResultVo<List<GetDropdownBox>> getDept() {
  186. return ResultVoUtil.success(dao.getDpet());
  187. }
  188. /**
  189. * 获取科室
  190. *
  191. * @return 返回科室信息
  192. */
  193. public ResultVo<List<GetDropdownBox>> getWard() {
  194. return ResultVoUtil.success(dao.getWard());
  195. }
  196. /**
  197. * 通过拼音码 来搜索项目
  198. *
  199. * @param pyCode 拼音码
  200. * @param xiangMuHuoYaoPinFlag 判断是查询项目还是药品 0 - 项目 1- 药品
  201. * @return 返回项目
  202. */
  203. public ResultVo<List<ZyDetailCharge>> queryXiangMu(String pyCode, Integer xiangMuHuoYaoPinFlag) {
  204. if (xiangMuHuoYaoPinFlag == 0) {
  205. return ResultVoUtil.success(dao.queryXiangMu(pyCode.toUpperCase() + "%"));
  206. }
  207. return ResultVoUtil.success();
  208. }
  209. /**
  210. * 这个项目录入
  211. *
  212. * @param param 参数
  213. * @return 返回提示语句
  214. */
  215. @Transactional(rollbackFor = Exception.class)
  216. public ResultVo<String> xiangMuFeiYongShangChuan(ZyDetailCharge param) {
  217. if (param.getList().size() > 50) {
  218. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "一次性项目录入大于50条");
  219. }
  220. if (StringUtil.isBlank(param.getInpatientNo()) || param.getAdmissTimes() == null || param.getList().size() == 0
  221. || StringUtil.isBlank(param.getWard()) || StringUtil.isBlank(param.getDept()) || StringUtil.isBlank(param.getZySerialNo())) {
  222. return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "患者信息不全。");
  223. }
  224. // 婴儿 要特殊处理
  225. int infantFlag = 0;
  226. // 如果带有这个 $ 说明是婴儿
  227. if (param.getInpatientNo().contains("$")) {
  228. infantFlag = 1;
  229. param.setInpatientNo(param.getInpatientNo().split("\\$")[0]);
  230. }
  231. // 获取最大流水号
  232. Integer maxDetailSn = transferInOfExpensesDao.getMaxDetailSn(param.getInpatientNo(), param.getAdmissTimes());
  233. // 获取项目的 总费用
  234. BigDecimal sum = new BigDecimal(0);
  235. // 录入人的id
  236. param.setOpIdCode(TokenUtil.getTokenUserId());
  237. for (ZyDetailCharge zyDetailCharge : param.getList()) {
  238. zyDetailCharge.setDetailSn(maxDetailSn += 1);
  239. // 判断患者的费用是否存在负数
  240. if (zyDetailCharge.getChargeAmount().signum() == -1 || zyDetailCharge.getAmount().signum() == -1) {
  241. return ResultVoUtil.fail(ExceptionEnum.EXIST_NEGATIVE_FEES);
  242. }
  243. sum = sum.add(zyDetailCharge.getChargeAmount().multiply(zyDetailCharge.getAmount()));
  244. // 这里不会保存单价 只会总价
  245. zyDetailCharge.setChargeAmount(zyDetailCharge.getChargeAmount().multiply(zyDetailCharge.getAmount()));
  246. if (StringUtil.isBlank(zyDetailCharge.getChargeCode())) {
  247. return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "项目编码空值。");
  248. }
  249. if (StringUtil.isBlank(zyDetailCharge.getDeptCode())) {
  250. return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "执行科室为空。");
  251. }
  252. if (zyDetailCharge.getChargeCodeMx() == null) {
  253. zyDetailCharge.setChargeCodeMx(zyDetailCharge.getChargeCode());
  254. }
  255. }
  256. FeiYongLeiXin fy = JiSuanFeiYong.jiSuan(param.getList(), true);
  257. fy.setTotalCharge(sum);
  258. // 在此处 插入费用
  259. dao.chaRuFeiYong(param, param.getList(), infantFlag);
  260. dao.huanZheZongFeiYong(fy, param.getInpatientNo(), param.getAdmissTimes(), "zy_actpatient");
  261. log.info("项目录入费用上传 ==》 操作人:{},数据:{}", param.getOpIdCode(), JSON.toJSONString(param));
  262. return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_NOTIFICATION, "费用上传成功。");
  263. }
  264. /**
  265. * 上传以及修改项目录入模板
  266. *
  267. * @param zyDetailCharge 模板的一些数据
  268. * @return 返回成功提示
  269. */
  270. public ResultVo<String> shangChuanMuBan(ZyDetailCharge zyDetailCharge) {
  271. if (dao.chaKanMuBanMingChengSFcunZi(zyDetailCharge.getName(), TokenUtil.getTokenUserId()) > 0) {
  272. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "模板名称重复");
  273. }
  274. zyDetailCharge.setOpIdCode(TokenUtil.getTokenUserId());
  275. // 在创建新的模板之前 需要先删除 原来的
  276. dao.delMuBan(zyDetailCharge.getName(), zyDetailCharge.getOpIdCode());
  277. dao.baoCunMuBan(zyDetailCharge);
  278. log.info("保存项目录入模板 ==》 操作人 :{},数据:{}", zyDetailCharge.getOpIdCode(), JSON.toJSONString(zyDetailCharge));
  279. return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_NOTIFICATION, "保存模板成功。");
  280. }
  281. /**
  282. * 医嘱退费匹配
  283. *
  284. * @param inpatientNo 住院号
  285. * @param admissTimes 住院次数
  286. * @return 返回是否匹配成功
  287. */
  288. public ResultVo<String> yiZhuTuiFeiPiPei(String inpatientNo, Integer admissTimes) {
  289. // 获取正的医嘱费用
  290. List<ZyDetailCharge> getYiZhuFeiYongZhenShu = dao.getYiZhuFeiYong(inpatientNo, admissTimes, ">");
  291. // 获取负的医嘱费用
  292. List<ZyDetailCharge> getYiZhuFeiYongFuShu = dao.getYiZhuFeiYong(inpatientNo, admissTimes, "<");
  293. // 需要保存需要匹配的一些流水数据
  294. List<ZyDetailCharge> piPei = new ArrayList<>();
  295. // 保存正数的数据用 map 来匹配
  296. Map<String, ZyDetailCharge> zhenShuMap = new HashMap<>();
  297. for (ZyDetailCharge zhenShu : getYiZhuFeiYongZhenShu) {
  298. String key = zhenShu.getOrderNo() + DateUtil.formatDatetime(zhenShu.getChargeDate()) + zhenShu.getChargeCodeMx() + zhenShu.getChargeAmount();
  299. zhenShuMap.put(key, zhenShu);
  300. }
  301. // 用负数拼接的 key 去查找
  302. for (ZyDetailCharge fuShu : getYiZhuFeiYongFuShu) {
  303. String key = fuShu.getOrderNo() + DateUtil.formatDatetime(fuShu.getChargeDate()) + fuShu.getChargeCodeMx() + fuShu.getChargeAmount().negate();
  304. if (zhenShuMap.containsKey(key)) {
  305. fuShu.setOriDetailSn(zhenShuMap.get(key).getDetailSn());
  306. piPei.add(fuShu);
  307. }
  308. }
  309. // 开始匹配
  310. if (piPei.size() > 0) {
  311. // 100 条的更新 ListUtils.partition 用来拆分 list size 是拆分的条数
  312. List<List<ZyDetailCharge>> fenDuan = ListUtils.partition(piPei, 100);
  313. for (List<ZyDetailCharge> list : fenDuan) {
  314. dao.yiZhuTuiFeiPiPei(inpatientNo, admissTimes, list);
  315. }
  316. log.info("医嘱退费匹配 ==》 操作人:{},住院号:{},住院次数:{}", TokenUtil.getTokenUserId(), inpatientNo, admissTimes);
  317. return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_NOTIFICATION, String.format("医嘱退费匹配,共有【%d】条,匹配成功【%d】条", getYiZhuFeiYongFuShu.size(), piPei.size()));
  318. } else {
  319. return ResultVoUtil.fail(ExceptionEnum.NO_DATA_EXIST, "该患者没有可以匹配的医嘱退费");
  320. }
  321. }
  322. public ResultVo<String> shanChuMuBan(String patterName, String opIdCode) {
  323. log.info("删除项目模板 ==》操作人:{},模板名称:{}", TokenUtil.getTokenUserId(), patterName);
  324. dao.delMuBan(patterName, opIdCode);
  325. return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_NOTIFICATION, "删除成功");
  326. }
  327. }