ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TBillController.java
@@ -4,9 +4,7 @@ import com.ruoyi.common.basic.PageInfo; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.system.dto.OfflinePayCheckDto; import com.ruoyi.system.dto.TBillDto; import com.ruoyi.system.dto.TbillSaveDto; import com.ruoyi.system.dto.*; import com.ruoyi.system.model.TBill; import com.ruoyi.system.query.TBillQuery; import com.ruoyi.system.service.TBillService; @@ -60,6 +58,30 @@ return R.ok(); } @PreAuthorize("@ss.hasPermi('system:bill:sendSmsByBillIds')") @ApiOperation("账单批量发送短信通知") @PostMapping("sendSmsByBillIds") public R sendSmsByBillIds(@Validated @RequestBody SmsByBillDto dto){ Integer failNum = tBillService.sendSmsByBillIds(dto); return R.ok(failNum); } @PreAuthorize("@ss.hasPermi('system:bill:sendMailBatchByBillIds')") @ApiOperation("账单批量发送短信通知") @PostMapping("sendMailBatchByBillIds") public R sendMailBatchByBillIds(@Validated @RequestBody SmsByBillDto dto){ Integer failNum = tBillService.sendMailBatchByBillIds(dto); return R.ok(failNum); } @PreAuthorize("@ss.hasPermi('system:bill:cashPay')") @ApiOperation("收款") @PostMapping("cashPay") public R cashPay(@RequestBody OfflinePayDto offlinePayDto){ return null; } } ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TContractController.java
@@ -89,7 +89,7 @@ TBill rentBill = new TBill(); rentBill.setContractId(contract.getId()); rentBill.setContractNumber(contract.getContractNumber()); rentBill.setPayableFeesTime(firstPayTime); rentBill.setPayableFeesTime(firstPayTime.toLocalDate()); rentBill.setPayFeesStatus("1"); rentBill.setBillType("1"); rentBill.setStartTime(contract.getStartPayTime()); @@ -169,7 +169,7 @@ depositBill.setPayableFeesMoney(contract.getDeposit()); depositBill.setOutstandingMoney(depositBill.getPayableFeesMoney()); depositBill.setPayableFeesTime(firstPayTime); depositBill.setPayableFeesTime(firstPayTime.toLocalDate()); depositBill.setPayFeesStatus("1"); depositBill.setBillType("2"); contractService.updateById(contract); ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/TaskUtil.java
@@ -45,7 +45,7 @@ List<TBill> list = billService.lambdaQuery().eq(TBill::getPayFeesStatus, 1).list(); for (TBill tBill : list) { TContract contract = contractService.getById(tBill.getContractId()); LocalDateTime payableFeesTime = tBill.getPayableFeesTime(); LocalDate payableFeesTime = tBill.getPayableFeesTime(); LocalDateTime now = LocalDateTime.now(); // 计算两个时间相差多少个小时 long hours = ChronoUnit.HOURS.between(payableFeesTime, now); @@ -75,7 +75,7 @@ try { List<TBill> list = billService.lambdaQuery().eq(TBill::getPayFeesStatus, "2").list(); for (TBill tBill : list) { if (tBill.getPayableFeesTime().toLocalDate().equals(LocalDate.now())){ if (tBill.getPayableFeesTime().equals(LocalDate.now())){ tBill.setPayFeesStatus("1"); } } ruoyi-common/pom.xml
@@ -181,6 +181,11 @@ <artifactId>jave-all-deps</artifactId> <version>2.5.1</version> </dependency> <dependency> <groupId>com.tencentcloudapi</groupId> <artifactId>tencentcloud-sdk-java</artifactId> <version>4.0.11</version> </dependency> </dependencies> ruoyi-common/src/main/java/com/ruoyi/common/config/SmsConfig.java
New file @@ -0,0 +1,38 @@ package com.ruoyi.common.config; import com.tencentcloudapi.common.Credential; import com.tencentcloudapi.common.profile.ClientProfile; import com.tencentcloudapi.common.profile.HttpProfile; import com.tencentcloudapi.sms.v20190711.SmsClient; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration @EnableConfigurationProperties(SmsProperties.class) @ConditionalOnProperty(value = SmsProperties.ENABLE_KEY,matchIfMissing = true) public class SmsConfig { @Bean public SmsClient smsClient(SmsProperties properties) { // 实例化一个认证对象,入参需要传入腾讯云账户 SecretId,SecretKey。 // 为了保护密钥安全,建议将密钥设置在环境变量中或者配置文件中,请参考凭证管理 https://github.com/TencentCloud/tencentcloud-sdk-java?tab=readme-ov-file#%E5%87%AD%E8%AF%81%E7%AE%A1%E7%90%86。 // 硬编码密钥到代码中有可能随代码泄露而暴露,有安全隐患,并不推荐。 // SecretId、SecretKey 查询: https://console.cloud.tencent.com/cam/capi // Credential cred = new Credential("SecretId", "SecretKey"); Credential cred = new Credential(properties.getSecretid(), properties.getSecretkey()); // 实例化一个http选项,可选的,没有特殊需求可以跳过 HttpProfile httpProfile = new HttpProfile(); // 指定接入地域域名,默认就近地域接入域名为 sms.tencentcloudapi.com ,也支持指定地域域名访问,例如广州地域的域名为 sms.ap-guangzhou.tencentcloudapi.com httpProfile.setEndpoint("sms.tencentcloudapi.com"); // 实例化一个客户端配置对象 ClientProfile clientProfile = new ClientProfile(); clientProfile.setHttpProfile(httpProfile); // 实例化要请求产品(sms)的client对象,第二个参数是地域信息,可以直接填写字符串ap-guangzhou,支持的地域列表参考 https://cloud.tencent.com/document/api/382/52071#.E5.9C.B0.E5.9F.9F.E5.88.97.E8.A1.A8 return new SmsClient(cred, "ap-guangzhou", clientProfile); } } ruoyi-common/src/main/java/com/ruoyi/common/config/SmsProperties.java
New file @@ -0,0 +1,36 @@ package com.ruoyi.common.config; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; @Data @ConfigurationProperties(prefix = "sms") public class SmsProperties { public static final String ENABLE_KEY = "sms.enable"; private Boolean enable; private String appId; private String secretid; private String secretkey; /** * 短信签名 */ private String sign; /** * 账单提醒 ,同一个用户离上次发送短信的最小间隔 * 单位分钟 */ private Integer billSmsDelayPeriod = 60; /** * 账单提醒 ,同一个用户离上次发送邮件的最小间隔 * 单位分钟 */ private Integer billMailDelayPeriod = 60; } ruoyi-common/src/main/java/com/ruoyi/common/utils/SmsUtil.java
New file @@ -0,0 +1,53 @@ package com.ruoyi.common.utils; import com.ruoyi.common.config.SmsProperties; import com.ruoyi.common.exception.ServiceException; import com.tencentcloudapi.common.exception.TencentCloudSDKException; import com.tencentcloudapi.sms.v20190711.SmsClient; import com.tencentcloudapi.sms.v20190711.models.SendSmsRequest; import com.tencentcloudapi.sms.v20190711.models.SendSmsResponse; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.Arrays; import java.util.List; @Component @Slf4j public class SmsUtil { @Resource SmsProperties smsProperties; @Resource SmsClient smsClient; public SmsProperties getPro(){ return smsProperties; } public boolean sendSms(String phone,String templateId,String[] param){ SendSmsRequest req = new SendSmsRequest(); req.setSmsSdkAppid(smsProperties.getAppId()); req.setPhoneNumberSet(new String[]{phone}); req.setTemplateID(templateId); req.setSign(smsProperties.getSign()); req.setTemplateParamSet(param); req.setSenderId(""); req.setSessionContext(""); req.setExtendCode(""); try { smsClient.SendSms(req); return true; } catch (TencentCloudSDKException e) { log.error("发送短信失败,{},{}",phone,param,e); throw new ServiceException("发送短信失败"); } catch (Exception e){ log.error("发送短信失败1,{},{}",phone,param,e); throw new ServiceException("发送短信失败1"); } } } ruoyi-system/src/main/java/com/ruoyi/system/dto/SmsByBillDto.java
New file @@ -0,0 +1,17 @@ package com.ruoyi.system.dto; import lombok.Data; import javax.validation.constraints.NotEmpty; import java.io.Serializable; import java.util.List; @Data public class SmsByBillDto implements Serializable { @NotEmpty(message = "账单ID不能为空") private List<String> billIds; private String sendUserId; } ruoyi-system/src/main/java/com/ruoyi/system/dto/TBillDto.java
@@ -12,6 +12,8 @@ private String phone; private String email; private String account; private String houseName; ruoyi-system/src/main/java/com/ruoyi/system/dto/TbillSaveDto.java
@@ -11,7 +11,10 @@ @Data public class TbillSaveDto extends TBill implements Serializable { @ApiModelProperty(value = "水单费列表") @ApiModelProperty(value = "水电费列表") private List<TBillDetail> details; } ruoyi-system/src/main/java/com/ruoyi/system/mapper/TBillMapper.java
@@ -33,4 +33,6 @@ * @return */ List<TBillDto> invoiceList(@Param("query")TBillQuery query, @Param("pageInfo")PageInfo<TBillDto> pageInfo); TBillDto selectTenentByBillId(@Param("billId") String billId); } ruoyi-system/src/main/java/com/ruoyi/system/model/TBill.java
@@ -5,9 +5,11 @@ import com.baomidou.mybatisplus.annotation.TableId; import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalDateTime; import com.baomidou.mybatisplus.annotation.TableField; import java.io.Serializable; import java.util.Date; import java.util.List; import com.fasterxml.jackson.annotation.JsonFormat; @@ -54,7 +56,7 @@ @ApiModelProperty(value = "应缴费日期") @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") @TableField("payable_fees_time") private LocalDateTime payableFeesTime; private LocalDate payableFeesTime; @ApiModelProperty(value = "缴费状态 1=未缴费 2=待确认 3=已缴费 4=已逾期 5= 已失效") @TableField("pay_fees_status") @@ -111,6 +113,31 @@ @TableField("confirm_id") private String confirmId; @ApiModelProperty(value = "短信发送状态:0.未发送 1.已发送 2.发送失败") @TableField("sms_status") private Integer smsStatus; @ApiModelProperty(value = "短信最后发送时间") @TableField("sms_last_time") private Date smsLastTime; @ApiModelProperty(value = "最后短信发送人") @TableField("sms_send_userid") private String smsSendUserid; @ApiModelProperty(value = "邮件发送状态:0.未发送 1.已发送 2.发送失败") @TableField("mail_status") private Integer mailStatus; @ApiModelProperty(value = "邮件最后发送时间") @TableField("mail_last_time") private Date mailLastTime; @ApiModelProperty(value = "最后邮件发送人") @TableField("mail_send_userid") private String mailSendUserid; /** * 抵扣金额 */ @@ -122,4 +149,9 @@ @TableField(exist = false) private BigDecimal preOutstand; } ruoyi-system/src/main/java/com/ruoyi/system/service/TBillService.java
@@ -3,6 +3,7 @@ import com.baomidou.mybatisplus.extension.service.IService; import com.ruoyi.common.basic.PageInfo; import com.ruoyi.system.dto.OfflinePayCheckDto; import com.ruoyi.system.dto.SmsByBillDto; import com.ruoyi.system.dto.TBillDto; import com.ruoyi.system.dto.TbillSaveDto; import com.ruoyi.system.model.TBill; @@ -76,4 +77,8 @@ * @return */ PageInfo<TBill> getBillByInvoiceId(String invoiceId); Integer sendSmsByBillIds(SmsByBillDto dto); Integer sendMailBatchByBillIds(SmsByBillDto dto); } ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TBillServiceImpl.java
@@ -7,9 +7,11 @@ import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.SmsUtil; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.uuid.UUID; import com.ruoyi.system.dto.OfflinePayCheckDto; import com.ruoyi.system.dto.SmsByBillDto; import com.ruoyi.system.dto.TBillDto; import com.ruoyi.system.dto.TbillSaveDto; import com.ruoyi.system.mapper.TBillMapper; @@ -18,6 +20,8 @@ import com.ruoyi.system.query.TInvoiceToBillQuery; import com.ruoyi.system.service.*; import com.taxi591.bankapi.dto.ChargeBillRequest; import com.tencentcloudapi.sms.v20190711.SmsClient; import com.tencentcloudapi.sms.v20190711.models.SendSmsRequest; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; import org.springframework.beans.BeanUtils; @@ -25,6 +29,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.util.*; import java.util.stream.Collectors; import java.math.BigDecimal; @@ -70,6 +75,10 @@ @Autowired TInvoiceToBillService tInvoiceToBillService; @Resource SmsUtil smsUtil; public PageInfo<TBillDto> queryPage(TBillQuery query){ PageInfo<TBill> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize()); @@ -345,4 +354,68 @@ } @Override public Integer sendSmsByBillIds(SmsByBillDto dto) { int failNum = 0; for (String billId : dto.getBillIds()) { TBillDto bill = getTenentByBillId(billId); if (bill.getSmsLastTime()!=null && (System.currentTimeMillis()-bill.getSmsLastTime().getTime()<smsUtil.getPro().getBillSmsDelayPeriod()*60*1000L)){ throw new ServiceException("有账单最近一次发送的时间是:"+DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,bill.getSmsLastTime())); } if (StringUtils.isEmpty(bill.getPhone())){ failNum++; continue; } TBill save = new TBill(); save.setId(bill.getId()); try { smsUtil.sendSms(bill.getPhone(), "", new String[]{""}); save.setSmsStatus(1); }catch (ServiceException e){ failNum++; save.setSmsStatus(2); } save.setSmsLastTime(new Date()); save.setSmsSendUserid(dto.getSendUserId()); lockAndUpdateInfo(save,1); } return failNum; } @Override public Integer sendMailBatchByBillIds(SmsByBillDto dto) { int failNum = 0; for (String billId : dto.getBillIds()) { TBillDto bill = getTenentByBillId(billId); if (bill.getSmsLastTime()!=null && (System.currentTimeMillis()-bill.getSmsLastTime().getTime()<smsUtil.getPro().getBillMailDelayPeriod()*60*1000L)){ throw new ServiceException("有账单最近一次发送的时间是:"+DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,bill.getSmsLastTime())); } if (StringUtils.isEmpty(bill.getEmail())){ failNum++; continue; } TBill save = new TBill(); save.setId(bill.getId()); try { //todo 发送邮件 save.setMailStatus(1); }catch (ServiceException e){ failNum++; save.setMailStatus(2); } save.setMailLastTime(new Date()); save.setMailSendUserid(dto.getSendUserId()); lockAndUpdateInfo(save,1); } return failNum; } private TBillDto getTenentByBillId(String billId) { return getBaseMapper().selectTenentByBillId(billId); } } ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TContractServiceImpl.java
@@ -150,7 +150,7 @@ TBill rentBill = new TBill(); rentBill.setContractId(contract.getId()); rentBill.setContractNumber(contract.getContractNumber()); rentBill.setPayableFeesTime(firstPayTime); rentBill.setPayableFeesTime(firstPayTime.toLocalDate()); if (firstPayTime.toLocalDate().equals(LocalDate.now())){ rentBill.setPayFeesStatus("1"); }else { @@ -226,7 +226,7 @@ depositBill.setOutstandingMoney(depositBill.getPayableFeesMoney()); depositBill.setStartTime(contract.getStartPayTime()); depositBill.setEndTime(contract.getEndTime()); depositBill.setPayableFeesTime(firstPayTime); depositBill.setPayableFeesTime(firstPayTime.toLocalDate()); if (firstPayTime.toLocalDate().equals(LocalDate.now())){ depositBill.setPayFeesStatus("1"); @@ -410,11 +410,11 @@ } 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()); tBill.setPayableFeesTime(contract.getEndTime().toLocalDate()); }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))); beforeBill.getEndTime().plusMonths(1).withDayOfMonth(15).toLocalDate():contract.getPayType().equals("2")? beforeBill.getEndTime().plusMonths(3).withDayOfMonth(15).toLocalDate():beforeBill.getEndTime().withDayOfMonth(15).plusMonths(12).toLocalDate())); } tBill.setPayFeesStatus("2"); tBill.setBillType("1"); @@ -597,11 +597,11 @@ } 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().withHour(0).withMinute(0).withSecond(0)); tBill.setPayableFeesTime(contract.getEndTime().withHour(0).withMinute(0).withSecond(0).toLocalDate()); }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))); beforeBill.getEndTime().plusMonths(1).withDayOfMonth(15).toLocalDate():contract.getPayType().equals("2")? beforeBill.getEndTime().plusMonths(3).withDayOfMonth(15).toLocalDate():beforeBill.getEndTime().withDayOfMonth(15).plusMonths(12).withHour(0).withMinute(0).withSecond(0).toLocalDate())); } tBill.setPayFeesStatus("1"); tBill.setBillType("1"); ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TInvoiceServiceImpl.java
@@ -1,23 +1,17 @@ package com.ruoyi.system.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.common.basic.PageInfo; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.system.mapper.TInvoiceMapper; import com.ruoyi.system.model.TBill; import com.ruoyi.system.model.TInvoice; import com.ruoyi.system.model.TInvoiceToBill; import com.ruoyi.system.query.TInvoiceQuery; import com.ruoyi.system.query.TInvoiceToBillQuery; import com.ruoyi.system.service.TBillService; import com.ruoyi.system.service.TInvoiceService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.sun.org.apache.regexp.internal.RE; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.bind.annotation.RequestParam; import java.util.ArrayList; import java.util.List; /** ruoyi-system/src/main/resources/mapper/system/TBillMapper.xml
@@ -63,6 +63,7 @@ and t.id = #{query.userId} </if> </where> order by b.payable_fees_time desc </select> <select id="getBillList" resultType="com.ruoyi.system.dto.TBillDto"> SELECT @@ -128,4 +129,20 @@ </where> order by b.pay_fees_time </select> <select id="selectTenentByBillId" resultType="com.ruoyi.system.dto.TBillDto"> SELECT b.*, t.resident_name as residentName, t.email, 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 b.id = #{billId} </select> </mapper>