package com.gree.mall.manager.schedule; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; import com.baomidou.mybatisplus.core.toolkit.IdWorker; import com.gree.mall.manager.commonmapper.LockQueryMapper; import com.gree.mall.manager.enums.TransactionTypeEnum; import com.gree.mall.manager.enums.workorder.OrderBaseStatusEnum; import com.gree.mall.manager.plus.entity.PgOrderBase; import com.gree.mall.manager.plus.entity.UserCompanyCredit; import com.gree.mall.manager.plus.entity.UserCompanyCreditBill; import com.gree.mall.manager.plus.entity.UserCompanyCreditBillItem; import com.gree.mall.manager.plus.service.UserCompanyCreditBillItemService; import com.gree.mall.manager.plus.service.UserCompanyCreditBillService; import com.gree.mall.manager.plus.service.UserCompanyCreditService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.math.BigDecimal; import java.util.Date; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; /** * 用户商户授信账单相关定时任务 * @author :fengcy * @description:TODO * @date :2025/10/21 17:30 */ @ConditionalOnProperty(name = "schedule.enable", havingValue = "true", matchIfMissing = true) @Component @Slf4j //@Service public class UserCompanyCreditBillSchedule { @Resource UserCompanyCreditBillService userCompanyCreditBillService; @Resource UserCompanyCreditBillItemService userCompanyCreditBillItemService; @Resource LockQueryMapper lockQueryMapper; /** * 每日凌晨1点执行,检查是否有用户需要在当天生成账单 */ @Transactional @Scheduled(cron = "0 0 1 * * ?") public void generateBillsOnBillingDay(String inDate){ // DateTime curDate = DateUtil.parseDate(inDate); DateTime curDate = DateUtil.date(); int currentDay = curDate.dayOfMonth(); final int lastDayOfMonth = DateUtil.endOfMonth(curDate).dayOfMonth(); // 直接判断:1-28号 或 实际月末(无论月末是28/29/30/31) if (currentDay >= 1 && currentDay <= 28 || currentDay == lastDayOfMonth) { // 处理月末特殊情况 if (currentDay == lastDayOfMonth) { currentDay = 29; } // 获取账单日为今天的所有用户商户授信关系 List userCompanyCreditList = lockQueryMapper.findByBillingDay(currentDay); if (CollectionUtil.isNotEmpty(userCompanyCreditList)) { for (UserCompanyCredit credit : userCompanyCreditList) { generateBillForUserCompany(credit, curDate); } } } } private void generateBillForUserCompany(UserCompanyCredit credit, DateTime curDate) { final String userId = credit.getUserId(); final String companyWechatId = credit.getCompanyWechatId(); DateTime today = curDate; // DateTime today = DateUtil.date(); // 获取授信记录明细开始时间 Date startTime; // 获取授信记录明细结束时间 Date endTime = DateUtil.endOfDay(DateUtil.offsetDay(today, -1)); if (Objects.isNull(credit.getLastBillingDate())) { // 第一次一成账单开始时间取授信创建时间 startTime = credit.getCreateTime(); } else { // 取上次的结束时间(已加1秒,比如上次获取授信记录明细结束时间为2025-10-22 23:59:59, 再加1秒等于下次执行的开始时间2025-10-23 00:00:00) startTime = credit.getLastBillingDate(); } if (startTime.getTime() > endTime.getTime()) { // 如果开始时间比结束时间大就返回 return; } // 处理月末情况 if (credit.getBillingDay() == 29) { endTime = DateUtil.endOfDay(DateUtil.offsetDay(DateUtil.endOfMonth(today), -1)); } // 查询该周期内示对账的消费明细 List billItemList = userCompanyCreditBillItemService.lambdaQuery() .select(UserCompanyCreditBillItem::getId, UserCompanyCreditBillItem::getTransactionType, UserCompanyCreditBillItem::getAmount) .eq(UserCompanyCreditBillItem::getUserId, userId) .eq(UserCompanyCreditBillItem::getCompanyWechatId, companyWechatId) .between(UserCompanyCreditBillItem::getCreateTime, startTime, endTime) .isNull(UserCompanyCreditBillItem::getUserCompanyCreditBillId) .list(); if (billItemList.isEmpty()) { // 没有需要对账的明细 return; } // 计算总金额 BigDecimal totalAmount = billItemList.stream() .map(item -> { if (item.getTransactionType().equals(TransactionTypeEnum.CONSUMPTION.getKey())) { return item.getAmount(); } else if (item.getTransactionType().equals(TransactionTypeEnum.REFUND.getKey())) { return item.getAmount().negate(); } else if (item.getTransactionType().equals(TransactionTypeEnum.REPAYMENT.getKey())) { return (StringUtils.isBlank(item.getRepaymentBillId())) ? item.getAmount().negate() : BigDecimal.ZERO; } return BigDecimal.ZERO; }) .reduce(BigDecimal.ZERO, BigDecimal::add); // 检查总还款金额少于0的就等于0否则就是总金额 totalAmount = totalAmount.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : totalAmount; // 计算还款日(账单日+账期天数) Date dueDate = DateUtil.offsetDay(today, credit.getPaymentGracePeriod()); // 创建账单 UserCompanyCreditBill bill = new UserCompanyCreditBill(); bill.setBillId(IdWorker.getIdStr()) .setUserCompanyCreditId(credit.getId()) .setUserId(credit.getUserId()) .setCompanyWechatId(credit.getCompanyWechatId()) .setCompanyWechatName(credit.getCompanyWechatName()) .setAmount(totalAmount) .setRemainingAmount(totalAmount) .setCreateDate(DateUtil.parseDate(DateUtil.formatDate(today))) .setDueDate(dueDate) .setIsPaid(totalAmount.compareTo(BigDecimal.ZERO) <= 0) .setRemark(DateUtil.formatDateTime(startTime) + " - " + DateUtil.formatDateTime(endTime)) .insert(); userCompanyCreditBillItemService.lambdaUpdate() .set(UserCompanyCreditBillItem::getUserCompanyCreditBillId, bill.getBillId()) .in(UserCompanyCreditBillItem::getId, billItemList.stream() .map(UserCompanyCreditBillItem::getId) .collect(Collectors.toList())) .update(); // 更新用户商户授信记录 DateTime offsetSecond = DateUtil.beginOfDay(DateUtil.offsetDay(endTime, 1)); credit.setLastBillingDate(offsetSecond) .updateById(); } }