|
@@ -37,12 +37,12 @@ import cn.iocoder.yudao.module.system.enums.change.BusinessConstants;
|
|
|
import cn.iocoder.yudao.module.system.enums.common.BooleanEnum;
|
|
import cn.iocoder.yudao.module.system.enums.common.BooleanEnum;
|
|
|
import cn.iocoder.yudao.module.system.framework.sms.util.AliyunSmsUtils;
|
|
import cn.iocoder.yudao.module.system.framework.sms.util.AliyunSmsUtils;
|
|
|
import cn.iocoder.yudao.module.system.service.discount.DiscountRuleService;
|
|
import cn.iocoder.yudao.module.system.service.discount.DiscountRuleService;
|
|
|
|
|
+import cn.iocoder.yudao.module.system.service.miniapp.JiashuUserService;
|
|
|
|
|
+import cn.iocoder.yudao.module.system.service.wx.WechatBusinessService;
|
|
|
import com.alibaba.excel.EasyExcel;
|
|
import com.alibaba.excel.EasyExcel;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
-import com.fasterxml.jackson.databind.JsonNode;
|
|
|
|
|
-import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
|
|
import com.mzt.logapi.context.LogRecordContext;
|
|
import com.mzt.logapi.context.LogRecordContext;
|
|
|
import com.mzt.logapi.starter.annotation.LogRecord;
|
|
import com.mzt.logapi.starter.annotation.LogRecord;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
@@ -51,7 +51,6 @@ import org.apache.commons.lang3.StringUtils;
|
|
|
import org.springframework.beans.BeanUtils;
|
|
import org.springframework.beans.BeanUtils;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.data.redis.core.RedisTemplate;
|
|
import org.springframework.data.redis.core.RedisTemplate;
|
|
|
-import org.springframework.http.ResponseEntity;
|
|
|
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
|
|
import javax.annotation.Resource;
|
|
import javax.annotation.Resource;
|
|
@@ -59,7 +58,6 @@ import javax.servlet.http.HttpServletResponse;
|
|
|
|
|
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
import org.springframework.validation.annotation.Validated;
|
|
import org.springframework.validation.annotation.Validated;
|
|
|
-import org.springframework.web.client.RestTemplate;
|
|
|
|
|
|
|
|
|
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
|
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exceptionCustomMsg;
|
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exceptionCustomMsg;
|
|
@@ -158,7 +156,11 @@ public class ExpenseOrderServiceImpl implements ExpenseOrderService {
|
|
|
private TaskStatusManager taskStatusManager;
|
|
private TaskStatusManager taskStatusManager;
|
|
|
|
|
|
|
|
@Autowired
|
|
@Autowired
|
|
|
- private RestTemplate restTemplate;
|
|
|
|
|
|
|
+ private WechatBusinessService wechatBusinessService;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private JiashuUserService jiashuUserService;
|
|
|
|
|
+
|
|
|
|
|
|
|
|
@Autowired
|
|
@Autowired
|
|
|
private ElderlyTempOutMapper elderlyTempOutMapper;
|
|
private ElderlyTempOutMapper elderlyTempOutMapper;
|
|
@@ -3439,6 +3441,47 @@ public class ExpenseOrderServiceImpl implements ExpenseOrderService {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 根据账单类型获取缴费类型描述
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param type 账单类型(1入院账单 2月度账单 3试住账单)
|
|
|
|
|
+ * @return 缴费类型描述,未知返回空串
|
|
|
|
|
+ */
|
|
|
|
|
+ private String getBillTypeDesc(Integer type) {
|
|
|
|
|
+ if (type == null) {
|
|
|
|
|
+ return "";
|
|
|
|
|
+ }
|
|
|
|
|
+ switch (type) {
|
|
|
|
|
+ case 1:
|
|
|
|
|
+ return "入院账单";
|
|
|
|
|
+ case 2:
|
|
|
|
|
+ return "月度账单";
|
|
|
|
|
+ case 3:
|
|
|
|
|
+ return "试住账单";
|
|
|
|
|
+ default:
|
|
|
|
|
+ return "";
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 将账单月份(yyyy-MM)格式化为微信模板 time 关键词所需的日期格式(yyyy-MM-dd)。
|
|
|
|
|
+ * 若格式异常则原样返回。
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param billingMonth 账单月份,如 "2025-09"
|
|
|
|
|
+ * @return 格式化后的日期,如 "2025-09-01"
|
|
|
|
|
+ */
|
|
|
|
|
+ private String formatBillDate(String billingMonth) {
|
|
|
|
|
+ if (StringUtils.isBlank(billingMonth)) {
|
|
|
|
|
+ return "";
|
|
|
|
|
+ }
|
|
|
|
|
+ // 账单月份格式为 yyyy-MM,补齐为合法的日期(time 关键词要求日期类型)
|
|
|
|
|
+ if (billingMonth.length() == 7 && billingMonth.contains("-")) {
|
|
|
|
|
+ return billingMonth + "-01";
|
|
|
|
|
+ }
|
|
|
|
|
+ return billingMonth;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
private void addDiscountRecord(Long elderId, String billingMonth, ExpenseItemRespVO item) {
|
|
private void addDiscountRecord(Long elderId, String billingMonth, ExpenseItemRespVO item) {
|
|
|
DiscountRecordDO discountRecordDO = new DiscountRecordDO();
|
|
DiscountRecordDO discountRecordDO = new DiscountRecordDO();
|
|
|
discountRecordDO.setElderId(elderId);
|
|
discountRecordDO.setElderId(elderId);
|
|
@@ -3491,82 +3534,45 @@ public class ExpenseOrderServiceImpl implements ExpenseOrderService {
|
|
|
TenantDO tenantDO = tenantMapper.selectById(relativesDO.getTenantId());
|
|
TenantDO tenantDO = tenantMapper.selectById(relativesDO.getTenantId());
|
|
|
String tenantName = tenantDO != null ? tenantDO.getName() : "";
|
|
String tenantName = tenantDO != null ? tenantDO.getName() : "";
|
|
|
|
|
|
|
|
- // 组装推送参数
|
|
|
|
|
- BillRequestDTO billRequestDTO = new BillRequestDTO();
|
|
|
|
|
- billRequestDTO.setUserPhone(relativesDO.getPhone());
|
|
|
|
|
- billRequestDTO.setElderId(expenseOrderDO.getElderId());
|
|
|
|
|
- billRequestDTO.setElderName(relativesDO.getPeopleName());
|
|
|
|
|
- billRequestDTO.setOrganizationId(relativesDO.getTenantId());
|
|
|
|
|
- billRequestDTO.setOrganizationName(tenantName);
|
|
|
|
|
- billRequestDTO.setRelationship(relativesDO.getRelation());
|
|
|
|
|
-
|
|
|
|
|
- BillRequestDTO.BillMessage billMessage = new BillRequestDTO.BillMessage();
|
|
|
|
|
- Integer type = expenseOrderDO.getType();
|
|
|
|
|
- if (type == 1) {
|
|
|
|
|
- billMessage.setBillType("入院账单");
|
|
|
|
|
- } else if (type == 2) {
|
|
|
|
|
- billMessage.setBillType("月度账单");
|
|
|
|
|
- } else if (type == 3) {
|
|
|
|
|
- billMessage.setBillType("试住账单");
|
|
|
|
|
- }
|
|
|
|
|
- billMessage.setBillDate(expenseOrderDO.getBillingMonth());
|
|
|
|
|
- billMessage.setAmount(String.valueOf(expenseOrderDO.getActualAmount().setScale(2,RoundingMode.HALF_UP)));
|
|
|
|
|
- billMessage.setElderName(relativesDO.getPeopleName());
|
|
|
|
|
- billMessage.setOrganizationName(tenantName);
|
|
|
|
|
- billMessage.setOrderId(expenseOrderDO.getId());
|
|
|
|
|
- billRequestDTO.setBillMessage(billMessage);
|
|
|
|
|
-
|
|
|
|
|
- // 调用推送接口
|
|
|
|
|
- List<BillRequestDTO> billList = Arrays.asList(billRequestDTO);
|
|
|
|
|
- Map<String,Object> map = new HashMap<>();
|
|
|
|
|
- map.put("billList", billList);
|
|
|
|
|
-
|
|
|
|
|
- try {
|
|
|
|
|
- ResponseEntity<String> response = restTemplate.postForEntity(
|
|
|
|
|
- "http://home.ynims.com/api/wechat/pushBill", map, String.class);
|
|
|
|
|
-
|
|
|
|
|
- log.info("推送账单结果:{}", response.getBody());
|
|
|
|
|
-
|
|
|
|
|
- // 解析响应结果
|
|
|
|
|
- ObjectMapper objectMapper = new ObjectMapper();
|
|
|
|
|
- JsonNode rootNode = objectMapper.readTree(response.getBody());
|
|
|
|
|
- int code = rootNode.path("code").asInt();
|
|
|
|
|
-
|
|
|
|
|
- if (code == 200) {
|
|
|
|
|
- JsonNode dataNode = rootNode.path("data");
|
|
|
|
|
- successCount += dataNode.path("successCount").asInt(0);
|
|
|
|
|
- failCount += dataNode.path("failCount").asInt(0);
|
|
|
|
|
-
|
|
|
|
|
- // 根据results结果更新账单推送状态
|
|
|
|
|
- JsonNode resultsNode = dataNode.path("results");
|
|
|
|
|
- if (resultsNode != null && resultsNode.isArray() && resultsNode.size() > 0) {
|
|
|
|
|
- for (JsonNode result : resultsNode) {
|
|
|
|
|
- boolean success = result.path("success").asBoolean(false);
|
|
|
|
|
- if (success) {
|
|
|
|
|
- // 将成功推送的账单ID加入集合
|
|
|
|
|
- pushedOrderIds.add(expenseOrderDO.getId());
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // 查询该亲属是否已关注公众号(yanglao-jiashu.user_v2.mp_open_id)
|
|
|
|
|
+ String mpOpenId = jiashuUserService.getMpOpenIdByPhone(relativesDO.getPhone());
|
|
|
|
|
+ if (StringUtils.isBlank(mpOpenId)) {
|
|
|
|
|
+ notFoundUsers.add(String.format("%s (%s): 未关注公众号或不存在",
|
|
|
|
|
+ relativesDO.getPeopleName(), relativesDO.getPhone()));
|
|
|
|
|
+ failCount++;
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
+ // 组装账单模板消息参数(字段与微信公众号模板一致)
|
|
|
|
|
+ String billType = getBillTypeDesc(expenseOrderDO.getType());
|
|
|
|
|
+ BigDecimal actualAmount = expenseOrderDO.getActualAmount();
|
|
|
|
|
+ String amount = actualAmount == null ? "0.00"
|
|
|
|
|
+ : actualAmount.setScale(2, RoundingMode.HALF_UP).toPlainString();
|
|
|
|
|
+ String billDate = formatBillDate(expenseOrderDO.getBillingMonth());
|
|
|
|
|
|
|
|
- // 收集未找到账单的用户信息
|
|
|
|
|
- JsonNode notFoundBillsNode = dataNode.path("notFoundBills");
|
|
|
|
|
- if (notFoundBillsNode != null && notFoundBillsNode.isArray() && notFoundBillsNode.size() > 0) {
|
|
|
|
|
- for (JsonNode notFound : notFoundBillsNode) {
|
|
|
|
|
- String userPhone = notFound.path("userPhone").asText();
|
|
|
|
|
- String reason = notFound.path("reason").asText();
|
|
|
|
|
- notFoundUsers.add(String.format("%s (%s): %s",
|
|
|
|
|
- billRequestDTO.getElderName(), userPhone, reason));
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- failCount++;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // 调用工程内实现:推送微信公众号账单模板消息
|
|
|
|
|
+ boolean sendSuccess;
|
|
|
|
|
+ try {
|
|
|
|
|
+ sendSuccess = wechatBusinessService.pushBillMessage(
|
|
|
|
|
+ mpOpenId,
|
|
|
|
|
+ expenseOrderDO.getId(),
|
|
|
|
|
+ billType,
|
|
|
|
|
+ relativesDO.getPeopleName(),
|
|
|
|
|
+ amount,
|
|
|
|
|
+ billDate,
|
|
|
|
|
+ tenantName);
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
- log.error("推送账单失败,长者ID: {}", expenseOrderDO.getElderId(), e);
|
|
|
|
|
- failedElderNames.add(elderlyInfoDO.getElderName());
|
|
|
|
|
|
|
+ log.error("推送账单失败,长者ID: {}, openId: {}", expenseOrderDO.getElderId(), mpOpenId, e);
|
|
|
|
|
+ sendSuccess = false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (sendSuccess) {
|
|
|
|
|
+ successCount++;
|
|
|
|
|
+ // 将成功推送的账单ID加入集合(用于更新推送状态)
|
|
|
|
|
+ pushedOrderIds.add(expenseOrderDO.getId());
|
|
|
|
|
+ } else {
|
|
|
failCount++;
|
|
failCount++;
|
|
|
|
|
+ failedElderNames.add(elderlyInfoDO.getElderName());
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -3619,6 +3625,7 @@ public class ExpenseOrderServiceImpl implements ExpenseOrderService {
|
|
|
.eqIfPresent(ExpenseOrderDO::getPayStatus, pageReqVO.getPayStatus())
|
|
.eqIfPresent(ExpenseOrderDO::getPayStatus, pageReqVO.getPayStatus())
|
|
|
.orderByDesc(ExpenseOrderDO::getBillingMonth)
|
|
.orderByDesc(ExpenseOrderDO::getBillingMonth)
|
|
|
);
|
|
);
|
|
|
|
|
+ log.info("小程序获取账单,长者id:{}",relativesDO.getPeopleId());
|
|
|
expenseOrders.forEach(i -> i.setElderName(relativesDO.getPeopleName()));
|
|
expenseOrders.forEach(i -> i.setElderName(relativesDO.getPeopleName()));
|
|
|
if (CollectionUtil.isEmpty(expenseOrders)) {
|
|
if (CollectionUtil.isEmpty(expenseOrders)) {
|
|
|
throw exception(RELATIVES_NOT_HAVE_BILL);
|
|
throw exception(RELATIVES_NOT_HAVE_BILL);
|