Bladeren bron

新增
1、长者轮候增加血常规、乙肝两对半、骨密度、心电图、头颅CT、胸片、肝功能、粪常规、尿常规、戊肝、丙肝、结核杆菌抗体、HIV、梅毒、血生化和认知评估报告字段
2、新增退住转离住功能
修改
1、离住模块重构
BUGFIX
1、修复变更附件无法显示的问题

liangwenxuan 1 week geleden
bovenliggende
commit
d731a90696
19 gewijzigde bestanden met toevoegingen van 492 en 100 verwijderingen
  1. 30 0
      sql/mysql/alter_elderly_check_in_wait_add_medical_report_urls.sql
  2. 8 0
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/business/BpmElderlyController.java
  3. 36 0
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/business/vo/BpmApplyRetreatSimpleCreateReqVO.java
  4. 11 0
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/business/BpmElderlApplyService.java
  5. 36 0
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/business/BpmElderlApplyServiceImpl.java
  6. 33 1
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
  7. 26 1
      yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/bpm/BpmElderlyExpenseApi.java
  8. 17 0
      yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/bpm/vo/CheckInWaitSupplementReqVO.java
  9. 16 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/bpm/BpmCheckInWaitApiImpl.java
  10. 57 7
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/bpm/BpmElderlyExpenseApiImpl.java
  11. 5 5
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/order/OrderApiImpl.java
  12. 4 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/vo/ElderlyTempOutRespVO.java
  13. 1 1
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/biz/DailyExpensesDO.java
  14. 33 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/biz/ElderlyCheckInWaitDO.java
  15. 3 1
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/biz/ElderlyInfoServiceImpl.java
  16. 159 71
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/biz/ElderlyTempOutServiceImpl.java
  17. 14 11
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/biz/ExpenseOrderServiceImpl.java
  18. 2 2
      yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/ElderlyChangeRecordMapper.xml
  19. 1 0
      yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/ElderlyInfoMapper.xml

+ 30 - 0
sql/mysql/alter_elderly_check_in_wait_add_medical_report_urls.sql

@@ -0,0 +1,30 @@
+-- 入住待审表体检报告 url 字段(非必填)
+-- fourth_approve 阶段上传的各项体检报告(均为 url,允许为空),使用 TEXT 避免行大小超过 65535 字节上限
+-- 血生化(blood_biochemistry) 由 肾功能/血脂/心肌酶/电解质/凝血功能 合并而来
+
+-- 步骤一:若此前已按旧结构执行过本脚本,先删除已被合并的 5 个字段(首次执行请注释掉此段)
+ALTER TABLE `elderly_check_in_wait`
+    DROP COLUMN `renal_function`,
+    DROP COLUMN `blood_fat`,
+    DROP COLUMN `myocardial_enzyme`,
+    DROP COLUMN `electrolyte`,
+    DROP COLUMN `coagulation_function`;
+
+-- 步骤二:新增体检报告 url 字段
+ALTER TABLE `elderly_check_in_wait`
+    ADD COLUMN `second_liver_two_half_and_half` text DEFAULT NULL COMMENT '乙肝两对半' AFTER `commit_remark`,
+    ADD COLUMN `syphilis` text DEFAULT NULL COMMENT '梅毒' AFTER `second_liver_two_half_and_half`,
+    ADD COLUMN `hiv` text DEFAULT NULL COMMENT 'HIV' AFTER `syphilis`,
+    ADD COLUMN `tuberculosis_bacillus_antibody` text DEFAULT NULL COMMENT '结核杆菌抗体' AFTER `hiv`,
+    ADD COLUMN `hepatitis_c` text DEFAULT NULL COMMENT '丙肝' AFTER `tuberculosis_bacillus_antibody`,
+    ADD COLUMN `hepatitis_e` text DEFAULT NULL COMMENT '戊肝' AFTER `hepatitis_c`,
+    ADD COLUMN `blood_routine_examination` text DEFAULT NULL COMMENT '血常规' AFTER `hepatitis_e`,
+    ADD COLUMN `urine_routines` text DEFAULT NULL COMMENT '尿常规' AFTER `blood_routine_examination`,
+    ADD COLUMN `fecal_routine` text DEFAULT NULL COMMENT '粪常规' AFTER `urine_routines`,
+    ADD COLUMN `liver_function` text DEFAULT NULL COMMENT '肝功能' AFTER `fecal_routine`,
+    ADD COLUMN `blood_biochemistry` text DEFAULT NULL COMMENT '血生化' AFTER `liver_function`,
+    ADD COLUMN `rabat` text DEFAULT NULL COMMENT '胸片' AFTER `blood_biochemistry`,
+    ADD COLUMN `head_ct` text DEFAULT NULL COMMENT '头颅CT' AFTER `rabat`,
+    ADD COLUMN `ecg` text DEFAULT NULL COMMENT '心电图' AFTER `head_ct`,
+    ADD COLUMN `bmd` text DEFAULT NULL COMMENT '骨密度' AFTER `ecg`,
+    ADD COLUMN `cognitive_assessment_report` text DEFAULT NULL COMMENT '认知评估报告' AFTER `bmd`;

+ 8 - 0
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/business/BpmElderlyController.java

@@ -56,6 +56,14 @@ public class BpmElderlyController {
         return success(elderlApplyService.createApplyRetreat(getLoginUserId(), createReqVO));
     }
 
+    @PostMapping("/retreatSimpleCreate")
+    @PreAuthorize("@ss.hasAnyPermissions('check-out:add', 'check-out:relaunch')")
+    @Operation(summary = "创建退住请求申请(离住转退住)")
+    @TenantIgnore
+    public CommonResult<Long> retreatSimpleCreate(@Valid @RequestBody BpmApplyRetreatSimpleCreateReqVO createReqVO) {
+        return success(elderlApplyService.createApplyRetreatSimple(getLoginUserId(), createReqVO));
+    }
+
     @PostMapping("/retreatRevoke")
     @PreAuthorize("@ss.hasAnyPermissions('check-out:add', 'check-out:relaunch')")
     @Operation(summary = "撤销退住申请(审批通过未结算)")

+ 36 - 0
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/business/vo/BpmApplyRetreatSimpleCreateReqVO.java

@@ -0,0 +1,36 @@
+package cn.iocoder.yudao.module.bpm.controller.admin.business.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.time.LocalDate;
+
+@Schema(description = "管理后台 - 退住申请(离住转退住) Request VO")
+@Data
+public class BpmApplyRetreatSimpleCreateReqVO {
+
+    @Schema(description = "退住日期", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "退住日期不能为空")
+    private LocalDate retreatDate;
+
+    @Schema(description = "费用截止日期", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "费用截止日期不能为空")
+    private LocalDate costDeadline;
+
+    @Schema(description = "长者ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    @NotNull(message = "长者ID不能为空")
+    private Long elderlyId;
+
+    @Schema(description = "退住原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "不适应")
+    @NotEmpty(message = "退住原因不能为空")
+    private String retreatReason;
+
+    @Schema(description = "退住描述", example = "长者主动要求退住")
+    private String retreatDescribe;
+
+    @Schema(description = "离住记录ID(离住转退住时传入,用于对该离住记录做返院登记)", example = "1024")
+    private Long tempOutId;
+
+}

+ 11 - 0
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/business/BpmElderlApplyService.java

@@ -25,6 +25,17 @@ public interface BpmElderlApplyService {
 
     Long createApplyRetreat(Long userId, BpmApplyRetreatCreateReqVO createReqVO);
 
+    /**
+     * 退住申请(离住转退住)
+     * <p>
+     * 不需要校验是否存在未返院的离住记录,也不需要校验费用截止日期月有无该长者账单。
+     *
+     * @param userId      用户编号
+     * @param createReqVO 创建请求参数
+     * @return 退住申请编号
+     */
+    Long createApplyRetreatSimple(Long userId, BpmApplyRetreatSimpleCreateReqVO createReqVO);
+
     void revokeApprovedRetreat(Long userId, Long retreatRecordId);
 
     Long bedChangeCreate(Long loginUserId, BedChangeRecordCreateReqVO createReqVO);

+ 36 - 0
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/business/BpmElderlApplyServiceImpl.java

@@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.common.util.string.StringUtil;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
 import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
+import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
 import cn.iocoder.yudao.module.bpm.controller.admin.business.vo.*;
 import cn.iocoder.yudao.module.bpm.dal.dataobject.business.BpmBusinessFormDO;
 import cn.iocoder.yudao.module.bpm.dal.mysql.business.BpmBusinessFormMapper;
@@ -177,6 +178,41 @@ public class BpmElderlApplyServiceImpl implements BpmElderlApplyService {
         return bpmBusinessFormService.create(businessFormCreateReqVO);
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    @LogRecord(type = DMISSION_RETREAT_TYPE, subType = DMISSION_ELDER_RETREAT_SUB_TYPE, bizNo = "{{#createReqVO.elderlyId}}",
+            success = DMISSION_ELDER_RETREAT_SUCCESS, extra = "{{#createReqVO.elderlyId}}")
+    public Long createApplyRetreatSimple(Long userId, BpmApplyRetreatSimpleCreateReqVO createReqVO) {
+        // 离住转退住:跳过未返院离住记录校验,但保留费用账单、未返院请假等通用校验
+        elderlyExpenseApi.applyRetreatCommonCheck(createReqVO.getElderlyId(), createReqVO.getCostDeadline());
+        // 离住转退住:若费用截止日期当月无月度账单则生成;并对离住记录做返院登记(返院日期为费用截止日期)
+        elderlyExpenseApi.handleTempOutReturnForRetreat(createReqVO.getTempOutId(), createReqVO.getElderlyId(),
+                TenantContextHolder.getTenantId(), createReqVO.getCostDeadline());
+        ElderlyRetreatRecordRespVO elderlyRetreatRecordRespVO = new ElderlyRetreatRecordRespVO();
+        elderlyRetreatRecordRespVO.setElderlyId(createReqVO.getElderlyId());
+        elderlyRetreatRecordRespVO.setRetreatDate(createReqVO.getRetreatDate());
+        elderlyRetreatRecordRespVO.setCostDeadlineDate(createReqVO.getCostDeadline());
+        elderlyRetreatRecordRespVO.setReason(createReqVO.getRetreatReason());
+        elderlyRetreatRecordRespVO.setDescription(createReqVO.getRetreatDescribe());
+        elderlyRetreatRecordRespVO.setApplyType(1);
+        // 生成退住申请记录
+        Long id = bpmElderlyApi.addElderlyRetreatRecord(elderlyRetreatRecordRespVO);
+
+        BpmBusinessFormCreateReqVO businessFormCreateReqVO = new BpmBusinessFormCreateReqVO();
+        businessFormCreateReqVO.setBusinessId(id);
+        businessFormCreateReqVO.setBusinessId2(elderlyRetreatRecordRespVO.getElderlyId());
+        businessFormCreateReqVO.setUserId(userId);
+        businessFormCreateReqVO.setType(BpmBusinessTypeEnum.APPLY_RETREAT.getValue());
+        businessFormCreateReqVO.setTenantId(TenantContextHolder.getTenantId());
+        ElderlyInfoReqVO elderlyInfo = bpmElderlyApi.getElderlyInfo(elderlyRetreatRecordRespVO.getElderlyId());
+        if (null != elderlyInfo) {
+            LogRecordContext.putVariable("id", elderlyInfo.getId());
+            LogRecordContext.putVariable("elderName", elderlyInfo.getElderName());
+        }
+        LogRecordContext.putVariable("nickname", SecurityFrameworkUtils.getLoginUserNickname());
+        return bpmBusinessFormService.create(businessFormCreateReqVO);
+    }
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     @TenantIgnore

+ 33 - 1
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java

@@ -703,7 +703,39 @@ public class BpmTaskServiceImpl implements BpmTaskService {
         if ("fourth_approve".equals(key)) {
             reqVO.setPhysicalExaminationReport(parseString(variables, "physicalExaminationReport"));
             reqVO.setRemark(parseString(variables, "remark"));
-            if (StrUtil.isNotBlank(reqVO.getPhysicalExaminationReport())) {
+            reqVO.setSecondLiverTwoHalfAndHalf(parseString(variables, "secondLiverTwoHalfAndHalf"));
+            reqVO.setSyphilis(parseString(variables, "syphilis"));
+            reqVO.setHiv(parseString(variables, "hiv"));
+            reqVO.setTuberculosisBacillusAntibody(parseString(variables, "tuberculosisBacillusAntibody"));
+            reqVO.setHepatitisC(parseString(variables, "hepatitisC"));
+            reqVO.setHepatitisE(parseString(variables, "hepatitisE"));
+            reqVO.setBloodRoutineExamination(parseString(variables, "bloodRoutineExamination"));
+            reqVO.setUrineRoutines(parseString(variables, "urineRoutines"));
+            reqVO.setFecalRoutine(parseString(variables, "fecalRoutine"));
+            reqVO.setLiverFunction(parseString(variables, "liverFunction"));
+            reqVO.setBloodBiochemistry(parseString(variables, "bloodBiochemistry"));
+            reqVO.setRabat(parseString(variables, "rabat"));
+            reqVO.setHeadCt(parseString(variables, "headCt"));
+            reqVO.setEcg(parseString(variables, "ecg"));
+            reqVO.setBmd(parseString(variables, "bmd"));
+            reqVO.setCognitiveAssessmentReport(parseString(variables, "cognitiveAssessmentReport"));
+            if (StrUtil.isNotBlank(reqVO.getPhysicalExaminationReport())
+                    || StrUtil.isNotBlank(reqVO.getSecondLiverTwoHalfAndHalf())
+                    || StrUtil.isNotBlank(reqVO.getSyphilis())
+                    || StrUtil.isNotBlank(reqVO.getHiv())
+                    || StrUtil.isNotBlank(reqVO.getTuberculosisBacillusAntibody())
+                    || StrUtil.isNotBlank(reqVO.getHepatitisC())
+                    || StrUtil.isNotBlank(reqVO.getHepatitisE())
+                    || StrUtil.isNotBlank(reqVO.getBloodRoutineExamination())
+                    || StrUtil.isNotBlank(reqVO.getUrineRoutines())
+                    || StrUtil.isNotBlank(reqVO.getFecalRoutine())
+                    || StrUtil.isNotBlank(reqVO.getLiverFunction())
+                    || StrUtil.isNotBlank(reqVO.getBloodBiochemistry())
+                    || StrUtil.isNotBlank(reqVO.getRabat())
+                    || StrUtil.isNotBlank(reqVO.getHeadCt())
+                    || StrUtil.isNotBlank(reqVO.getEcg())
+                    || StrUtil.isNotBlank(reqVO.getBmd())
+                    || StrUtil.isNotBlank(reqVO.getCognitiveAssessmentReport())) {
                 checkInWaitApi.updateFourthReviewInfo(reqVO);
             }
             checkInWaitApi.updateCheckInWaitStatusByBusinessId(businessForm.getBusinessId(),

+ 26 - 1
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/bpm/BpmElderlyExpenseApi.java

@@ -22,6 +22,31 @@ public interface BpmElderlyExpenseApi {
      * 检查是否有未缴费的账单,存在则不能申请抛出异常
      * 检查是否有未进行返院登记的外出记录,存在则不能申请抛出异常
      */
+    void applyRetreatCheck(Long elderId, LocalDate costDeadlineDate);
 
-    void applyRetreatCheck(Long elderId,LocalDate costDeadlineDate);
+    /**
+     * 退住申请通用校验(普通退住与离住转退住均需校验)
+     *
+     * @param elderId           长者ID
+     * @param costDeadlineDate 费用截止日期
+     */
+    void applyRetreatCommonCheck(Long elderId, LocalDate costDeadlineDate);
+
+    /**
+     * 退住申请专属校验(仅普通退住需校验,离住转退住跳过)
+     * 检查是否存在未返院的离住记录,存在则不能申请抛出异常
+     *
+     * @param elderId 长者ID
+     */
+    void applyRetreatTempOutCheck(Long elderId);
+
+    /**
+     * 离住转退住:生成费用截止日期当月的月度账单(若该月不存在时),并对指定离住记录做返院登记
+     *
+     * @param tempOutId        离住记录ID
+     * @param elderId          长者ID
+     * @param tenantId         机构ID
+     * @param costDeadlineDate 费用截止日期(作为返院日期,并据此确定账单月份)
+     */
+    void handleTempOutReturnForRetreat(Long tempOutId, Long elderId, Long tenantId, LocalDate costDeadlineDate);
 }

+ 17 - 0
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/bpm/vo/CheckInWaitSupplementReqVO.java

@@ -19,4 +19,21 @@ public class CheckInWaitSupplementReqVO {
     private String auditName;
 
     private Long bedId;
+
+    private String secondLiverTwoHalfAndHalf;
+    private String syphilis;
+    private String hiv;
+    private String tuberculosisBacillusAntibody;
+    private String hepatitisC;
+    private String hepatitisE;
+    private String bloodRoutineExamination;
+    private String urineRoutines;
+    private String fecalRoutine;
+    private String liverFunction;
+    private String bloodBiochemistry;
+    private String rabat;
+    private String headCt;
+    private String ecg;
+    private String bmd;
+    private String cognitiveAssessmentReport;
 }

+ 16 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/bpm/BpmCheckInWaitApiImpl.java

@@ -122,6 +122,22 @@ public class BpmCheckInWaitApiImpl implements BpmCheckInWaitApi {
         updateDO.setId(reqVO.getId());
         updateDO.setRemark(reqVO.getRemark());
         updateDO.setPhysicalExaminationReport(reqVO.getPhysicalExaminationReport());
+        updateDO.setSecondLiverTwoHalfAndHalf(reqVO.getSecondLiverTwoHalfAndHalf());
+        updateDO.setSyphilis(reqVO.getSyphilis());
+        updateDO.setHiv(reqVO.getHiv());
+        updateDO.setTuberculosisBacillusAntibody(reqVO.getTuberculosisBacillusAntibody());
+        updateDO.setHepatitisC(reqVO.getHepatitisC());
+        updateDO.setHepatitisE(reqVO.getHepatitisE());
+        updateDO.setBloodRoutineExamination(reqVO.getBloodRoutineExamination());
+        updateDO.setUrineRoutines(reqVO.getUrineRoutines());
+        updateDO.setFecalRoutine(reqVO.getFecalRoutine());
+        updateDO.setLiverFunction(reqVO.getLiverFunction());
+        updateDO.setBloodBiochemistry(reqVO.getBloodBiochemistry());
+        updateDO.setRabat(reqVO.getRabat());
+        updateDO.setHeadCt(reqVO.getHeadCt());
+        updateDO.setEcg(reqVO.getEcg());
+        updateDO.setBmd(reqVO.getBmd());
+        updateDO.setCognitiveAssessmentReport(reqVO.getCognitiveAssessmentReport());
         return checkInWaitMapper.updateById(updateDO);
     }
 

+ 57 - 7
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/bpm/BpmElderlyExpenseApiImpl.java

@@ -17,6 +17,7 @@ import cn.iocoder.yudao.module.system.api.wechat.dto.CorpSendMessage;
 import cn.iocoder.yudao.module.system.api.wechat.dto.CorpWechatTextcard;
 import cn.iocoder.yudao.module.system.api.wechat.dto.WechatMessageSaveReq;
 import cn.iocoder.yudao.module.system.controller.admin.biz.vo.ExpenseOrderItemVO;
+import cn.iocoder.yudao.module.system.controller.admin.biz.vo.ExpenseOrderSaveVO;
 import cn.iocoder.yudao.module.system.controller.admin.biz.vo.ExpenseOrderVO;
 import cn.iocoder.yudao.module.system.controller.admin.biz.vo.RefundSettlementOrderRespVO;
 import cn.iocoder.yudao.module.system.dal.dataobject.biz.*;
@@ -452,16 +453,27 @@ public class BpmElderlyExpenseApiImpl implements BpmElderlyExpenseApi {
     }
 
     @Override
-    public void applyRetreatCheck(Long elderId,LocalDate costDeadlineDate){
+    public void applyRetreatCheck(Long elderId, LocalDate costDeadlineDate) {
+        applyRetreatCommonCheck(elderId, costDeadlineDate);
+        applyRetreatTempOutCheck(elderId);
+    }
+
+    /**
+     * 退住申请通用校验(普通退住与离住转退住均需校验)
+     * <p>
+     * 1. 费用截止日期月是否存在该长者账单(仅入住状态为在院长者校验)
+     * 2. 是否存在未返院的请假记录
+     */
+    public void applyRetreatCommonCheck(Long elderId, LocalDate costDeadlineDate) {
         ElderlyInfoDO elderlyInfoDO = elderlyInfoMapper.selectById(elderId);
-        if(elderlyInfoDO.getInStatusType() == 1){
+        if (elderlyInfoDO.getInStatusType() == 1) {
             YearMonth deadLineYearMonth = YearMonth.from(costDeadlineDate);
             List<ExpenseOrderDO> expenseOrderDOS = expenseOrderMapper.selectList(new LambdaQueryWrapperX<ExpenseOrderDO>()
                     .eq(ExpenseOrderDO::getElderId, elderId)
                     .eq(ExpenseOrderDO::getBillingMonth, deadLineYearMonth)
-                    .in(ExpenseOrderDO::getType,1,2)
+                    .in(ExpenseOrderDO::getType, 1, 2)
             );
-            if(CollectionUtil.isEmpty(expenseOrderDOS)){
+            if (CollectionUtil.isEmpty(expenseOrderDOS)) {
                 throw exception(APPLY_RETREAT_CURRENT_EXPENSE_ORDER_NOT_EXISTS);
             }
         }
@@ -470,14 +482,21 @@ public class BpmElderlyExpenseApiImpl implements BpmElderlyExpenseApi {
                 .isNull(ElderlyAskLeaveDO::getUpdateDate)
                 .and(w -> w.eq(ElderlyAskLeaveDO::getLeaveStatus, ElderlyAskLeaveDO.LEAVE_STATUS_APPROVED)
                         .or().isNull(ElderlyAskLeaveDO::getLeaveStatus)));
-        if(CollectionUtil.isNotEmpty(elderlyAskLeaveDOS)){
+        if (CollectionUtil.isNotEmpty(elderlyAskLeaveDOS)) {
             throw exception(APPLY_RETREAT_ASK_LEAVE_EXISTS);
         }
-        // 检查是否存在未返院的离住记录
+    }
+
+    /**
+     * 退住申请专属校验(仅普通退住需校验,离住转退住跳过)
+     * <p>
+     * 检查是否存在未返院的离住记录
+     */
+    public void applyRetreatTempOutCheck(Long elderId) {
         List<ElderlyTempOutDO> elderlyTempOutDOS = elderlyTempOutMapper.selectList(new LambdaQueryWrapperX<ElderlyTempOutDO>()
                 .eq(ElderlyTempOutDO::getElderId, elderId)
                 .eq(ElderlyTempOutDO::getOutStatus, 1));
-        if(CollectionUtil.isNotEmpty(elderlyTempOutDOS)){
+        if (CollectionUtil.isNotEmpty(elderlyTempOutDOS)) {
             throw exception(APPLY_RETREAT_TEMP_OUT_EXISTS);
         }
     }
@@ -492,4 +511,35 @@ public class BpmElderlyExpenseApiImpl implements BpmElderlyExpenseApi {
                 .set(ExpenseItemDO::getChangeEndDate, endDate);
         expenseItemMapper.update(null, updateWrapper);
     }
+
+    @Override
+    public void handleTempOutReturnForRetreat(Long tempOutId, Long elderId, Long tenantId, LocalDate costDeadlineDate) {
+        if (tempOutId == null || elderId == null || costDeadlineDate == null) {
+            return;
+        }
+        // 1. 费用截止日期当月若无月度账单,则生成该长者该月账单(参考 batchGenerateExpenseBill 单长者逻辑)
+        YearMonth billingMonth = YearMonth.from(costDeadlineDate);
+        ExpenseOrderSaveVO saveVO = new ExpenseOrderSaveVO();
+        saveVO.setTenantId(tenantId);
+        saveVO.setBillingMonth(billingMonth.toString());
+        saveVO.setElderId(elderId);
+        expenseOrderService.batchGenerateExpenseBill(saveVO, null);
+
+        // 2. 对离住记录做返院登记,返院日期为费用截止日期
+        ElderlyTempOutDO tempOutDO = elderlyTempOutMapper.selectById(tempOutId);
+        if (tempOutDO == null) {
+            return;
+        }
+        // 仅当该离住记录仍未返院时才登记,避免重复登记
+        if (tempOutDO.getOutStatus() != null && tempOutDO.getOutStatus() == 2) {
+            return;
+        }
+        YearMonth comeYm = YearMonth.from(costDeadlineDate);
+        ElderlyTempOutDO updateDO = new ElderlyTempOutDO();
+        updateDO.setId(tempOutId);
+        updateDO.setComeTime(costDeadlineDate.atStartOfDay());
+        updateDO.setComeMonth(comeYm.toString());
+        updateDO.setOutStatus(2);
+        elderlyTempOutMapper.updateById(updateDO);
+    }
 }

+ 5 - 5
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/order/OrderApiImpl.java

@@ -666,11 +666,11 @@ public class OrderApiImpl implements OrderApi {
         BigDecimal nurseDeduct = nz(typeMap.get(2));
         BigDecimal mealDeduct = nz(typeMap.get(3));
         BigDecimal serviceDeduct = nz(typeMap.get(7));
-        // 如果退住了那么就按退住结算单的显示
-        dto.setBedActualAmount(bedDeduct);
-        dto.setMealActualAmount(mealDeduct);
-        dto.setNurseActualAmount(nurseDeduct);
-        dto.setServiceActualAmount(serviceDeduct);
+
+        dto.setBedActualAmount(nz(dto.getBedActualAmount()).add(bedDeduct));
+        dto.setMealActualAmount(nz(dto.getMealActualAmount()).add(mealDeduct));
+        dto.setNurseActualAmount(nz(dto.getNurseActualAmount()).add(nurseDeduct));
+        dto.setServiceActualAmount(nz(dto.getServiceActualAmount()).add(serviceDeduct));
 
         BigDecimal actualTotal = dto.getBedActualAmount()
                 .add(dto.getMealActualAmount())

+ 4 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/vo/ElderlyTempOutRespVO.java

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.module.system.controller.admin.biz.vo;
 
+import cn.iocoder.yudao.module.system.api.bpm.vo.ElderlyRetreatRecordRespVO;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
@@ -55,5 +56,8 @@ public class ElderlyTempOutRespVO {
 
     @Schema(description = "机构id")
     private Long tenantId;
+
+    @Schema(description = "退住申请单数据(长者存在退住申请时返回)")
+    private ElderlyRetreatRecordRespVO retreatRecord;
 }
 

+ 1 - 1
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/biz/DailyExpensesDO.java

@@ -58,7 +58,7 @@ public class DailyExpensesDO {
     /**
      * 费用来源
      */
-    @Schema(description = "费用来源类型,1:日常 2:变更 3:外出 4:额外 5:分期 6:赠送 7:点餐 8:优惠抵扣 9:用药")
+    @Schema(description = "费用来源类型,1:日常 2:变更 3:外出 4:额外 5:分期 6:赠送 7:点餐 8:优惠抵扣 9:用药 10:离住")
     private Integer type;
     /**
      * 单价

+ 33 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/biz/ElderlyCheckInWaitDO.java

@@ -51,4 +51,37 @@ public class ElderlyCheckInWaitDO extends BaseNoDeleteDO {
     private String medicalCareRemark;
     private String commitRemark;
 
+    /** 乙肝两对半 url */
+    private String secondLiverTwoHalfAndHalf;
+    /** 梅毒 url */
+    private String syphilis;
+    /** HIV url */
+    private String hiv;
+    /** 结核杆菌抗体 url */
+    private String tuberculosisBacillusAntibody;
+    /** 丙肝 url */
+    private String hepatitisC;
+    /** 戊肝 url */
+    private String hepatitisE;
+    /** 血常规 url */
+    private String bloodRoutineExamination;
+    /** 尿常规 url */
+    private String urineRoutines;
+    /** 粪常规 url */
+    private String fecalRoutine;
+    /** 肝功能 url */
+    private String liverFunction;
+    /** 血生化 url */
+    private String bloodBiochemistry;
+    /** 胸片 url */
+    private String rabat;
+    /** 头颅CT url */
+    private String headCt;
+    /** 心电图 url */
+    private String ecg;
+    /** 骨密度 url */
+    private String bmd;
+    /** 认知评估报告 url */
+    private String cognitiveAssessmentReport;
+
 }

+ 3 - 1
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/biz/ElderlyInfoServiceImpl.java

@@ -929,7 +929,9 @@ public class ElderlyInfoServiceImpl implements ElderlyInfoService {
                 .eq(ElderlyCheckInRecordDO::getCurrentFlag, 0)
                 .orderByDesc(ElderlyCheckInRecordDO::getCreatedTime)
                 .last("LIMIT 1"));
-        return getCheckInDetail(checkInRecord.getId());
+        CheckInRecordDetailRespVO checkInDetail = getCheckInDetail(checkInRecord.getId());
+        checkInDetail.setCheckInDeadlineTime(elderlyContract.getExpireTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
+        return checkInDetail;
     }
 
     @Override

+ 159 - 71
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/biz/ElderlyTempOutServiceImpl.java

@@ -5,19 +5,14 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
+import cn.iocoder.yudao.module.system.api.bpm.vo.ElderlyRetreatRecordRespVO;
 import cn.iocoder.yudao.module.system.controller.admin.biz.vo.ElderlyTempOutCreateReqVO;
 import cn.iocoder.yudao.module.system.controller.admin.biz.vo.ElderlyTempOutPageReqVO;
 import cn.iocoder.yudao.module.system.controller.admin.biz.vo.ElderlyTempOutRespVO;
 import cn.iocoder.yudao.module.system.controller.admin.biz.vo.ElderlyTempOutUpdateReqVO;
 import cn.iocoder.yudao.module.system.controller.admin.biz.vo.ExpenseItemRespVO;
 import cn.iocoder.yudao.module.system.controller.admin.biz.vo.ExpenseOrderSaveVO;
-import cn.iocoder.yudao.module.system.dal.dataobject.biz.DailyExpensesDO;
-import cn.iocoder.yudao.module.system.dal.dataobject.biz.ElderlyTempOutDO;
-import cn.iocoder.yudao.module.system.dal.dataobject.biz.ElderlyInfoDO;
-import cn.iocoder.yudao.module.system.dal.dataobject.biz.ExpenseItemDO;
-import cn.iocoder.yudao.module.system.dal.dataobject.biz.ExpenseOrderDO;
-import cn.iocoder.yudao.module.system.dal.dataobject.biz.ExpenseOrderItemDO;
-import cn.iocoder.yudao.module.system.dal.dataobject.biz.ElderlyContractDO;
+import cn.iocoder.yudao.module.system.dal.dataobject.biz.*;
 import cn.iocoder.yudao.module.system.dal.mysql.biz.*;
 import cn.iocoder.yudao.module.system.enums.change.BusinessConstants;
 import cn.iocoder.yudao.module.system.enums.common.BooleanEnum;
@@ -78,6 +73,9 @@ public class ElderlyTempOutServiceImpl implements ElderlyTempOutService {
     @Autowired
     private ElderlyContractMapper elderlyContractMapper;
 
+    @Autowired
+    private ElderlyRetreatRecordMapper elderlyRetreatRecordMapper;
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void create(ElderlyTempOutCreateReqVO createReq) {
@@ -142,82 +140,149 @@ public class ElderlyTempOutServiceImpl implements ElderlyTempOutService {
         YearMonth billYm = YearMonth.from(outTime);
         String billingMonth = billYm.format(DateTimeFormatter.ofPattern("yyyy-MM"));
 
-        ExpenseOrderDO monthOrder = expenseOrderMapper.selectOne(new LambdaQueryWrapperX<ExpenseOrderDO>()
+        // 查询离住当月及之后的月度/入院账单,账单不存在时自然不会产生任何费用
+        List<ExpenseOrderDO> monthOrderList = expenseOrderMapper.selectList(new LambdaQueryWrapperX<ExpenseOrderDO>()
                 .eq(ExpenseOrderDO::getElderId, elderId)
-                .eq(ExpenseOrderDO::getBillingMonth, billingMonth)
-                .in(ExpenseOrderDO::getType, 1,2));
-        if (monthOrder == null) {
-            return;
-        }
-        if (Boolean.TRUE.equals(monthOrder.getConfirmStatus()) || Boolean.TRUE.equals(monthOrder.getIsLock())) {
-            return;
-        }
-
-        List<ExpenseOrderItemDO> orderItems = expenseOrderItemMapper.selectList(new LambdaQueryWrapperX<ExpenseOrderItemDO>()
-                .eq(ExpenseOrderItemDO::getExpenseOrderId, monthOrder.getId())
-                .eq(ExpenseOrderItemDO::getExpenseSource, BusinessConstants.EXPENSE_ITEM));
-        if (CollectionUtil.isEmpty(orderItems)) {
-            return;
-        }
-
-        LocalDate outDate = outTime.toLocalDate();
-        LocalDate monthEnd = billYm.atEndOfMonth();
-        if (outDate.isAfter(monthEnd)) {
-            return;
-        }
-
-        int refundDays = monthEnd.getDayOfMonth() - outDate.getDayOfMonth() + 1;
-        int daysInMonth = billYm.lengthOfMonth();
-
-        for (ExpenseOrderItemDO item : orderItems) {
-            if (item.getType() == null) {
-                continue;
-            }
-            // 只处理“月固定费用”(床位费/护理费/膳食费/服务费...),排除押金/一次性等
-            if (!item.getExpenseSource().equals(BusinessConstants.EXPENSE_ITEM)) {
+                .ge(ExpenseOrderDO::getBillingMonth, billingMonth)
+                .in(ExpenseOrderDO::getType, 1, 2));
+        for (ExpenseOrderDO monthOrder : monthOrderList) {
+            if (monthOrder == null) {
                 continue;
             }
 
-            BigDecimal monthAmount = item.getTotalAmount() == null ? BigDecimal.ZERO : item.getTotalAmount();
-            if (monthAmount.compareTo(BigDecimal.ZERO) == 0) {
+            List<ExpenseOrderItemDO> orderItems = expenseOrderItemMapper.selectList(new LambdaQueryWrapperX<ExpenseOrderItemDO>()
+                    .eq(ExpenseOrderItemDO::getExpenseOrderId, monthOrder.getId())
+                    .eq(ExpenseOrderItemDO::getExpenseSource, BusinessConstants.EXPENSE_ITEM));
+            if (CollectionUtil.isEmpty(orderItems)) {
                 continue;
             }
-            BigDecimal dayPrice = monthAmount.divide(BigDecimal.valueOf(daysInMonth), 8, RoundingMode.DOWN);
-            BigDecimal refundAmount = dayPrice.multiply(BigDecimal.valueOf(refundDays)).setScale(2, RoundingMode.HALF_UP).negate();
-            if (refundAmount.compareTo(BigDecimal.ZERO) == 0) {
+
+            LocalDate outDate = outTime.toLocalDate();
+            LocalDate monthEnd = billYm.atEndOfMonth();
+            if (outDate.isAfter(monthEnd)) {
                 continue;
             }
 
-            // 离住冲减不生成日常费用记录:直接写入账单明细(expenseSource=expense_item,金额为负数)
-            ExpenseOrderItemDO orderItem = new ExpenseOrderItemDO();
-            orderItem.setExpenseOrderId(monthOrder.getId());
-            orderItem.setSourceExpenseItemId(item.getSourceExpenseItemId());
-            orderItem.setExpenseSource(BusinessConstants.EXPENSE_ITEM);
-            orderItem.setCount(refundDays);
-            orderItem.setItemName(item.getItemName());
-            orderItem.setItemCategoryName(item.getItemCategoryName());
-            orderItem.setPrice(dayPrice);
-            orderItem.setActualPrice(dayPrice);
-            orderItem.setTotalAmount(refundAmount);
-            orderItem.setRoundAmount(orderItem.getTotalAmount().setScale(0, RoundingMode.HALF_UP));
-            orderItem.setRoundTwoDecimalAmount(orderItem.getTotalAmount().setScale(2, RoundingMode.HALF_UP));
-            orderItem.setCreatedTime(new Date());
-            orderItem.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
-            orderItem.setTenantId(tenantId);
-            orderItem.setStartDate(outDate);
-            orderItem.setEndDate(monthEnd);
-            orderItem.setDescription("离住退费冲减:" + outDate + "至" + monthEnd + "共" + refundDays + "天," + item.getItemName());
-            orderItem.setType(item.getType());
-            orderItem.setItemId(item.getItemId());
-            orderItem.setIsMonthlyExpense(BooleanEnum.TRUE.getValue());
-            expenseOrderItemMapper.insert(orderItem);
-            BigDecimal newAmount = monthOrder.getActualAmount() == null ? BigDecimal.ZERO : monthOrder.getActualAmount();
-            newAmount = newAmount.add(orderItem.getTotalAmount().setScale(2, RoundingMode.DOWN));
-            monthOrder.setActualAmount(newAmount);
-            expenseOrderMapper.updateById(monthOrder);
+            int refundDays = monthEnd.getDayOfMonth() - outDate.getDayOfMonth() + 1;
+            int daysInMonth = billYm.lengthOfMonth();
+
+            for (ExpenseOrderItemDO item : orderItems) {
+                if (item.getType() == null) {
+                    continue;
+                }
+                // 只处理“月固定费用”(床位费/护理费/膳食费/服务费...),排除押金/一次性等
+                if (!item.getExpenseSource().equals(BusinessConstants.EXPENSE_ITEM)) {
+                    continue;
+                }
+
+                BigDecimal monthAmount = item.getTotalAmount() == null ? BigDecimal.ZERO : item.getTotalAmount();
+                if (monthAmount.compareTo(BigDecimal.ZERO) == 0) {
+                    continue;
+                }
+                int itemDays = (item.getEndDate() != null && item.getStartDate() != null) ? item.getEndDate().getDayOfMonth() - item.getStartDate().getDayOfMonth() + 1 : daysInMonth;
+                BigDecimal dayPrice = monthAmount.divide(BigDecimal.valueOf(itemDays), 8, RoundingMode.DOWN);
+                BigDecimal refundAmount = dayPrice.multiply(BigDecimal.valueOf(refundDays)).setScale(2, RoundingMode.HALF_UP).negate();
+                if (refundAmount.compareTo(BigDecimal.ZERO) == 0) {
+                    continue;
+                }
+
+                // 账单已缴费、锁定、确认:生成日常费用记录(来源=离住)并写入已缴费账单明细
+                if (Objects.equals(monthOrder.getPayStatus(), 1) || Boolean.TRUE.equals(monthOrder.getConfirmStatus()) || Boolean.TRUE.equals(monthOrder.getIsLock())) {
+                    DailyExpensesDO dailyExpenses = buildTempOutDailyExpense(elderId, tenantId, monthOrder.getBillOrderNumber(),
+                            item, dayPrice, refundAmount, refundDays, outDate, monthEnd, billingMonth);
+                    dailyExpensesMapper.insert(dailyExpenses);
+
+                    ExpenseOrderItemDO orderItem = new ExpenseOrderItemDO();
+                    orderItem.setExpenseOrderId(monthOrder.getId());
+                    orderItem.setSourceExpenseItemId(dailyExpenses.getId());
+                    orderItem.setExpenseSource(BusinessConstants.DAILY_EXPENSES);
+                    orderItem.setCount(refundDays);
+                    orderItem.setItemName(dailyExpenses.getItemName());
+                    orderItem.setItemCategoryName(dailyExpenses.getItemCategory());
+                    orderItem.setPrice(dayPrice);
+                    orderItem.setActualPrice(dayPrice);
+                    orderItem.setTotalAmount(refundAmount);
+                    orderItem.setRoundAmount(orderItem.getTotalAmount().setScale(0, RoundingMode.HALF_UP));
+                    orderItem.setRoundTwoDecimalAmount(orderItem.getTotalAmount().setScale(2, RoundingMode.HALF_UP));
+                    orderItem.setCreatedTime(new Date());
+                    orderItem.setCreatedBy(dailyExpenses.getCreatedBy());
+                    orderItem.setTenantId(tenantId);
+                    orderItem.setStartDate(outDate);
+                    orderItem.setEndDate(monthEnd);
+                    orderItem.setDescription(dailyExpenses.getRemarks());
+                    orderItem.setType(item.getType());
+                    orderItem.setItemId(item.getItemId());
+                    orderItem.setIsMonthlyExpense(BooleanEnum.TRUE.getValue());
+                    expenseOrderItemMapper.insert(orderItem);
+
+                    BigDecimal newAmount = monthOrder.getActualAmount() == null ? BigDecimal.ZERO : monthOrder.getActualAmount();
+                    newAmount = newAmount.add(orderItem.getTotalAmount().setScale(2, RoundingMode.DOWN));
+                    monthOrder.setActualAmount(newAmount);
+                    expenseOrderMapper.updateById(monthOrder);
+                } else {
+                    // 账单未缴费:直接生成费用项在未缴费账单中(不生成日常费用记录)
+                    ExpenseOrderItemDO orderItem = new ExpenseOrderItemDO();
+                    orderItem.setExpenseOrderId(monthOrder.getId());
+                    orderItem.setSourceExpenseItemId(item.getSourceExpenseItemId());
+                    orderItem.setExpenseSource(BusinessConstants.EXPENSE_ITEM);
+                    orderItem.setCount(refundDays);
+                    orderItem.setItemName(item.getItemName());
+                    orderItem.setItemCategoryName(item.getItemCategoryName());
+                    orderItem.setPrice(dayPrice);
+                    orderItem.setActualPrice(dayPrice);
+                    orderItem.setTotalAmount(refundAmount);
+                    orderItem.setRoundAmount(orderItem.getTotalAmount().setScale(0, RoundingMode.HALF_UP));
+                    orderItem.setRoundTwoDecimalAmount(orderItem.getTotalAmount().setScale(2, RoundingMode.HALF_UP));
+                    orderItem.setCreatedTime(new Date());
+                    orderItem.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
+                    orderItem.setTenantId(tenantId);
+                    orderItem.setStartDate(outDate);
+                    orderItem.setEndDate(monthEnd);
+                    orderItem.setDescription("离住退费冲减:" + outDate + "至" + monthEnd + "共" + refundDays + "天," + item.getItemName());
+                    orderItem.setType(item.getType());
+                    orderItem.setItemId(item.getItemId());
+                    orderItem.setIsMonthlyExpense(BooleanEnum.TRUE.getValue());
+                    expenseOrderItemMapper.insert(orderItem);
+                    BigDecimal newAmount = monthOrder.getActualAmount() == null ? BigDecimal.ZERO : monthOrder.getActualAmount();
+                    newAmount = newAmount.add(orderItem.getTotalAmount().setScale(2, RoundingMode.DOWN));
+                    monthOrder.setActualAmount(newAmount);
+                    expenseOrderMapper.updateById(monthOrder);
+                }
+            }
         }
     }
 
+    /**
+     * 构造临时外出离住退费的日常费用记录(费用来源类型=外出)
+     */
+    private DailyExpensesDO buildTempOutDailyExpense(Long elderId, Long tenantId, String billOrderNumber,
+                                                    ExpenseOrderItemDO item, BigDecimal dayPrice, BigDecimal refundAmount,
+                                                    int refundDays, LocalDate outDate, LocalDate monthEnd, String billingMonth) {
+        DailyExpensesDO dailyExpenses = new DailyExpensesDO();
+        dailyExpenses.setElderId(elderId);
+        dailyExpenses.setExpenseOrderNumber(billOrderNumber);
+        dailyExpenses.setItemId(item.getItemId());
+        dailyExpenses.setItemCategory(item.getItemCategoryName());
+        dailyExpenses.setItemName(item.getItemName());
+        dailyExpenses.setType(10); // 费用来源类型:3-离住
+        dailyExpenses.setPrice(dayPrice);
+        dailyExpenses.setAmount(refundAmount);
+        dailyExpenses.setRoundAmount(refundAmount.setScale(0, RoundingMode.HALF_UP));
+        dailyExpenses.setRoundTwoDecimalAmount(refundAmount.setScale(2, RoundingMode.HALF_UP));
+        dailyExpenses.setCount(refundDays);
+        dailyExpenses.setStatus(0);
+        dailyExpenses.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
+        dailyExpenses.setCreatedTime(new Date());
+        dailyExpenses.setAccountingTime(new Date());
+        dailyExpenses.setStartDate(outDate);
+        dailyExpenses.setEndDate(monthEnd);
+        dailyExpenses.setAttributionBillTime(billingMonth);
+        dailyExpenses.setIsGenerateBill(BooleanEnum.TRUE.getValue());
+        dailyExpenses.setRemarks("离住退费冲减:" + outDate + "至" + monthEnd + "共" + refundDays + "天," + item.getItemName());
+        dailyExpenses.setTenantId(tenantId);
+        return dailyExpenses;
+    }
+
     /**
      * 返院:返院当月,未生成则生成月账单并按天计费;已生成则补固定费
      * @param elderId
@@ -389,10 +454,30 @@ public class ElderlyTempOutServiceImpl implements ElderlyTempOutService {
             if (record.getBedId() != null) {
                 record.setBedName(buildService.getFullBedNameByBedId(record.getBedId()));
             }
+            if (record.getElderId() != null) {
+                record.setRetreatRecord(getLatestRetreatRecord(record.getElderId()));
+            }
         }
         return respPage;
     }
 
+    /**
+     * 查询长者最新的退住申请单(存在则返回,否则返回 null)
+     */
+    private ElderlyRetreatRecordRespVO getLatestRetreatRecord(Long elderId) {
+        if (elderId == null) {
+            return null;
+        }
+        ElderlyRetreatRecordDO retreatRecordDO = elderlyRetreatRecordMapper.selectOne(new LambdaQueryWrapperX<ElderlyRetreatRecordDO>()
+                .eq(ElderlyRetreatRecordDO::getElderlyId, elderId)
+                .orderByDesc(ElderlyRetreatRecordDO::getId)
+                .last("LIMIT 1"));
+        if (retreatRecordDO == null) {
+            return null;
+        }
+        return BeanUtils.toBean(retreatRecordDO, ElderlyRetreatRecordRespVO.class);
+    }
+
     @Override
     public ElderlyTempOutRespVO get(Long id) {
         ElderlyTempOutDO dataObject = elderlyTempOutMapper.selectById(id);
@@ -415,6 +500,9 @@ public class ElderlyTempOutServiceImpl implements ElderlyTempOutService {
         if (respVO.getBedId() != null) {
             respVO.setBedName(buildService.getFullBedNameByBedId(respVO.getBedId()));
         }
+        if (respVO.getElderId() != null) {
+            respVO.setRetreatRecord(getLatestRetreatRecord(respVO.getElderId()));
+        }
         return respVO;
     }
 }

+ 14 - 11
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/biz/ExpenseOrderServiceImpl.java

@@ -2266,17 +2266,20 @@ public class ExpenseOrderServiceImpl implements ExpenseOrderService {
         String billingMonth = saveVO.getBillingMonth();
 
         try {
-            // 一次性加载所有数据
-            List<Long> elderIds = expenseMapper.selectList(new LambdaQueryWrapperX<ExpenseDO>()
-                            .select(ExpenseDO::getElderId)
-                            .eq(ExpenseDO::getTenantId, tenantId))
-                    .stream()
-                    .map(ExpenseDO::getElderId)
-                    .distinct()
-                    .collect(Collectors.toList());
-            // 批量处理长者账单
-            processBatchElderlyBilling(elderIds, tenantId, billingMonth, taskId);
-
+            if(saveVO.getElderId() != null){
+                processBatchElderlyBilling(Collections.singletonList(saveVO.getElderId()), tenantId, billingMonth, taskId);
+            }else {
+                // 一次性加载所有数据
+                List<Long> elderIds = expenseMapper.selectList(new LambdaQueryWrapperX<ExpenseDO>()
+                                .select(ExpenseDO::getElderId)
+                                .eq(ExpenseDO::getTenantId, tenantId))
+                        .stream()
+                        .map(ExpenseDO::getElderId)
+                        .distinct()
+                        .collect(Collectors.toList());
+                // 批量处理长者账单
+                processBatchElderlyBilling(elderIds, tenantId, billingMonth, taskId);
+            }
         } catch (Exception e) {
             log.error("批量生成账单失败", e);
             if (taskId != null) {

+ 2 - 2
yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/ElderlyChangeRecordMapper.xml

@@ -100,7 +100,7 @@
             ecr.is_discount,
             ecr.reason,
             ecr.elderly_id,
-            ecr.change_files AS bedFiles,
+            ecr.change_files,
             ecr.overhead_charge_id,
             ecr.amount,
             ecr.actual_amount,
@@ -147,7 +147,7 @@
         ecr.is_discount,
         ecr.reason,
         ecr.elderly_id,
-        ecr.change_files AS bedFiles,
+        ecr.change_files,
         ecr.overhead_charge_id,
         ecr.amount,
         ecr.actual_amount,

+ 1 - 0
yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/ElderlyInfoMapper.xml

@@ -252,6 +252,7 @@
             ei.id AS elder_id,
             ei.elder_sex,
             ei.elder_age,
+            ei.birthday,
             ei.in_status_type,
             ei.nurse_level_name,
             ei.id_card,