yupeng
2025-02-12 158fc64a58912fb5f3ea411a469c74a509d440c0
Merge remote-tracking branch 'origin/master' into xizang-changyun

# Conflicts:
# ruoyi-system/src/main/java/com/ruoyi/system/service/TBillService.java
# ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TBillServiceImpl.java
16个文件已修改
1个文件已添加
777 ■■■■ 已修改文件
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TContractController.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/TaskUtil.java 479 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/application-test.yml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/PayController.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/TBillController.java 38 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/dto/SetContractDto.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/dto/TContractDTO.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/mapper/TBillMapper.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/model/TContract.java 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/model/TContractRentType.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/query/TContractQuery.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/TBillService.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TBillServiceImpl.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/vo/TBillVO.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/vo/TContractVO.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/TBillMapper.xml 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/TContractMapper.xml 37 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TContractController.java
@@ -14,6 +14,7 @@
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.WebUtils;
import com.ruoyi.system.dto.SetContractDto;
import com.ruoyi.system.dto.TContractDTO;
import com.ruoyi.system.dto.THouseDTO;
import com.ruoyi.system.dto.TerminateContractDTO;
@@ -91,6 +92,7 @@
            tContractRentType.setIncreasingDecreasingType(dto.getIncreasingDecreasingType());
            tContractRentType.setNumericalValue(dto.getNumericalValue());
            tContractRentType.setChangeTime(dto.getChangeTime());
            tContractRentType.setCycleTime(dto.getCycleTime());
            contractRentTypeService.save(tContractRentType);
        }
        return R.ok();
@@ -109,6 +111,7 @@
            tContractRentType.setIncreasingDecreasingType(dto.getIncreasingDecreasingType());
            tContractRentType.setNumericalValue(dto.getNumericalValue());
            tContractRentType.setChangeTime(dto.getChangeTime());
            tContractRentType.setCycleTime(dto.getCycleTime());
            contractRentTypeService.save(tContractRentType);
        }
        return R.ok();
@@ -157,6 +160,7 @@
        TCheckAcceptRecord tCheckAcceptRecord = checkAcceptRecordService.lambdaQuery().eq(TCheckAcceptRecord::getContractId, id).one();
        res.setCheckResult(tCheckAcceptRecord.getCheckResult());
        res.setPayMoney(payMoney);
        return R.ok(res);
    }
    @Log(title = "合同管理-撤销审批", businessType =  BusinessType.UPDATE)
@@ -187,36 +191,41 @@
    private WordUtil wordUtil;
    @ApiOperation(value = "生成合同附件")
    @PostMapping("/set")
    public R set(Integer id, HttpServletResponse response){
        TContract contract = contractService.getById(id);
        THouse tHouse = houseService.getById(contract.getHouseId());
        Map<String, Object> templateParam = new HashMap<>(5);
        templateParam.put("partyOneName", contract.getPartyOneName());
        templateParam.put("partyTwoName", contract.getPartyTwoName());
        templateParam.put("houseAddress", tHouse.getHouseAddress());
        templateParam.put("houseArea", tHouse.getHouseArea()+"m²");
        templateParam.put("startTime", DateUtils.localDateTimeToStringYear(contract.getStartTime()));
        templateParam.put("endTime", DateUtils.localDateTimeToStringYear(contract.getEndTime()));
        templateParam.put("monthRent", "¥¥"+contract.getMonthRent()+"元");
        templateParam.put("monthRentString", "人民币"+NumberToChineseUtils.numberToChinese(contract.getMonthRent().setScale(2, BigDecimal.ROUND_DOWN).doubleValue()));
        templateParam.put("totalYear", "¥¥"+contract.getTotalYear()+"元");
        templateParam.put("totalYearString", "人民币"+NumberToChineseUtils.numberToChinese(contract.getTotalYear().setScale(2, BigDecimal.ROUND_DOWN).doubleValue()));
        templateParam.put("payType", contract.getPayType().equals("1")?"月":contract.getPayType().equals("2")?"季":"年");
        templateParam.put("firstRent", "¥"+(contract.getPayType().equals("1")?contract.getMonthRent():contract.getPayType().equals("2")?contract.getMonthRent().multiply(new BigDecimal("3")):contract.getMonthRent().multiply(new BigDecimal("12"))).setScale(2,BigDecimal.ROUND_DOWN)+"元");
        templateParam.put("firstRentString", "人民币"+NumberToChineseUtils.numberToChinese((contract.getPayType().equals("1")?contract.getMonthRent():contract.getPayType().equals("2")?contract.getMonthRent().multiply(new BigDecimal("3")):contract.getMonthRent().multiply(new BigDecimal("12")).setScale(2,BigDecimal.ROUND_DOWN)).doubleValue()));
        templateParam.put("nextPayTime", contract.getPayType().equals("1")?"月":contract.getPayType().equals("2")?"季":"年");
        templateParam.put("deposit", "¥"+contract.getDeposit()+"元");
        templateParam.put("depositString", NumberToChineseUtils.numberToChinese(contract.getDeposit().setScale(2, BigDecimal.ROUND_DOWN).doubleValue()));
        templateParam.put("partyOnePerson", contract.getPartyOnePerson());
        templateParam.put("partyOnePhone", contract.getPartyOnePhone());
        templateParam.put("partyTwoPerson", contract.getPartyTwoPerson());
        templateParam.put("partyTwoPhone", contract.getPartyTwoPhone());
        String url = wordUtil.generatePdf("/templates", "1_yzj_租赁合同.xml", templateParam, "租赁合同", "E:\\");
        return R.ok(url);
    public R<List<String>> set(@RequestBody SetContractDto dto,HttpServletResponse response){
        List<TContract> list = contractService.lambdaQuery().in(TContract::getId, dto.getIds()).list();
        List<String> res = new ArrayList<>();
        for (TContract contract : list) {
            THouse tHouse = houseService.getById(contract.getHouseId());
            Map<String, Object> templateParam = new HashMap<>(5);
            templateParam.put("partyOneName", contract.getPartyOneName());
            templateParam.put("partyTwoName", contract.getPartyTwoName());
            templateParam.put("houseAddress", tHouse.getHouseAddress());
            templateParam.put("houseArea", tHouse.getHouseArea()+"m²");
            templateParam.put("startTime", DateUtils.localDateTimeToStringYear(contract.getStartTime()));
            templateParam.put("endTime", DateUtils.localDateTimeToStringYear(contract.getEndTime()));
            templateParam.put("monthRent", "¥¥"+contract.getMonthRent()+"元");
            templateParam.put("monthRentString", "人民币"+NumberToChineseUtils.numberToChinese(contract.getMonthRent().setScale(2, BigDecimal.ROUND_DOWN).doubleValue()));
            templateParam.put("totalYear", "¥¥"+contract.getTotalYear()+"元");
            templateParam.put("totalYearString", "人民币"+NumberToChineseUtils.numberToChinese(contract.getTotalYear().setScale(2, BigDecimal.ROUND_DOWN).doubleValue()));
            templateParam.put("payType", contract.getPayType().equals("1")?"月":contract.getPayType().equals("2")?"季":"年");
            templateParam.put("firstRent", "¥"+(contract.getPayType().equals("1")?contract.getMonthRent():contract.getPayType().equals("2")?contract.getMonthRent().multiply(new BigDecimal("3")):contract.getMonthRent().multiply(new BigDecimal("12"))).setScale(2,BigDecimal.ROUND_DOWN)+"元");
            templateParam.put("firstRentString", "人民币"+NumberToChineseUtils.numberToChinese((contract.getPayType().equals("1")?contract.getMonthRent():contract.getPayType().equals("2")?contract.getMonthRent().multiply(new BigDecimal("3")):contract.getMonthRent().multiply(new BigDecimal("12")).setScale(2,BigDecimal.ROUND_DOWN)).doubleValue()));
            templateParam.put("nextPayTime", contract.getPayType().equals("1")?"月":contract.getPayType().equals("2")?"季":"年");
            templateParam.put("deposit", "¥"+contract.getDeposit()+"元");
            templateParam.put("depositString", NumberToChineseUtils.numberToChinese(contract.getDeposit().setScale(2, BigDecimal.ROUND_DOWN).doubleValue()));
            templateParam.put("partyOnePerson", contract.getPartyOnePerson());
            templateParam.put("partyOnePhone", contract.getPartyOnePhone());
            templateParam.put("partyTwoPerson", contract.getPartyTwoPerson());
            templateParam.put("partyTwoPhone", contract.getPartyTwoPhone());
            String url = wordUtil.generatePdf("/templates", "1_yzj_租赁合同.xml", templateParam, "租赁合同", "E:\\");
            res.add(url);
        }
        return R.ok(res);
    }
    /**
     * 光缆巡检列表导出
     * 导出
     */
    @ApiOperation(value = "导出")
    @Log(title = "导出", businessType = BusinessType.EXPORT)
@@ -224,7 +233,6 @@
    public void exportOpticalInspection(@RequestBody TContractQuery query)
    {
        List<ContractExport> contractExports = new ArrayList<>();
        List<TContract> exportList = contractService.contractExportList(query);
        for (TContract contract : exportList) {
            ContractExport contractExport = new ContractExport();
ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/TaskUtil.java
@@ -3,7 +3,9 @@
import com.ruoyi.system.model.TBill;
import com.ruoyi.system.model.TContract;
import com.ruoyi.system.model.TContractRentType;
import com.ruoyi.system.service.TBillService;
import com.ruoyi.system.service.TContractRentTypeService;
import com.ruoyi.system.service.TContractService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
@@ -32,8 +34,39 @@
    private TContractService contractService;
    @Autowired
    private TBillService billService;
    @Autowired
    private TContractRentTypeService contractRentTypeService;
    // 每天凌晨00点执行的定时任务 用于生成违约金
    @Scheduled(cron = "0 0 0 * * ?")
    public void dayOfProportionBill() {
        try {
            // 查询所有未缴费账单
            List<TBill> list = billService.lambdaQuery().eq(TBill::getPayFeesStatus, 1).list();
            for (TBill tBill : list) {
                TContract contract = contractService.getById(tBill.getContractId());
                LocalDateTime payableFeesTime = tBill.getPayableFeesTime();
                LocalDateTime now = LocalDateTime.now();
                // 计算两个时间相差多少个小时
                long hours = ChronoUnit.HOURS.between(payableFeesTime, now);
                long l = hours / 72;
                if (l>0){
                    // 计算每天租金
                    long days = ChronoUnit.DAYS.between(tBill.getStartTime(),tBill.getEndTime());
                    BigDecimal everyDayMoney = tBill.getPayableFeesMoney().divide(new BigDecimal(days), 2, BigDecimal.ROUND_DOWN);
                    // 违约金比例
                    BigDecimal proportion = contract.getProportion();
                    // 预期x天后的违约金
                    BigDecimal money = everyDayMoney.multiply(proportion).multiply(new BigDecimal(l));
                    tBill.setPayableFeesPenalty(money);
                }
            }
            billService.updateBatchById(list);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    // 每天凌晨00点执行的定时任务 用于合同生成第一笔账单
@@ -41,12 +74,14 @@
    public void dayOfFirstBill() {
        try {
            // 查询所有已签订的合同并且未生成第一笔账单的
            List<TContract> list = contractService.lambdaQuery().eq(TContract::getStatus, 4).isNull(TContract::getFirstPayTime).list();
            List<TContract> list = contractService.lambdaQuery().eq(TContract::getStatus, 4)
                    .isNull(TContract::getFirstPayTime).list();
            List<TBill> bills = new ArrayList<>();
            List<TContractRentType> contractRentTypes = contractRentTypeService.list();
            for (TContract contract : list) {
                contract.setFirstPayTime(contract.getStartTime().plusDays(10));
                // 第一次应缴费日期
                LocalDateTime firstPayTime = contract.getStartTime().plusDays(10);
                LocalDateTime firstPayTime = contract.getStartTime().plusDays(10).withHour(0).withMinute(0).withSecond(0);
                LocalDate localDate = contract.getStartTime().plusDays(10).toLocalDate();
                LocalDate now = LocalDate.now();
                // 如果应缴费日期和当前时间不相同 跳过
@@ -58,26 +93,75 @@
                rentBill.setContractNumber(contract.getContractNumber());
                LocalDateTime startPayTime = contract.getStartPayTime();
                LocalDateTime endTime1 = contract.getEndTime();
                // 计算两个时间相差多少天
                long days = ChronoUnit.DAYS.between(startPayTime, endTime1)+1L;
                // 如果时间小于30天 需要计算每日租金
                if (days<30){
                    rentBill.setPayableFeesMoney(contract.getMonthRent().divide(new BigDecimal("30"),2,BigDecimal.ROUND_DOWN).multiply(new BigDecimal(days)));
                }else{
                    rentBill.setPayableFeesMoney(contract.getPayType().equals("1")?contract.getMonthRent():
                            contract.getPayType().equals("2")?contract.getMonthRent().multiply(new BigDecimal("3")):contract.getMonthRent().multiply(new BigDecimal("12")).setScale(2,BigDecimal.ROUND_DOWN));
                }
//                // 计算两个时间相差多少天
//                // 如果时间小于30天 需要计算每日租金
//                if (days<30){
//                    rentBill.setPayableFeesMoney(contract.getMonthRent().divide(new BigDecimal("30"),2,BigDecimal.ROUND_DOWN).multiply(new BigDecimal(days)));
//                }else{
//                    rentBill.setPayableFeesMoney(contract.getPayType().equals("1")?contract.getMonthRent():
//                            contract.getPayType().equals("2")?contract.getMonthRent().multiply(new BigDecimal("3")):contract.getMonthRent().multiply(new BigDecimal("12")).setScale(2,BigDecimal.ROUND_DOWN));
//                }
                rentBill.setPayableFeesTime(firstPayTime);
                rentBill.setPayFeesStatus("1");
                rentBill.setBillType("1");
                rentBill.setStartTime(contract.getStartPayTime());
                if ((contract.getEndTime().getYear() == contract.getStartTime().getYear()) && (contract.getEndTime().getMonth() == contract.getStartTime().getMonth())) {
                    // 如果同年同月 那么账单周期为合同结束时间
                    rentBill.setEndTime(contract.getEndTime());
                } else {
                    // 否则 取当月最后一天
                    LocalDateTime endTime = contract.getStartTime().with(TemporalAdjusters.lastDayOfMonth()).withSecond(59).withHour(23).withMinute(59);
                    rentBill.setEndTime(endTime);
                TContractRentType tContractRentType = contractRentTypes.stream().filter(e -> e.getContractId().equals(contract.getId())).findFirst().orElse(null);
                if (tContractRentType!=null && contract.getStartPayTime().plusMonths(contract.getPayType().equals("1")? 1:contract.getPayType().equals("2")? 3:12).isAfter(tContractRentType.getChangeTime())){
                    // 计算租金变动的天数
                    long moneyDays = ChronoUnit.DAYS.between(tContractRentType.getChangeTime(), contract.getStartPayTime().plusMonths(contract.getPayType().equals("1")? 1:contract.getPayType().equals("2")? 3:12))+1L;
                    contract.setChangeTime(LocalDateTime.now());
                    // 递增递减的租金
                    BigDecimal contractRentTypeMoney = new BigDecimal("0");
                    // 不递增递减的租金
                    BigDecimal originalMoney = new BigDecimal("0");
                    // 原租金
                    switch (tContractRentType.getIncreasingDecreasingType()){
                        case 1:
                            switch (tContractRentType.getIncreasingDecreasing()){
                                case 1:
                                    contractRentTypeMoney =contractRentTypeMoney.add(contract.getChangeRent().multiply(new BigDecimal(100).add(tContractRentType.getNumericalValue()).divide(new BigDecimal(100),2,BigDecimal.ROUND_DOWN)).divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(moneyDays)));
                                    contract.setChangeRent(contractRentTypeMoney.add(contract.getChangeRent().multiply(new BigDecimal(100).add(tContractRentType.getNumericalValue()).divide(new BigDecimal(100),2,BigDecimal.ROUND_DOWN))));
                                    break;
                                case 2:
                                    contractRentTypeMoney = contractRentTypeMoney.add(contract.getChangeRent().multiply(new BigDecimal(100).subtract(tContractRentType.getNumericalValue()).divide(new BigDecimal(100),2,BigDecimal.ROUND_DOWN)).divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(moneyDays)));
                                    contract.setChangeRent(contractRentTypeMoney.add(contract.getChangeRent().multiply(new BigDecimal(100).subtract(tContractRentType.getNumericalValue()).divide(new BigDecimal(100),2,BigDecimal.ROUND_DOWN))));
                                    break;
                            }
                            break;
                        case 2:
                            switch (tContractRentType.getIncreasingDecreasing()){
                                case 1:
                                    contractRentTypeMoney =contractRentTypeMoney.add(contract.getChangeRent().add(tContractRentType.getNumericalValue())).divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(moneyDays));
                                    contract.setChangeRent(contractRentTypeMoney.add(contract.getChangeRent().add(tContractRentType.getNumericalValue())));
                                    break;
                                case 2:
                                    contractRentTypeMoney = contractRentTypeMoney.add(contract.getChangeRent().subtract(tContractRentType.getNumericalValue())).divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(moneyDays));
                                    contract.setChangeRent(contractRentTypeMoney.add(contract.getChangeRent().subtract(tContractRentType.getNumericalValue())));
                                    break;
                            }
                            break;
                    }
                    // 不需要涨租金的时间段
                    long originalDays = ChronoUnit.DAYS.between(contract.getFirstPayTime(), tContractRentType.getChangeTime());
                    originalMoney=originalMoney.add(contract.getMonthRent().divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN))
                            .multiply(new BigDecimal(originalDays));
                    rentBill.setPayableFeesMoney(contractRentTypeMoney.add(originalMoney));
                    if (contract.getFirstPayTime().plusMonths(contract.getPayType().equals("1")? 1:contract.getPayType().equals("2")? 3:12).isAfter(contract.getEndTime())){
                        rentBill.setEndTime(contract.getFirstPayTime().plusMonths(contract.getPayType().equals("1")? 1:contract.getPayType().equals("2")? 3:12));
                    }else{
                        rentBill.setEndTime(contract.getEndTime());
                    }
                }else{
                    if (contract.getFirstPayTime().plusMonths(contract.getPayType().equals("1")? 1:contract.getPayType().equals("2")? 3:12).isAfter(contract.getEndTime())){
                        rentBill.setEndTime(contract.getFirstPayTime().plusMonths(contract.getPayType().equals("1")? 1:contract.getPayType().equals("2")? 3:12));
                    }else{
                        rentBill.setEndTime(contract.getEndTime());
                    }
                    // 不走递增递减
                    long allDays = ChronoUnit.DAYS.between(contract.getFirstPayTime(), rentBill.getEndTime());
                    rentBill.setPayableFeesMoney(contract.getMonthRent().divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(allDays)));
                }
                // 租金账单
                bills.add(rentBill);
@@ -103,21 +187,173 @@
    public void dayOfEndBill() {
        try {
            // 查询所有已签订的合同并且已经生成第一笔账单的
            List<TContract> list = contractService.lambdaQuery().eq(TContract::getStatus, 4).isNotNull(TContract::getFirstPayTime).list();
            List<TContract> list = contractService.lambdaQuery().eq(TContract::getStatus, 4)
                    .ge(TContract::getEndTime,LocalDateTime.now())
                    .isNotNull(TContract::getFirstPayTime).list();
            List<TContractRentType> contractRentTypes = contractRentTypeService.list();
            List<TBill> bills = new ArrayList<>();
            for (TContract contract : list) {
                TBill beforeBill = billService.lambdaQuery().eq(TBill::getContractId, contract.getId()).eq(TBill::getBillType, 1).orderByDesc(TBill::getCreateTime)
                        .last("limit 1").one();
                if (!(beforeBill.getEndTime().toLocalDate().equals(contract.getEndTime().toLocalDate()))&&beforeBill.getEndTime().plusMonths(1).with(TemporalAdjusters.lastDayOfMonth()).isAfter(contract.getEndTime())){
                if (!(beforeBill.getEndTime().toLocalDate().equals(contract.getEndTime().toLocalDate()))
                    &&
                        (contract.getPayType().equals("1")?
                        beforeBill.getEndTime().plusMonths(1):contract.getPayType().equals("2")?
                        beforeBill.getEndTime().plusMonths(3):beforeBill.getEndTime().plusMonths(12))
                        .with(TemporalAdjusters.lastDayOfMonth()).isAfter(contract.getEndTime())
                && beforeBill.getEndTime().isBefore(contract.getEndTime())
                ){
                    TBill tBill = new TBill();
                    tBill.setContractId(contract.getId());
                    long days = ChronoUnit.DAYS.between((contract.getPayType().equals("1")?
                            beforeBill.getEndTime().plusMonths(1):contract.getPayType().equals("2")?
                            beforeBill.getEndTime().plusMonths(3):beforeBill.getEndTime().plusMonths(12)).with(TemporalAdjusters.firstDayOfMonth()), contract.getEndTime())+1L;
                    if (contract.getIsIncreasing()){
                        TContractRentType tContractRentType = contractRentTypes.stream().filter(e -> e.getContractId().equals(contract.getId())).findFirst().orElse(null);
                        if (tContractRentType!=null
                                && beforeBill.getEndTime().isBefore(tContractRentType.getChangeTime())
                                && beforeBill.getEndTime().plusMonths(contract.getPayType().equals("1")? 1:contract.getPayType().equals("2")? 3:12).with(TemporalAdjusters.lastDayOfMonth()).isAfter(tContractRentType.getChangeTime())){
                            // 如果没变过
                            if (contract.getChangeTime()==null){
                                contract.setChangeTime(LocalDateTime.now());
                                // 租金递增递减的时长 天
                                long moneyDays = ChronoUnit.DAYS.between(tContractRentType.getChangeTime(), contract.getEndTime());
                                // 递增递减的租金
                                BigDecimal contractRentTypeMoney = new BigDecimal("0");
                                // 不递增递减的租金
                                BigDecimal originalMoney = new BigDecimal("0");
                                // 原租金
                                switch (tContractRentType.getIncreasingDecreasingType()){
                                    case 1:
                                        switch (tContractRentType.getIncreasingDecreasing()){
                                            case 1:
                                                contractRentTypeMoney =contractRentTypeMoney.add(contract.getChangeRent().multiply(new BigDecimal(100).add(tContractRentType.getNumericalValue()).divide(new BigDecimal(100),2,BigDecimal.ROUND_DOWN)).divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(days)));
                                                contract.setChangeRent(contractRentTypeMoney.add(contract.getChangeRent().multiply(new BigDecimal(100).add(tContractRentType.getNumericalValue()).divide(new BigDecimal(100),2,BigDecimal.ROUND_DOWN))));
                                                break;
                                            case 2:
                                                contractRentTypeMoney = contractRentTypeMoney.add(contract.getChangeRent().multiply(new BigDecimal(100).subtract(tContractRentType.getNumericalValue()).divide(new BigDecimal(100),2,BigDecimal.ROUND_DOWN)).divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(days)));
                                                contract.setChangeRent(contractRentTypeMoney.add(contract.getChangeRent().multiply(new BigDecimal(100).subtract(tContractRentType.getNumericalValue()).divide(new BigDecimal(100),2,BigDecimal.ROUND_DOWN))));
                                                break;
                                        }
                                        break;
                                    case 2:
                                        switch (tContractRentType.getIncreasingDecreasing()){
                                            case 1:
                                                contractRentTypeMoney =contractRentTypeMoney.add(contract.getChangeRent().add(tContractRentType.getNumericalValue())).divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(moneyDays));
                                                contract.setChangeRent(contractRentTypeMoney.add(contract.getChangeRent().add(tContractRentType.getNumericalValue())));
                                                break;
                                            case 2:
                                                contractRentTypeMoney = contractRentTypeMoney.add(contract.getChangeRent().subtract(tContractRentType.getNumericalValue())).divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(moneyDays));
                                                contract.setChangeRent(contractRentTypeMoney.add(contract.getChangeRent().subtract(tContractRentType.getNumericalValue())));
                                                break;
                                        }
                                        break;
                                }
                                // 不需要涨租金的时间段
                                long originalDays = ChronoUnit.DAYS.between(beforeBill.getEndTime(), tContractRentType.getChangeTime());
                                originalMoney=originalMoney.add(contract.getMonthRent().divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN))
                                        .multiply(new BigDecimal(originalDays));
                                tBill.setPayableFeesMoney(contractRentTypeMoney.add(originalMoney));
                            }else{
                                // 之前已经涨、跌过租金了 需要判断周期是否还需要再涨、跌
                                if ((LocalDateTime.now().getYear() - contract.getChangeTime().getYear())%tContractRentType.getCycleTime()==0){
                                    contract.setChangeTime(LocalDateTime.now());
                                    // 租金递增递减的时长 天
                                    long moneyDays = ChronoUnit.DAYS.between(tContractRentType.getChangeTime(), contract.getEndTime());
                                    // 递增递减的租金
                                    BigDecimal contractRentTypeMoney = new BigDecimal("0");
                                    // 不递增递减的租金
                                    BigDecimal originalMoney = new BigDecimal("0");
                                    // 原租金
                                    switch (tContractRentType.getIncreasingDecreasingType()){
                                        case 1:
                                            switch (tContractRentType.getIncreasingDecreasing()){
                                                case 1:
                                                    contractRentTypeMoney =contractRentTypeMoney.add(contract.getChangeRent().multiply(new BigDecimal(100).add(tContractRentType.getNumericalValue()).divide(new BigDecimal(100),2,BigDecimal.ROUND_DOWN)).divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(days)));
                                                    contract.setChangeRent(contractRentTypeMoney.add(contract.getChangeRent().multiply(new BigDecimal(100).add(tContractRentType.getNumericalValue()).divide(new BigDecimal(100),2,BigDecimal.ROUND_DOWN))));
                                                    break;
                                                case 2:
                                                    contractRentTypeMoney = contractRentTypeMoney.add(contract.getChangeRent().multiply(new BigDecimal(100).subtract(tContractRentType.getNumericalValue()).divide(new BigDecimal(100),2,BigDecimal.ROUND_DOWN)).divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(days)));
                                                    contract.setChangeRent(contractRentTypeMoney.add(contract.getChangeRent().multiply(new BigDecimal(100).subtract(tContractRentType.getNumericalValue()).divide(new BigDecimal(100),2,BigDecimal.ROUND_DOWN))));
                                                    break;
                                            }
                                            break;
                                        case 2:
                                            switch (tContractRentType.getIncreasingDecreasing()){
                                                case 1:
                                                    contractRentTypeMoney =contractRentTypeMoney.add(contract.getChangeRent().add(tContractRentType.getNumericalValue())).divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(moneyDays));
                                                    contract.setChangeRent(contractRentTypeMoney.add(contract.getChangeRent().add(tContractRentType.getNumericalValue())));
                                                    break;
                                                case 2:
                                                    contractRentTypeMoney = contractRentTypeMoney.add(contract.getChangeRent().subtract(tContractRentType.getNumericalValue())).divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(moneyDays));
                                                    contract.setChangeRent(contractRentTypeMoney.add(contract.getChangeRent().subtract(tContractRentType.getNumericalValue())));
                                                    break;
                                            }
                                            break;
                                    }
                                    // 不需要涨租金的时间段
                                    long originalDays = ChronoUnit.DAYS.between(beforeBill.getEndTime(), tContractRentType.getChangeTime());
                                    originalMoney=originalMoney.add(contract.getMonthRent().divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN))
                                            .multiply(new BigDecimal(originalDays));
                                    tBill.setPayableFeesMoney(contractRentTypeMoney.add(originalMoney));
                                }else{
                                    // 不涨租金 用上次的
                                    // 租金递增递减的时长 天
                                    long moneyDays = ChronoUnit.DAYS.between(tContractRentType.getChangeTime(), contract.getEndTime());
                                    // 递增递减的租金
                                    BigDecimal contractRentTypeMoney = new BigDecimal("0");
                                    // 不递增递减的租金
                                    BigDecimal originalMoney = new BigDecimal("0");
                                    // 原租金
                                    switch (tContractRentType.getIncreasingDecreasingType()){
                                        case 1:
                                            switch (tContractRentType.getIncreasingDecreasing()){
                                                case 1:
                                                    contractRentTypeMoney =contractRentTypeMoney.add(contract.getChangeRent().divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(days))) ;
                                                    break;
                                                case 2:
                                                    contractRentTypeMoney = contractRentTypeMoney.add(contract.getChangeRent().divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(days)));
                                                    break;
                                            }
                                            break;
                                        case 2:
                                            switch (tContractRentType.getIncreasingDecreasing()){
                                                case 1:
                                                    contractRentTypeMoney =contractRentTypeMoney.add(contract.getChangeRent()).divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(moneyDays));
                                                    break;
                                                case 2:
                                                    contractRentTypeMoney = contractRentTypeMoney.add(contract.getChangeRent()).divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(moneyDays));
                                                    break;
                                            }
                                            break;
                                    }
                                    // 不需要涨租金的时间段
                                    long originalDays = ChronoUnit.DAYS.between(beforeBill.getEndTime(), tContractRentType.getChangeTime());
                                    originalMoney=originalMoney.add(contract.getMonthRent().divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN))
                                            .multiply(new BigDecimal(originalDays));
                                    tBill.setPayableFeesMoney(contractRentTypeMoney.add(originalMoney));
                                }
                            }
                        }
                    }else{
                        long allDays = ChronoUnit.DAYS.between(beforeBill.getEndTime(), contract.getEndTime());
                        tBill.setPayableFeesMoney(contract.getMonthRent().divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(allDays)));
                    }
                    tBill.setContractNumber(contract.getContractNumber());
                    tBill.setPayableFeesMoney(contract.getMonthRent());
                    tBill.setPayableFeesTime(LocalDateTime.now());
                    if (beforeBill.getEndTime().plusMonths(contract.getPayType().equals("1")? 1:contract.getPayType().equals("2")? 3:12).getDayOfMonth()<=15){
                        tBill.setPayableFeesTime(contract.getEndTime().withHour(0).withMinute(0).withSecond(0));
                    }else{
                        tBill.setPayableFeesTime((contract.getPayType().equals("1")?
                                beforeBill.getEndTime().plusMonths(1).withDayOfMonth(15):contract.getPayType().equals("2")?
                                beforeBill.getEndTime().plusMonths(3).withDayOfMonth(15):beforeBill.getEndTime().withDayOfMonth(15).plusMonths(12).withHour(0).withMinute(0).withSecond(0)));
                    }
                    tBill.setPayFeesStatus("1");
                    tBill.setBillType("1");
                    tBill.setStartTime(beforeBill.getEndTime().plusMonths(1).with(TemporalAdjusters.firstDayOfMonth()));
                    tBill.setEndTime(contract.getEndTime());
                    tBill.setStartTime(beforeBill.getEndTime().plusDays(1));
                    tBill.setEndTime(beforeBill.getEndTime().plusMonths(contract.getPayType().equals("1")? 1:contract.getPayType().equals("2")? 3:12));
                    bills.add(tBill);
                }
            }
@@ -131,28 +367,192 @@
    @Scheduled(cron = "0 0 0 15 * ?")
    public void monthOfBill() {
        try {
            // 查询所有已签订的合同 且合同时间大于15号
            // 查询所有已签订的合同
            List<TContract> list = contractService.lambdaQuery().eq(TContract::getStatus, 4)
                    .isNotNull(TContract::getFirstPayTime)
                    .ge(TContract::getEndTime, LocalDateTime.now())
                    .list();
            List<TContractRentType> contractRentTypes = contractRentTypeService.list();
            List<TBill> bills = new ArrayList<>();
            for (TContract contract : list) {
                TBill beforeBill = billService.lambdaQuery().eq(TBill::getContractId, contract.getId()).eq(TBill::getBillType, 1).orderByDesc(TBill::getCreateTime)
                        .last("limit 1").one();
                if (beforeBill.getEndTime().toLocalDate().equals(contract.getEndTime().toLocalDate()))continue;
                if (beforeBill.getEndTime().plusMonths(1).with(TemporalAdjusters.lastDayOfMonth()).isBefore(contract.getEndTime())){
                if (beforeBill.getEndTime().plusMonths(contract.getPayType().equals("1")? 1:contract.getPayType().equals("2")? 3:12).with(TemporalAdjusters.lastDayOfMonth()).isBefore(contract.getEndTime())){
                    TBill tBill = new TBill();
                    tBill.setContractId(contract.getId());
                    tBill.setContractNumber(contract.getContractNumber());
                    tBill.setPayableFeesMoney(contract.getMonthRent());
                    tBill.setPayableFeesTime(LocalDateTime.now());
                    // 根据支付方式判断需不需要生成订单
                    if (!(beforeBill.getEndTime().toLocalDate().equals(contract.getEndTime().toLocalDate()))
                            &&
                            (contract.getPayType().equals("1")?
                                    beforeBill.getEndTime().plusMonths(1):contract.getPayType().equals("2")?
                                    beforeBill.getEndTime().plusMonths(3):beforeBill.getEndTime().plusMonths(12))
                                    .with(TemporalAdjusters.lastDayOfMonth()).isBefore(contract.getEndTime())
                            && beforeBill.getEndTime().isBefore(contract.getEndTime())
                    ){
                        tBill.setContractId(contract.getId());
                        long days = ChronoUnit.DAYS.between(beforeBill.getEndTime(), (contract.getPayType().equals("1")?
                                beforeBill.getEndTime().plusMonths(1):contract.getPayType().equals("2")?
                                beforeBill.getEndTime().plusMonths(3):beforeBill.getEndTime().plusMonths(12)).with(TemporalAdjusters.lastDayOfMonth()))+1L;
                        if (contract.getIsIncreasing()){
                            TContractRentType tContractRentType = contractRentTypes.stream().filter(e -> e.getContractId().equals(contract.getId())).findFirst().orElse(null);
                            if (tContractRentType!=null
                                    && beforeBill.getEndTime().isBefore(tContractRentType.getChangeTime())
                                    && beforeBill.getEndTime().plusMonths(contract.getPayType().equals("1")? 1:contract.getPayType().equals("2")? 3:12).with(TemporalAdjusters.lastDayOfMonth()).isAfter(tContractRentType.getChangeTime())){
                                // 如果没变过
                                if (contract.getChangeTime()==null){
                                    contract.setChangeTime(LocalDateTime.now());
                                    // 租金递增递减的时长 天
                                    long moneyDays = ChronoUnit.DAYS.between(tContractRentType.getChangeTime(), contract.getEndTime());
                                    // 递增递减的租金
                                    BigDecimal contractRentTypeMoney = new BigDecimal("0");
                                    // 不递增递减的租金
                                    BigDecimal originalMoney = new BigDecimal("0");
                                    // 原租金
                                    switch (tContractRentType.getIncreasingDecreasingType()){
                                        case 1:
                                            switch (tContractRentType.getIncreasingDecreasing()){
                                                case 1:
                                                    contractRentTypeMoney =contractRentTypeMoney.add(contract.getChangeRent().multiply(new BigDecimal(100).add(tContractRentType.getNumericalValue()).divide(new BigDecimal(100),2,BigDecimal.ROUND_DOWN)).divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(days)));
                                                    contract.setChangeRent(contractRentTypeMoney.add(contract.getChangeRent().multiply(new BigDecimal(100).add(tContractRentType.getNumericalValue()).divide(new BigDecimal(100),2,BigDecimal.ROUND_DOWN))));
                                                    break;
                                                case 2:
                                                    contractRentTypeMoney = contractRentTypeMoney.add(contract.getChangeRent().multiply(new BigDecimal(100).subtract(tContractRentType.getNumericalValue()).divide(new BigDecimal(100),2,BigDecimal.ROUND_DOWN)).divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(days)));
                                                    contract.setChangeRent(contractRentTypeMoney.add(contract.getChangeRent().multiply(new BigDecimal(100).subtract(tContractRentType.getNumericalValue()).divide(new BigDecimal(100),2,BigDecimal.ROUND_DOWN))));
                                                    break;
                                            }
                                            break;
                                        case 2:
                                            switch (tContractRentType.getIncreasingDecreasing()){
                                                case 1:
                                                    contractRentTypeMoney =contractRentTypeMoney.add(contract.getChangeRent().add(tContractRentType.getNumericalValue())).divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(moneyDays));
                                                    contract.setChangeRent(contractRentTypeMoney.add(contract.getChangeRent().add(tContractRentType.getNumericalValue())));
                                                    break;
                                                case 2:
                                                    contractRentTypeMoney = contractRentTypeMoney.add(contract.getChangeRent().subtract(tContractRentType.getNumericalValue())).divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(moneyDays));
                                                    contract.setChangeRent(contractRentTypeMoney.add(contract.getChangeRent().subtract(tContractRentType.getNumericalValue())));
                                                    break;
                                            }
                                            break;
                                    }
                                    // 不需要涨租金的时间段
                                    long originalDays = ChronoUnit.DAYS.between(beforeBill.getEndTime(), tContractRentType.getChangeTime());
                                    originalMoney=originalMoney.add(contract.getMonthRent().divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN))
                                            .multiply(new BigDecimal(originalDays));
                                    tBill.setPayableFeesMoney(contractRentTypeMoney.add(originalMoney));
                                }else{
                                    // 之前已经涨、跌过租金了 需要判断周期是否还需要再涨、跌
                                    if ((LocalDateTime.now().getYear() - contract.getChangeTime().getYear())%tContractRentType.getCycleTime()==0){
                                        contract.setChangeTime(LocalDateTime.now());
                                        // 租金递增递减的时长 天
                                        long moneyDays = ChronoUnit.DAYS.between(tContractRentType.getChangeTime(), contract.getEndTime());
                                        // 递增递减的租金
                                        BigDecimal contractRentTypeMoney = new BigDecimal("0");
                                        // 不递增递减的租金
                                        BigDecimal originalMoney = new BigDecimal("0");
                                        // 原租金
                                        switch (tContractRentType.getIncreasingDecreasingType()){
                                            case 1:
                                                switch (tContractRentType.getIncreasingDecreasing()){
                                                    case 1:
                                                        contractRentTypeMoney =contractRentTypeMoney.add(contract.getChangeRent().multiply(new BigDecimal(100).add(tContractRentType.getNumericalValue()).divide(new BigDecimal(100),2,BigDecimal.ROUND_DOWN)).divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(days)));
                                                        contract.setChangeRent(contractRentTypeMoney.add(contract.getChangeRent().multiply(new BigDecimal(100).add(tContractRentType.getNumericalValue()).divide(new BigDecimal(100),2,BigDecimal.ROUND_DOWN))));
                                                        break;
                                                    case 2:
                                                        contractRentTypeMoney = contractRentTypeMoney.add(contract.getChangeRent().multiply(new BigDecimal(100).subtract(tContractRentType.getNumericalValue()).divide(new BigDecimal(100),2,BigDecimal.ROUND_DOWN)).divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(days)));
                                                        contract.setChangeRent(contractRentTypeMoney.add(contract.getChangeRent().multiply(new BigDecimal(100).subtract(tContractRentType.getNumericalValue()).divide(new BigDecimal(100),2,BigDecimal.ROUND_DOWN))));
                                                        break;
                                                }
                                                break;
                                            case 2:
                                                switch (tContractRentType.getIncreasingDecreasing()){
                                                    case 1:
                                                        contractRentTypeMoney =contractRentTypeMoney.add(contract.getChangeRent().add(tContractRentType.getNumericalValue())).divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(moneyDays));
                                                        contract.setChangeRent(contractRentTypeMoney.add(contract.getChangeRent().add(tContractRentType.getNumericalValue())));
                                                        break;
                                                    case 2:
                                                        contractRentTypeMoney = contractRentTypeMoney.add(contract.getChangeRent().subtract(tContractRentType.getNumericalValue())).divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(moneyDays));
                                                        contract.setChangeRent(contractRentTypeMoney.add(contract.getChangeRent().subtract(tContractRentType.getNumericalValue())));
                                                        break;
                                                }
                                                break;
                                        }
                                        // 不需要涨租金的时间段
                                        long originalDays = ChronoUnit.DAYS.between(beforeBill.getEndTime(), tContractRentType.getChangeTime());
                                        originalMoney=originalMoney.add(contract.getMonthRent().divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN))
                                                .multiply(new BigDecimal(originalDays));
                                        tBill.setPayableFeesMoney(contractRentTypeMoney.add(originalMoney));
                                    }else{
                                        // 不涨租金 用上次的
                                        // 租金递增递减的时长 天
                                        long moneyDays = ChronoUnit.DAYS.between(tContractRentType.getChangeTime(), contract.getEndTime());
                                        // 递增递减的租金
                                        BigDecimal contractRentTypeMoney = new BigDecimal("0");
                                        // 不递增递减的租金
                                        BigDecimal originalMoney = new BigDecimal("0");
                                        // 原租金
                                        switch (tContractRentType.getIncreasingDecreasingType()){
                                            case 1:
                                                switch (tContractRentType.getIncreasingDecreasing()){
                                                    case 1:
                                                        contractRentTypeMoney =contractRentTypeMoney.add(contract.getChangeRent().divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(days))) ;
                                                        break;
                                                    case 2:
                                                        contractRentTypeMoney = contractRentTypeMoney.add(contract.getChangeRent().divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(days)));
                                                        break;
                                                }
                                                break;
                                            case 2:
                                                switch (tContractRentType.getIncreasingDecreasing()){
                                                    case 1:
                                                        contractRentTypeMoney =contractRentTypeMoney.add(contract.getChangeRent()).divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(moneyDays));
                                                        break;
                                                    case 2:
                                                        contractRentTypeMoney = contractRentTypeMoney.add(contract.getChangeRent()).divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(moneyDays));
                                                        break;
                                                }
                                                break;
                                        }
                                        // 不需要涨租金的时间段
                                        long originalDays = ChronoUnit.DAYS.between(beforeBill.getEndTime(), tContractRentType.getChangeTime());
                                        originalMoney=originalMoney.add(contract.getMonthRent().divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN))
                                                .multiply(new BigDecimal(originalDays));
                                        tBill.setPayableFeesMoney(contractRentTypeMoney.add(originalMoney));
                                    }
                                }
                            }
                        }else{
                            long allDays = ChronoUnit.DAYS.between(beforeBill.getEndTime(), (contract.getPayType().equals("1")?
                                    beforeBill.getEndTime().plusMonths(1):contract.getPayType().equals("2")?
                                    beforeBill.getEndTime().plusMonths(3):beforeBill.getEndTime().plusMonths(12)).with(TemporalAdjusters.lastDayOfMonth()));
                            tBill.setPayableFeesMoney(contract.getMonthRent().divide(new BigDecimal(30), 2, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(allDays)));
                        }
                        tBill.setContractNumber(contract.getContractNumber());
                        if (beforeBill.getEndTime().plusMonths(contract.getPayType().equals("1")? 1:contract.getPayType().equals("2")? 3:12).getDayOfMonth()<=15){
                            tBill.setPayableFeesTime(contract.getEndTime());
                        }else{
                            tBill.setPayableFeesTime((contract.getPayType().equals("1")?
                                    beforeBill.getEndTime().plusMonths(1).withDayOfMonth(15):contract.getPayType().equals("2")?
                                    beforeBill.getEndTime().plusMonths(3).withDayOfMonth(15):beforeBill.getEndTime().withDayOfMonth(15).plusMonths(12)));
                        }
                        tBill.setPayFeesStatus("1");
                        tBill.setBillType("1");
                        tBill.setStartTime(beforeBill.getEndTime().plusDays(1));
                        tBill.setEndTime(contract.getEndTime());
                        bills.add(tBill);
                    }
                    tBill.setPayableFeesMoney(contract.getMonthRent().multiply(new BigDecimal("3")));
                    tBill.setPayableFeesTime(LocalDateTime.now().withHour(0).withMinute(0).withSecond(0));
                    tBill.setPayFeesStatus("1");
                    tBill.setBillType("1");
                    tBill.setStartTime(beforeBill.getEndTime().plusMonths(1).with(TemporalAdjusters.firstDayOfMonth()));
                    tBill.setEndTime(beforeBill.getEndTime().plusMonths(1).with(TemporalAdjusters.lastDayOfMonth()));
                    bills.add(tBill);
                }
            }
            billService.saveBatch(bills);
@@ -163,17 +563,18 @@
    public static void main(String[] args) {
        LocalDateTime now = LocalDateTime.now().minusMonths(1).withDayOfMonth(31);
        System.err.println(now);
        LocalDateTime now2 = now.plusMonths(1);
        System.err.println(now2);
        LocalDateTime now1 = LocalDateTime.now();
        long days = ChronoUnit.DAYS.between(now, now1);
        long days2 = ChronoUnit.DAYS.between(now.plusDays(1), now1);
        System.err.println(days);
        System.err.println(days2);
//        LocalDateTime now = LocalDateTime.now().minusMonths(1).withDayOfMonth(31);
//        System.err.println(now);
//        LocalDateTime now2 = now.plusMonths(1);
//        System.err.println(now2);
//
//        LocalDateTime now1 = LocalDateTime.now();
//        long days = ChronoUnit.DAYS.between(now, now1);
//        long days2 = ChronoUnit.DAYS.between(now.plusDays(1), now1);
//
//        System.err.println(days);
//        System.err.println(days2);
//        LocalDateTime endTime = now.with(TemporalAdjusters.lastDayOfMonth()).withSecond(59).withHour(23).withMinute(59);
//
//        System.err.println(endTime);
ruoyi-admin/src/main/resources/application-test.yml
@@ -21,7 +21,7 @@
  port: 8081
  servlet:
    # 应用的访问路径
    context-path: /admin
    context-path: /
  tomcat:
    # tomcat的URI编码
    uri-encoding: UTF-8
ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/PayController.java
@@ -12,6 +12,7 @@
import com.ruoyi.system.service.TBillConfirmService;
import com.ruoyi.system.service.TBillService;
import com.ruoyi.system.service.TPayOrderService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
@@ -27,6 +28,7 @@
import java.util.Collections;
import java.util.List;
@Api(value = "支付订单")
@RestController
@RequestMapping("/t-pay")
public class PayController {
ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/TBillController.java
@@ -8,14 +8,12 @@
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.dto.TBillDto;
import com.ruoyi.system.dto.TInvoiceDTO;
import com.ruoyi.system.model.*;
import com.ruoyi.system.query.TBillQuery;
import com.ruoyi.system.service.TBillDetailService;
import com.ruoyi.system.service.TBillService;
import com.ruoyi.system.service.TInvoiceService;
import com.ruoyi.system.service.TInvoiceToBillService;
import com.ruoyi.system.service.*;
import com.ruoyi.system.vo.TBillVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@@ -44,9 +42,15 @@
    @Autowired
    TBillDetailService billDetailService;
    @Autowired
    TContractService contractService;
    @Autowired
    THouseService houseService;
    @Autowired
    TInvoiceService invoiceService;
    @Autowired
    TInvoiceToBillService invoiceToBillService;
    @Autowired
    TokenService tokenService;
    @ApiOperation(value = "缴费账单查询分页列表")
    @PostMapping("list")
@@ -56,6 +60,16 @@
        }
        PageInfo<TBillDto> pageInfo = tBillService.queryPage(query);
        return R.ok(pageInfo);
    }
    @ApiOperation(value = "缴费账单查询列表")
    @PostMapping("/getBillIds")
    public R<List<String>> getBillIds(@RequestBody TBillQuery query){
        if (StringUtils.isEmpty(query.getUserId())){
            throw new ServiceException("用户ID不能为空");
        }
        List<String> billIds = tBillService.getBillIds(query);
        return R.ok(billIds);
    }
    @ApiOperation(value = "查看缴费账单详情")
@@ -70,6 +84,13 @@
                    .eq(TBillDetail::getBillId, id));
            billVO.setBillDetailList(list);
        }
        // 查询合同信息
        contractService.lambdaQuery().eq(TContract::getId, bill.getContractId()).oneOpt().ifPresent(contract -> {
            // 查询房屋信息
            billVO.setHouse(houseService.getById(contract.getHouseId()));
            billVO.setMonthRent(contract.getMonthRent());
            billVO.setPayType(contract.getPayType());
        });
        billVO.setBillType(DictUtils.getDictLabel(DictConstants.DICT_TYPE_BILL_TYPE,billVO.getBillType()));
        billVO.setPayFeesStatus(DictUtils.getDictLabel(DictConstants.DICT_TYPE_PAY_FEES_STATUS,billVO.getPayFeesStatus()));
        return R.ok(billVO);
@@ -94,7 +115,16 @@
        return R.ok();
    }
    @ApiOperation(value = "缴费账单开票列表")
    @PostMapping(value = "/invoiceList")
    public R<PageInfo<TBillDto>> invoiceList(@RequestBody TBillQuery query) {
//        Long userId = tokenService.getLoginUser().getUserId();
        String userId = "1881967035070177281";
        query.setUserId(userId);
        PageInfo<TBillDto> pageInfo = tBillService.invoiceList(query);
        return R.ok(pageInfo);
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/dto/SetContractDto.java
New file
@@ -0,0 +1,13 @@
package com.ruoyi.system.dto;
import com.ruoyi.system.model.TBill;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import java.util.List;
@Data
@ApiModel(value = "批量导出合同附件")
public class SetContractDto  {
    private List<String> ids;
}
ruoyi-system/src/main/java/com/ruoyi/system/dto/TContractDTO.java
@@ -26,4 +26,6 @@
    @ApiModelProperty(value = "递增或递减时点")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime changeTime;
    @ApiModelProperty(value = "周期 单位年")
    private Integer cycleTime;
}
ruoyi-system/src/main/java/com/ruoyi/system/mapper/TBillMapper.java
@@ -5,8 +5,11 @@
import com.ruoyi.system.dto.TBillDto;
import com.ruoyi.system.model.TBill;
import com.ruoyi.system.query.TBillQuery;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
 * <p>
@@ -16,8 +19,18 @@
 * @author xiaochen
 * @since 2025-01-17
 */
@Mapper
public interface TBillMapper extends BaseMapper<TBill> {
    PageInfo<TBillDto> page(@Param("pageInfo") PageInfo<TBill> pageInfo, @Param("query") TBillQuery query);
    List<TBillDto> getBillList(@Param("query")TBillQuery query);
    /**
     * 获取开票列表
     * @param query
     * @param pageInfo
     * @return
     */
    List<TBillDto> invoiceList(@Param("query")TBillQuery query, @Param("pageInfo")PageInfo<TBillDto> pageInfo);
}
ruoyi-system/src/main/java/com/ruoyi/system/model/TContract.java
@@ -64,6 +64,9 @@
    @ApiModelProperty(value = "押金")
    @TableField("deposit")
    private BigDecimal deposit;
    @ApiModelProperty(value = "变动后递增或递减之后的每月租金 前端忽略")
    @TableField("change_rent")
    private BigDecimal changeRent;
    @ApiModelProperty(value = "租金支付方式 月付 季付 年付")
    @TableField("pay_type")
@@ -73,6 +76,10 @@
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @TableField("first_pay_time")
    private LocalDateTime firstPayTime;
    @ApiModelProperty(value = "变动时间 根据周期改变 前端忽略")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @TableField("change_time")
    private LocalDateTime changeTime;
    @ApiModelProperty(value = "是否递增递减 true=是 false=否")
    @TableField("isIncreasing")
@@ -80,7 +87,7 @@
    @ApiModelProperty(value = "押金是否随租金递增递减 true=是 false=否")
    @TableField("isIncreasing_deposit")
    private Boolean isincreasingDeposit;
    private Boolean isIncreasingDeposit;
    @ApiModelProperty(value = "违约金比例")
    @TableField("proportion")
ruoyi-system/src/main/java/com/ruoyi/system/model/TContractRentType.java
@@ -48,6 +48,9 @@
    @ApiModelProperty(value = "数值")
    @TableField("numerical_value")
    private BigDecimal numericalValue;
    @ApiModelProperty(value = "周期 单位年")
    @TableField("cycle_time")
    private Integer cycleTime;
    @ApiModelProperty(value = "递增或递减时点")
    @TableField("change_time")
ruoyi-system/src/main/java/com/ruoyi/system/query/TContractQuery.java
@@ -5,6 +5,8 @@
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
@Data
@ApiModel(value = "合同分页列表查询Query")
public class TContractQuery extends BasePage {
@@ -16,4 +18,6 @@
    private Integer contractName;
    @ApiModelProperty(value = "合同状态 1=待提交 2=待审批 3=未签订 4=已签订")
    private Integer status;
    @ApiModelProperty(value = "选中的行")
    private List<String> ids;
}
ruoyi-system/src/main/java/com/ruoyi/system/service/TBillService.java
@@ -14,6 +14,8 @@
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.List;
/**
 * <p>
 * 租金账单 服务类
@@ -53,4 +55,18 @@
    boolean checkOfflinePay(OfflinePayCheckDto dto);
    void completePay(ChargeBillRequest billRequest);
    /**
     * 查询账单id列表
     * @param query
     * @return
     */
    List<String> getBillIds(TBillQuery query);
    /**
     * 查询开票列表
     * @param query
     * @return
     */
    PageInfo<TBillDto> invoiceList(TBillQuery query);
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TBillServiceImpl.java
@@ -3,6 +3,8 @@
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.basic.PageInfo;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.constant.AmountConstant;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.core.redis.RedisCache;
@@ -25,6 +27,9 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.Collections;
@@ -77,6 +82,19 @@
        return info;
    }
    @Override
    public List<String> getBillIds(TBillQuery query) {
        List<TBillDto> billDtos = tBillMapper.getBillList(query);
        return billDtos.stream().map(TBillDto::getId).collect(Collectors.toList());
    }
    @Override
    public PageInfo<TBillDto> invoiceList(TBillQuery query) {
        PageInfo<TBillDto> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize());
        List<TBillDto> list = tBillMapper.invoiceList(query,pageInfo);
        pageInfo.setRecords(list);
        return pageInfo;
    }
    private static final String[] ignorePro = {"payableFeesMoney","payableFeesPenalty","payFeesMoney","outstandingMoney"};
ruoyi-system/src/main/java/com/ruoyi/system/vo/TBillVO.java
@@ -1,11 +1,14 @@
package com.ruoyi.system.vo;
import com.baomidou.mybatisplus.annotation.TableField;
import com.ruoyi.system.model.TBill;
import com.ruoyi.system.model.TBillDetail;
import com.ruoyi.system.model.THouse;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
@Data
@@ -15,4 +18,12 @@
    @ApiModelProperty(value = "水电费明细")
    private List<TBillDetail> billDetailList;
    @ApiModelProperty(value = "房屋信息")
    private THouse house;
    @ApiModelProperty(value = "租金")
    private BigDecimal monthRent;
    @ApiModelProperty(value = "租金支付方式 月付 季付 年付")
    private String payType;
}
ruoyi-system/src/main/java/com/ruoyi/system/vo/TContractVO.java
@@ -34,4 +34,6 @@
    private BigDecimal payMoney;
    @ApiModelProperty(value = "房屋验收结果")
    private Boolean checkResult;
    @ApiModelProperty(value = "周期 单位年")
    private Integer cycleTime;
}
ruoyi-system/src/main/resources/mapper/system/TBillMapper.xml
@@ -64,4 +64,68 @@
            </if>
        </where>
    </select>
    <select id="getBillList" resultType="com.ruoyi.system.dto.TBillDto">
        SELECT
        b.*,
        t.resident_name as residentName,
        t.phone,
        t.account,
        h.house_name as houseName
        FROM
        t_bill b
        LEFT JOIN t_contract c ON c.contract_number = b.contract_number and c.disabled=0
        LEFT JOIN t_house h ON h.id = c.house_id and h.disabled=0
        LEFT JOIN t_tenant t ON t.id = c.tenant_id and t.disabled=0
        <where>
            <if test="query.payFeesStatus != null">
                and b.pay_fees_status = #{query.payFeesStatus}
            </if>
            <if test="query.phone != null and query.phone !=''">
                and t.phone = #{query.phone}
            </if>
            <if test="query.residentName != null and query.residentName !=''">
                and t.resident_name like concat('%',#{query.residentName},'%')
            </if>
            <if test="query.contractNumber != null and query.contractNumber !=''">
                and b.contract_number = #{query.contractNumber}
            </if>
            <if test="query.userId != null and query.userId !=''">
                and t.id = #{query.userId}
            </if>
            and b.disabled = ${@com.ruoyi.common.enums.DisabledEnum@NO.getCode()}
        </where>
        order by b.payable_fees_time
    </select>
    <select id="invoiceList" resultType="com.ruoyi.system.dto.TBillDto">
        SELECT
        b.*,
        t.resident_name as residentName,
        t.phone,
        t.account,
        h.house_name as houseName
        FROM
        t_bill b
        LEFT JOIN t_contract c ON c.contract_number = b.contract_number and c.disabled=0
        LEFT JOIN t_house h ON h.id = c.house_id and h.disabled=0
        LEFT JOIN t_tenant t ON t.id = c.tenant_id and t.disabled=0
        LEFT JOIN t_invoice_to_bill tb ON b.id = tb.bill_id
        <where>
            <if test="query.phone != null and query.phone !=''">
                and t.phone = #{query.phone}
            </if>
            <if test="query.residentName != null and query.residentName !=''">
                and t.resident_name like concat('%',#{query.residentName},'%')
            </if>
            <if test="query.contractNumber != null and query.contractNumber !=''">
                and b.contract_number = #{query.contractNumber}
            </if>
            <if test="query.userId != null and query.userId !=''">
                and t.id = #{query.userId}
            </if>
            and b.pay_fees_status = 3
            and tb.invoice_id IS NULL
            and b.disabled = ${@com.ruoyi.common.enums.DisabledEnum@NO.getCode()}
        </where>
        order by b.pay_fees_time
    </select>
</mapper>
ruoyi-system/src/main/resources/mapper/system/TContractMapper.xml
@@ -14,7 +14,7 @@
        <result column="pay_type" property="payType" />
        <result column="first_pay_time" property="firstPayTime" />
        <result column="isIncreasing" property="isIncreasing" />
        <result column="isIncreasing_deposit" property="isincreasingDeposit" />
        <result column="isIncreasing_deposit" property="isIncreasingDeposit" />
        <result column="proportion" property="proportion" />
        <result column="house_id" property="houseId" />
        <result column="party_one_name" property="partyOneName" />
@@ -88,15 +88,32 @@
        AND t3.disabled = ${@com.ruoyi.common.enums.DisabledEnum@NO.getCode()}
    </select>
    <select id="contractExportList" resultType="com.ruoyi.system.model.TContract">
        select t1.*,t2.contract_number as contractNumber,t3.resident_name as residentName,t3.phone as phone
        from t_bill t1
                 left join t_contract t2 on t1.contract_id = t2.id
                 left join t_resident t3 on t2.tenant_id = t3.id
        where t2.id = #{query.id}
          and (t1.pay_fees_status = 1 or t1.pay_fees_status = 4)
          AND t1.disabled = ${@com.ruoyi.common.enums.DisabledEnum@NO.getCode()}
          AND t2.disabled = ${@com.ruoyi.common.enums.DisabledEnum@NO.getCode()}
          AND t3.disabled = ${@com.ruoyi.common.enums.DisabledEnum@NO.getCode()}
        select t1.* from t_contract t1
        <where>
            <if test="query.ids != null and query.ids.size()>0">
                AND t1.id IN
                <foreach collection="query.ids" item="item" open="(" separator="," close=")">
                    #{item}
                </foreach>
            </if>
            <if test="query.ids == null and query.ids.size()=0">
                <if test="query.partyTwoName != null and query.partyTwoName != ''">
                    and t1.party_two_name like concat('%',#{query.partyTwoName},'%')
                </if>
                <if test="query.contractNumber != null and query.contractNumber != ''">
                    and t1.contract_number like concat('%',#{query.contractNumber},'%')
                </if>
                <if test="query.contractName != null and query.contractName != ''">
                    and t1.contract_name like concat('%',#{query.contractName},'%')
                </if>
                <if test="query.status != null">
                    and t1.status = #{query.status}
                </if>
            </if>
            AND t1.disabled = ${@com.ruoyi.common.enums.DisabledEnum@NO.getCode()}
        </where>
    </select>
</mapper>