更新代码
This commit is contained in:
@@ -70,6 +70,22 @@ public class BillController {
|
|||||||
return ResultMessage.success(new PageResult());
|
return ResultMessage.success(new PageResult());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/pageQueryUnpaidMargin")
|
||||||
|
@LoginCheck
|
||||||
|
public ResultMessage pageQueryUnpaidMargin(@RequestBody BillQueryCondition condition) {
|
||||||
|
try {
|
||||||
|
UserContext userContext = UserContext.get();
|
||||||
|
if(userContext == null || userContext.getCusNo() == null) {
|
||||||
|
return ResultMessage.success(new PageResult());
|
||||||
|
}
|
||||||
|
condition.setCusNo(userContext.getCusNo());
|
||||||
|
return ResultMessage.success(billService.pageQueryUnpaidMargin(condition));
|
||||||
|
}catch (Exception e) {
|
||||||
|
log.error(e.getMessage(),e);
|
||||||
|
}
|
||||||
|
return ResultMessage.success(new PageResult());
|
||||||
|
}
|
||||||
|
|
||||||
@LoginCheck
|
@LoginCheck
|
||||||
@GetMapping("/countUnpayRentBills")
|
@GetMapping("/countUnpayRentBills")
|
||||||
public ResultMessage countUnpayRentBills() {
|
public ResultMessage countUnpayRentBills() {
|
||||||
@@ -85,6 +101,21 @@ public class BillController {
|
|||||||
return ResultMessage.success(0);
|
return ResultMessage.success(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@LoginCheck
|
||||||
|
@GetMapping("/countUnpaidMargin")
|
||||||
|
public ResultMessage countUnpaidRentMargin() {
|
||||||
|
try {
|
||||||
|
UserContext userContext = UserContext.get();
|
||||||
|
if(userContext == null || userContext.getCusNo() == null) {
|
||||||
|
return ResultMessage.success(0);
|
||||||
|
}
|
||||||
|
return ResultMessage.success(billService.countUnpaidRentMargin(userContext.getCusNo()));
|
||||||
|
}catch (Exception e) {
|
||||||
|
log.error(e.getMessage(),e);
|
||||||
|
}
|
||||||
|
return ResultMessage.success(0);
|
||||||
|
}
|
||||||
|
|
||||||
@LoginCheck
|
@LoginCheck
|
||||||
@GetMapping("/countUnpayWaeBills")
|
@GetMapping("/countUnpayWaeBills")
|
||||||
public ResultMessage countUnpayWaeBills() {
|
public ResultMessage countUnpayWaeBills() {
|
||||||
@@ -115,8 +146,19 @@ public class BillController {
|
|||||||
return ResultMessage.success(orderService.createOrder(orderVo));
|
return ResultMessage.success(orderService.createOrder(orderVo));
|
||||||
}catch (Exception e) {
|
}catch (Exception e) {
|
||||||
log.error(e.getMessage(),e);
|
log.error(e.getMessage(),e);
|
||||||
|
return ResultMessage.error(e.getMessage());
|
||||||
}
|
}
|
||||||
return ResultMessage.success(0);
|
}
|
||||||
|
|
||||||
|
@PostMapping("/paycallback")
|
||||||
|
public ResultMessage payCallBack(@RequestParam("orderId") String orderId,@RequestParam("payResult")String payResult) {
|
||||||
|
try {
|
||||||
|
orderService.tmPayCallback(orderId,payResult);
|
||||||
|
return ResultMessage.success();
|
||||||
|
}catch (Exception e) {
|
||||||
|
log.error(e.getMessage(),e);
|
||||||
|
}
|
||||||
|
return ResultMessage.error();
|
||||||
}
|
}
|
||||||
|
|
||||||
@LoginCheck
|
@LoginCheck
|
||||||
@@ -133,4 +175,5 @@ public class BillController {
|
|||||||
}
|
}
|
||||||
return ResultMessage.success(0);
|
return ResultMessage.success(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ public class BillQueryCondition extends PageQueryRequest {
|
|||||||
private String cusNo; //客商编码
|
private String cusNo; //客商编码
|
||||||
private String year; //年份
|
private String year; //年份
|
||||||
private String billStatus; //账单状态
|
private String billStatus; //账单状态
|
||||||
|
private String startDate; //账单开始日期
|
||||||
|
private String endDate; //账单结束日期
|
||||||
|
|
||||||
public String getCusNo() {
|
public String getCusNo() {
|
||||||
return cusNo;
|
return cusNo;
|
||||||
@@ -31,4 +33,20 @@ public class BillQueryCondition extends PageQueryRequest {
|
|||||||
public void setBillStatus(String billStatus) {
|
public void setBillStatus(String billStatus) {
|
||||||
this.billStatus = billStatus;
|
this.billStatus = billStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getStartDate() {
|
||||||
|
return startDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStartDate(String startDate) {
|
||||||
|
this.startDate = startDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEndDate() {
|
||||||
|
return endDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEndDate(String endDate) {
|
||||||
|
this.endDate = endDate;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
package org.chenyon.bill;
|
package org.chenyon.bill;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.chenyon.oa.OaBillService;
|
import org.chenyon.oa.OaBillService;
|
||||||
import org.chenyon.oa.bill.OaBillVo;
|
import org.chenyon.oa.bill.OaBillVo;
|
||||||
import org.chenyon.oa.bill.OaPayRecordVo;
|
import org.chenyon.oa.bill.OaPayRecordVo;
|
||||||
import org.chenyon.pay.OrderService;
|
import org.chenyon.pay.OrderService;
|
||||||
import org.rcy.framework.api.entity.PageResult;
|
import org.rcy.framework.api.entity.PageResult;
|
||||||
|
import org.rcy.framework.data.id.LongIdGenerator;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.IdGenerator;
|
||||||
|
import org.springframework.util.JdkIdGenerator;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -26,17 +30,37 @@ public class BillService {
|
|||||||
public PageResult<OaBillVo> pageQueryWaeBill(BillQueryCondition condition) throws Exception {
|
public PageResult<OaBillVo> pageQueryWaeBill(BillQueryCondition condition) throws Exception {
|
||||||
return oaBillService.pageQueryWaeBill(condition);
|
return oaBillService.pageQueryWaeBill(condition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PageResult<OaBillVo> pageQueryUnpaidMargin(BillQueryCondition condition) throws Exception {
|
||||||
|
return oaBillService.pageQueryUnpaidMargin(condition);
|
||||||
|
}
|
||||||
|
|
||||||
public PageResult<OaPayRecordVo> pageQueryContractPayRecord(PayRecordQueryConditon condition) throws Exception {
|
public PageResult<OaPayRecordVo> pageQueryContractPayRecord(PayRecordQueryConditon condition) throws Exception {
|
||||||
return oaBillService.pageQueryPayRecord(condition);
|
return oaBillService.pageQueryPayRecord(condition);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer countUnpayRentBills(String cusNo) throws Exception {
|
public Integer countUnpayRentBills(String cusNo) throws Exception {
|
||||||
|
if(StringUtils.isBlank(cusNo)){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Map<String,Object> params = new HashMap<>();
|
Map<String,Object> params = new HashMap<>();
|
||||||
params.put("cusNo",cusNo);
|
params.put("cusNo",cusNo);
|
||||||
return oaBillService.countUnpayRentBills(params);
|
return oaBillService.countUnpayRentBills(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Integer countUnpaidRentMargin(String cusNo) throws Exception {
|
||||||
|
if(StringUtils.isBlank(cusNo)){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
Map<String,Object> params = new HashMap<>();
|
||||||
|
params.put("cusNo",cusNo);
|
||||||
|
return oaBillService.countUnpaidRentMargin(params);
|
||||||
|
}
|
||||||
|
|
||||||
public Integer countUnpayWaeBills(String cusNo) throws Exception {
|
public Integer countUnpayWaeBills(String cusNo) throws Exception {
|
||||||
|
if(StringUtils.isBlank(cusNo)){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Map<String,Object> params = new HashMap<>();
|
Map<String,Object> params = new HashMap<>();
|
||||||
params.put("cusNo",cusNo);
|
params.put("cusNo",cusNo);
|
||||||
return oaBillService.countUnpayWaeBills(params);
|
return oaBillService.countUnpayWaeBills(params);
|
||||||
@@ -48,4 +72,8 @@ public class BillService {
|
|||||||
params.put("bizType",bizType);
|
params.put("bizType",bizType);
|
||||||
return oaBillService.getBillPayReceiver(params);
|
return oaBillService.getBillPayReceiver(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
System.out.println(LongIdGenerator.generate());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,10 @@ public final class OaApiUrl {
|
|||||||
* 分页查询水电费账单
|
* 分页查询水电费账单
|
||||||
*/
|
*/
|
||||||
public static final String PAGE_QUERY_WAE_BILL = "/bill/waeBill/queryPage";
|
public static final String PAGE_QUERY_WAE_BILL = "/bill/waeBill/queryPage";
|
||||||
|
/**
|
||||||
|
* 分页查询保证金账单
|
||||||
|
*/
|
||||||
|
public static final String PAGE_QUERY_UNPAID_MARGIN = "/bill/unpaidMargin/queryPage";
|
||||||
/**
|
/**
|
||||||
* 分页查询缴费记录
|
* 分页查询缴费记录
|
||||||
*/
|
*/
|
||||||
@@ -69,10 +73,18 @@ public final class OaApiUrl {
|
|||||||
* 统计未缴租金账单数
|
* 统计未缴租金账单数
|
||||||
*/
|
*/
|
||||||
public static final String COUNT_UNPAY_RENT_BILLS = "/bill/countUnpay/rent";
|
public static final String COUNT_UNPAY_RENT_BILLS = "/bill/countUnpay/rent";
|
||||||
|
/**
|
||||||
|
* 统计未缴租金账单数
|
||||||
|
*/
|
||||||
|
public static final String COUNT_UNPAID_RENT_MARGIN = "/bill/countUnpay/margin";
|
||||||
/**
|
/**
|
||||||
* 获取账单收款方
|
* 获取账单收款方
|
||||||
*/
|
*/
|
||||||
public static final String BILL_PAY_RECEIVER = "/bill/payreceiver";
|
public static final String BILL_PAY_RECEIVER = "/bill/payreceiver";
|
||||||
|
/**
|
||||||
|
* 支付回调
|
||||||
|
*/
|
||||||
|
public static final String PAY_CALLBACK = "/bill/pay/callback";
|
||||||
/**
|
/**
|
||||||
* 统计未缴水电费账单数
|
* 统计未缴水电费账单数
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -117,6 +117,9 @@ public class ContractService {
|
|||||||
return assetsInfo;
|
return assetsInfo;
|
||||||
}
|
}
|
||||||
public Integer countUnsign(String cusNo) throws Exception {
|
public Integer countUnsign(String cusNo) throws Exception {
|
||||||
|
if(StringUtils.isBlank(cusNo)){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Integer count = oaContractService.countUnsign(cusNo);
|
Integer count = oaContractService.countUnsign(cusNo);
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.chenyon.message;
|
package org.chenyon.message;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.chenyon.wx.AesException;
|
import org.chenyon.wx.AesException;
|
||||||
import org.rcy.framework.api.entity.PageResult;
|
import org.rcy.framework.api.entity.PageResult;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -37,6 +38,9 @@ public class MessageService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Integer countUnread(String cusNo){
|
public Integer countUnread(String cusNo){
|
||||||
|
if(StringUtils.isBlank(cusNo)){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
MessageQueryCondition messageQueryCondition = new MessageQueryCondition();
|
MessageQueryCondition messageQueryCondition = new MessageQueryCondition();
|
||||||
messageQueryCondition.setMessageReceiver(cusNo);
|
messageQueryCondition.setMessageReceiver(cusNo);
|
||||||
messageQueryCondition.setHasRead(false);
|
messageQueryCondition.setHasRead(false);
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import org.rcy.framework.utils.json.JsonUtils;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -40,6 +42,26 @@ public class OaBillService {
|
|||||||
return pageResult;
|
return pageResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PageResult<OaBillVo> pageQueryUnpaidMargin(BillQueryCondition condition) throws Exception {
|
||||||
|
OaResp oaResp = seeyonHttpClient.sendPost("分页查询保障金账单信息", OaApiUrl.PAGE_QUERY_UNPAID_MARGIN, JsonUtils.convertJson(condition));
|
||||||
|
String data = oaResp.getDataStr();
|
||||||
|
Map mapRoot = JsonUtils.parseObject(data, Map.class);
|
||||||
|
List<OaBillVo> oaBillVos = null;
|
||||||
|
Long totalCount = 0L;
|
||||||
|
if(mapRoot.get("totalCount") != null){
|
||||||
|
totalCount = mapRoot.get("totalCount") instanceof Long ? (Long) mapRoot.get("totalCount") : Long.parseLong(mapRoot.get("totalCount") + "");
|
||||||
|
}
|
||||||
|
if(mapRoot.get("datas") != null) {
|
||||||
|
oaBillVos = JsonUtils.parseArray(JsonUtils.convertJson(mapRoot.get("datas")), OaBillVo.class);
|
||||||
|
}
|
||||||
|
PageResult<OaBillVo> pageResult = new PageResult<>();
|
||||||
|
pageResult.setPageNo(condition.getPageNo());
|
||||||
|
pageResult.setPageSize(condition.getPageSize());
|
||||||
|
pageResult.setRecordTotal(totalCount.intValue());
|
||||||
|
pageResult.setResult(oaBillVos);
|
||||||
|
return pageResult;
|
||||||
|
}
|
||||||
|
|
||||||
public PageResult<OaBillVo> pageQueryWaeBill(BillQueryCondition condition) throws Exception {
|
public PageResult<OaBillVo> pageQueryWaeBill(BillQueryCondition condition) throws Exception {
|
||||||
OaResp oaResp = seeyonHttpClient.sendPost("分页查询水电费账单信息", OaApiUrl.PAGE_QUERY_WAE_BILL, JsonUtils.convertJson(condition));
|
OaResp oaResp = seeyonHttpClient.sendPost("分页查询水电费账单信息", OaApiUrl.PAGE_QUERY_WAE_BILL, JsonUtils.convertJson(condition));
|
||||||
String data = oaResp.getDataStr();
|
String data = oaResp.getDataStr();
|
||||||
@@ -86,6 +108,11 @@ public class OaBillService {
|
|||||||
return (Integer) oaResp.getData();
|
return (Integer) oaResp.getData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Integer countUnpaidRentMargin(Map<String,Object> params) throws Exception {
|
||||||
|
OaResp oaResp = seeyonHttpClient.sendPost("统计未缴保证金账单数", OaApiUrl.COUNT_UNPAID_RENT_MARGIN, JsonUtils.convertJson(params));
|
||||||
|
return (Integer) oaResp.getData();
|
||||||
|
}
|
||||||
|
|
||||||
public Integer countUnpayWaeBills(Map<String,Object> params) throws Exception {
|
public Integer countUnpayWaeBills(Map<String,Object> params) throws Exception {
|
||||||
OaResp oaResp = seeyonHttpClient.sendPost("统计未缴水电费账单数", OaApiUrl.COUNT_UNPAY_WAE_BILLS, JsonUtils.convertJson(params));
|
OaResp oaResp = seeyonHttpClient.sendPost("统计未缴水电费账单数", OaApiUrl.COUNT_UNPAY_WAE_BILLS, JsonUtils.convertJson(params));
|
||||||
return (Integer) oaResp.getData();
|
return (Integer) oaResp.getData();
|
||||||
@@ -96,4 +123,11 @@ public class OaBillService {
|
|||||||
return (String) oaResp.getData();
|
return (String) oaResp.getData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void payCallBack(String billNo, String bizType, String payDate) throws Exception {
|
||||||
|
Map<String,Object> params = new HashMap<>();
|
||||||
|
params.put("billNo",billNo);
|
||||||
|
params.put("bizType",bizType);
|
||||||
|
params.put("payDate",payDate);
|
||||||
|
OaResp oaResp = seeyonHttpClient.sendPost("支付回调", OaApiUrl.PAY_CALLBACK ,JsonUtils.convertJson(params));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,9 +39,9 @@ public class OaCusService {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CusVo matchPersonCus(String phone) throws Exception {
|
public CusVo matchPersonCus(String cardNo) throws Exception {
|
||||||
Map<String,Object> params = new HashMap<>();
|
Map<String,Object> params = new HashMap<>();
|
||||||
params.put("phone",phone);
|
params.put("cardNo",cardNo);
|
||||||
OaResp oaResp = seeyonHttpClient.sendPost("匹配个人客户",OaApiUrl.MATCH_PERSON, params);
|
OaResp oaResp = seeyonHttpClient.sendPost("匹配个人客户",OaApiUrl.MATCH_PERSON, params);
|
||||||
Object data = oaResp.getData();
|
Object data = oaResp.getData();
|
||||||
CusVo cusVo = new CusVo();
|
CusVo cusVo = new CusVo();
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import org.springframework.beans.BeanUtils;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -28,18 +29,27 @@ public class OaNoticeService {
|
|||||||
String data = oaResp.getDataStr();
|
String data = oaResp.getDataStr();
|
||||||
Map mapRoot = JsonUtils.parseObject(data, Map.class);
|
Map mapRoot = JsonUtils.parseObject(data, Map.class);
|
||||||
Long totalCount = 0L;
|
Long totalCount = 0L;
|
||||||
List<NoticeVo> vos = null;
|
List<OaNoticeVo> vos = null;
|
||||||
if(mapRoot.get("totalCount") != null){
|
if(mapRoot.get("totalCount") != null){
|
||||||
totalCount = mapRoot.get("totalCount") instanceof Long ? (Long) mapRoot.get("totalCount") : Long.parseLong(mapRoot.get("totalCount") + "");
|
totalCount = mapRoot.get("totalCount") instanceof Long ? (Long) mapRoot.get("totalCount") : Long.parseLong(mapRoot.get("totalCount") + "");
|
||||||
}
|
}
|
||||||
if(mapRoot.get("datas") != null) {
|
if(mapRoot.get("datas") != null) {
|
||||||
vos = JsonUtils.parseArray(JsonUtils.convertJson(mapRoot.get("datas")), NoticeVo.class);
|
vos = JsonUtils.parseArray(JsonUtils.convertJson(mapRoot.get("datas")), OaNoticeVo.class);
|
||||||
}
|
}
|
||||||
|
List<NoticeVo> noticeVos = new ArrayList<>();
|
||||||
PageResult<NoticeVo> pageResult = new PageResult<>();
|
PageResult<NoticeVo> pageResult = new PageResult<>();
|
||||||
|
if(vos == null) {
|
||||||
|
return pageResult;
|
||||||
|
}
|
||||||
|
for (OaNoticeVo vo : vos) {
|
||||||
|
NoticeVo noticeVo = new NoticeVo();
|
||||||
|
BeanUtils.copyProperties(vo, noticeVo);
|
||||||
|
noticeVos.add(noticeVo);
|
||||||
|
}
|
||||||
pageResult.setPageNo(condition.getPageNo());
|
pageResult.setPageNo(condition.getPageNo());
|
||||||
pageResult.setPageSize(condition.getPageSize());
|
pageResult.setPageSize(condition.getPageSize());
|
||||||
pageResult.setRecordTotal(totalCount.intValue());
|
pageResult.setRecordTotal(totalCount.intValue());
|
||||||
pageResult.setResult(vos);
|
pageResult.setResult(noticeVos);
|
||||||
return pageResult;
|
return pageResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.chenyon.oa;
|
package org.chenyon.oa;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.chenyon.constants.OaApiUrl;
|
import org.chenyon.constants.OaApiUrl;
|
||||||
import org.chenyon.fallback.FallbackSubmitVo;
|
import org.chenyon.fallback.FallbackSubmitVo;
|
||||||
import org.chenyon.reservation.ReservationQueryCondition;
|
import org.chenyon.reservation.ReservationQueryCondition;
|
||||||
@@ -41,6 +42,9 @@ public class OaReservationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Integer countHandling(String openId) throws Exception {
|
public Integer countHandling(String openId) throws Exception {
|
||||||
|
if(StringUtils.isBlank(openId)){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Map<String,Object> params = new HashMap<>();
|
Map<String,Object> params = new HashMap<>();
|
||||||
params.put("openId",openId);
|
params.put("openId",openId);
|
||||||
OaResp oaResp = seeyonHttpClient.sendPost("查询处理中预约", OaApiUrl.RESERVATION_COUNT_HANDLING,JsonUtils.convertJson(params));
|
OaResp oaResp = seeyonHttpClient.sendPost("查询处理中预约", OaApiUrl.RESERVATION_COUNT_HANDLING,JsonUtils.convertJson(params));
|
||||||
|
|||||||
@@ -9,12 +9,15 @@ import org.chenyon.pay.shopcar.TmPayOrderRespVo;
|
|||||||
import org.chenyon.pay.shopcar.VaFld;
|
import org.chenyon.pay.shopcar.VaFld;
|
||||||
import org.chenyon.user.UserService;
|
import org.chenyon.user.UserService;
|
||||||
import org.rcy.framework.data.id.LongIdGenerator;
|
import org.rcy.framework.data.id.LongIdGenerator;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -22,6 +25,8 @@ import java.util.*;
|
|||||||
@Service
|
@Service
|
||||||
public class OrderService {
|
public class OrderService {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(OrderService.class);
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private WeAppOrderDao weAppOrderDao;
|
private WeAppOrderDao weAppOrderDao;
|
||||||
@Autowired
|
@Autowired
|
||||||
@@ -31,8 +36,10 @@ public class OrderService {
|
|||||||
private String mid;
|
private String mid;
|
||||||
@Value("${chinaums.tid}")
|
@Value("${chinaums.tid}")
|
||||||
private String tid;
|
private String tid;
|
||||||
@Value("${chinaums.sourceNo}")
|
@Value("${chinaums.systemNo}")
|
||||||
private String sourceNo;
|
private String sourceNo;
|
||||||
|
@Value("${chinaums.sysSource}")
|
||||||
|
private String sysSource;
|
||||||
@Value("${wx.appId}")
|
@Value("${wx.appId}")
|
||||||
private String miniProgramAppId;
|
private String miniProgramAppId;
|
||||||
|
|
||||||
@@ -49,94 +56,113 @@ public class OrderService {
|
|||||||
private String fwglMid;
|
private String fwglMid;
|
||||||
@Value("${wx.appId}")
|
@Value("${wx.appId}")
|
||||||
private String wxAppId;
|
private String wxAppId;
|
||||||
@Value("${chinaums.pay.notifyUrl}")
|
@Value("${cdn.domain}")
|
||||||
private String notifyUrl;
|
private String domain;
|
||||||
|
private DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
|
|
||||||
/**
|
|
||||||
* 批量创建支付订单
|
|
||||||
* 【核心】批量前 校验所有 billNo 是否已经存在子订单
|
|
||||||
* 子订单唯一键:billNo
|
|
||||||
*/
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public TmPayOrderRespVo createOrder(OrderVo orderVo) throws Exception {
|
public TmPayOrderRespVo createOrder(OrderVo orderVo) throws Exception {
|
||||||
// 1. 基础入参校验
|
// 1. 基础参数校验
|
||||||
if (orderVo == null || orderVo.getBillVoList() == null || orderVo.getBillVoList().isEmpty()) {
|
if (orderVo == null || orderVo.getBillVoList() == null || orderVo.getBillVoList().isEmpty()) {
|
||||||
throw new Exception("批量支付账单不能为空");
|
throw new Exception("批量支付账单不能为空");
|
||||||
}
|
}
|
||||||
if (StringUtils.isEmpty(orderVo.getPayerOpenId())) {
|
if (StringUtils.isEmpty(orderVo.getPayerOpenId())) {
|
||||||
throw new Exception("支付人OPENID不能为空");
|
throw new Exception("支付人OPENID不能为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
List<UnpaidBillVo> billVoList = orderVo.getBillVoList();
|
List<UnpaidBillVo> billVoList = orderVo.getBillVoList();
|
||||||
|
|
||||||
// ======================================================================
|
// ======================================================================
|
||||||
// 【批量支付 最强幂等校验】
|
// 【第1步:最前置全局幂等锁单校验(核心防重,在所有操作之前!)】
|
||||||
// 遍历所有子账单,根据 billNo 查询是否已存在支付记录
|
// 只要任意账单存在 【支付中未完成】订单,直接拒绝,后续所有流程全部不执行
|
||||||
// 只要有一个已存在 → 整批拒绝支付
|
// 不创建本地订单、不调用银联、不生成支付单,从源头杜绝重复支付
|
||||||
// ======================================================================
|
// ======================================================================
|
||||||
for (UnpaidBillVo billVo : billVoList) {
|
for (UnpaidBillVo billVo : billVoList) {
|
||||||
String billNo = billVo.getBillNo();
|
String billNo = billVo.getBillNo();
|
||||||
// 子订单唯一键:billNo
|
|
||||||
WeAppSubOrder existSubOrder = weAppSubOrderDao.selectByBillNo(billNo);
|
WeAppSubOrder existSubOrder = weAppSubOrderDao.selectByBillNo(billNo);
|
||||||
if (existSubOrder != null) {
|
if (existSubOrder == null) {
|
||||||
throw new Exception("批量支付失败:账单号【" + billNo + "】已存在支付记录,禁止重复支付");
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 规则1:账单已支付成功,永久禁止支付
|
||||||
|
if ("1".equals(existSubOrder.getPayStatus())) {
|
||||||
|
throw new Exception("账单【" + billNo + "】已支付完成,无法再次支付");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 规则2:子订单绑定的旧主订单 处于【待支付/支付中】,直接拒绝本次请求
|
||||||
|
Long oldMainOrderId = existSubOrder.getMainOrderId();
|
||||||
|
WeAppOrder oldMainOrder = weAppOrderDao.get(oldMainOrderId);
|
||||||
|
if (oldMainOrder != null && "0".equals(oldMainOrder.getPayStatus())) {
|
||||||
|
throw new Exception("账单【" + billNo + "】存在进行中的支付订单,请等待支付结果或支付超时关闭后重试");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 生成主订单ID
|
// ======================================================================
|
||||||
Long mainOrderId = LongIdGenerator.generate();
|
// 【第2步:全部校验通过,生成全新主订单】
|
||||||
String bizId = mainOrderId.toString();
|
// ======================================================================
|
||||||
|
Long newMainOrderId = LongIdGenerator.generate();
|
||||||
|
String bizId = String.valueOf(newMainOrderId);
|
||||||
orderVo.setBizId(bizId);
|
orderVo.setBizId(bizId);
|
||||||
|
|
||||||
// 3. 主订单幂等校验
|
// 生成银联唯一支付单号
|
||||||
WeAppOrder existMainOrder = weAppOrderDao.findByBizId(bizId);
|
|
||||||
if (existMainOrder != null) {
|
|
||||||
TmPayOrderRespVo resp = new TmPayOrderRespVo();
|
|
||||||
// resp.setOrderNo(existMainOrder.getTmOrderId());
|
|
||||||
// resp.setAmount(existMainOrder.getAmount());
|
|
||||||
return resp;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. 生成第三方支付订单号
|
|
||||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
|
||||||
int random = 1000000 + new Random().nextInt(9000000);
|
int random = 1000000 + new Random().nextInt(9000000);
|
||||||
String tmOrderNo = sourceNo + sdf.format(new Date()) + random;
|
String tmOrderNo = "14BF" + sdf.format(new Date()) + random;
|
||||||
|
|
||||||
// 第三方单号唯一兜底
|
// 银联单号唯一性校验
|
||||||
WeAppOrder orderByTmNo = weAppOrderDao.selectByTmOrderId(tmOrderNo);
|
if (weAppOrderDao.selectByTmOrderId(tmOrderNo) != null) {
|
||||||
if (orderByTmNo != null) {
|
|
||||||
throw new Exception("支付单号重复,请重新提交");
|
throw new Exception("支付单号重复,请重新提交");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. 调用支付创建分账订单
|
// ======================================================================
|
||||||
ShopCarOrderCreateRequest request = buildShopCarOrderCreateRequest(orderVo, tmOrderNo);
|
// 【第3步:本地子订单、主订单全部先落库(数据先行锁定)】
|
||||||
TmPayOrderRespVo payResp = tmPayService.weChatPayCreateSplitOrder(request);
|
// 不存在则新增,旧单已关闭则更新绑定最新主订单
|
||||||
|
// ======================================================================
|
||||||
// 6. 批量插入子订单 + 修复 BigDecimal 金额BUG
|
|
||||||
BigDecimal totalAmount = BigDecimal.ZERO;
|
BigDecimal totalAmount = BigDecimal.ZERO;
|
||||||
for (UnpaidBillVo billVo : billVoList) {
|
for (UnpaidBillVo billVo : billVoList) {
|
||||||
WeAppSubOrder subOrder = new WeAppSubOrder();
|
String billNo = billVo.getBillNo();
|
||||||
subOrder.setMainOrderId(mainOrderId);
|
WeAppSubOrder existSub = weAppSubOrderDao.selectByBillNo(billNo);
|
||||||
subOrder.setBillNo(billVo.getBillNo()); // 唯一键
|
|
||||||
subOrder.setAmount(billVo.getAmount());
|
if (existSub == null) {
|
||||||
subOrder.setPayStatus("0");
|
// 子订单首次不存在:新增,绑定本次新主订单
|
||||||
weAppSubOrderDao.insert(subOrder);
|
WeAppSubOrder subOrder = new WeAppSubOrder();
|
||||||
|
subOrder.setMainOrderId(newMainOrderId);
|
||||||
|
subOrder.setBillNo(billNo);
|
||||||
|
subOrder.setAmount(billVo.getAmount());
|
||||||
|
subOrder.setBizSubType(billVo.getBizType());
|
||||||
|
subOrder.setPayStatus("0");
|
||||||
|
subOrder.setCreateTime(new Date());
|
||||||
|
weAppSubOrderDao.insert(subOrder);
|
||||||
|
} else {
|
||||||
|
// 子订单已存在:走到这里已经经过前置校验
|
||||||
|
// 旧主订单一定是【失败/关闭】状态,安全更新绑定最新主订单
|
||||||
|
existSub.setMainOrderId(newMainOrderId);
|
||||||
|
existSub.setPayStatus("0"); // 重置为待支付状态
|
||||||
|
weAppSubOrderDao.updateByPrimaryKeySelective(existSub);
|
||||||
|
}
|
||||||
|
|
||||||
// 正确累加金额(修复原BUG)
|
|
||||||
totalAmount = totalAmount.add(new BigDecimal(billVo.getAmount()));
|
totalAmount = totalAmount.add(new BigDecimal(billVo.getAmount()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7. 插入主订单
|
// 插入全新主订单(本地数据全部落库完成)
|
||||||
WeAppOrder weAppOrder = new WeAppOrder();
|
WeAppOrder weAppOrder = new WeAppOrder();
|
||||||
weAppOrder.setId(mainOrderId);
|
weAppOrder.setId(newMainOrderId);
|
||||||
weAppOrder.setBizId(bizId);
|
weAppOrder.setBizId(bizId);
|
||||||
weAppOrder.setPayerId(orderVo.getPayer());
|
weAppOrder.setPayerId(orderVo.getPayer());
|
||||||
weAppOrder.setPayerName(orderVo.getPayerName());
|
weAppOrder.setPayerName(orderVo.getPayerName());
|
||||||
weAppOrder.setTmOrderId(tmOrderNo);
|
weAppOrder.setTmOrderId(tmOrderNo);
|
||||||
weAppOrder.setAmount(totalAmount.toString());
|
weAppOrder.setAmount(totalAmount.toString());
|
||||||
weAppOrder.setPayStatus("0");
|
weAppOrder.setPayStatus("0"); // 待支付(支付中)
|
||||||
|
weAppOrder.setCreateTime(new Date());
|
||||||
|
weAppOrder.setPayerOpenId(orderVo.getPayerOpenId());
|
||||||
weAppOrderDao.insert(weAppOrder);
|
weAppOrderDao.insert(weAppOrder);
|
||||||
|
|
||||||
|
// ======================================================================
|
||||||
|
// 【第4步:本地所有订单数据全部安全落库后,最后才调用银联创建支付单】
|
||||||
|
// 顺序彻底修正!业务数据优先,第三方支付最后执行
|
||||||
|
// ======================================================================
|
||||||
|
ShopCarOrderCreateRequest request = buildShopCarOrderCreateRequest(orderVo, tmOrderNo);
|
||||||
|
TmPayOrderRespVo payResp = tmPayService.weChatPayCreateSplitOrder(request);
|
||||||
|
|
||||||
|
payResp.setMainOrderId(newMainOrderId);
|
||||||
return payResp;
|
return payResp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,10 +176,11 @@ public class OrderService {
|
|||||||
request.setSubAppId(wxAppId);
|
request.setSubAppId(wxAppId);
|
||||||
request.setMchntOrderId(orderNo);
|
request.setMchntOrderId(orderNo);
|
||||||
request.setMsgType("wx.unifiedOrder");
|
request.setMsgType("wx.unifiedOrder");
|
||||||
|
String notifyUrl = domain + "/api" + "/bill/paycallback" + "?orderId=" + orderVo.getBizId() + "&" + "payResult=SUCCESS";
|
||||||
request.setNotifyUrl(notifyUrl);
|
request.setNotifyUrl(notifyUrl);
|
||||||
request.setTradeType("MINI");
|
request.setTradeType("MINI");
|
||||||
request.setSubOpenId(orderVo.getPayerOpenId());
|
request.setSubOpenId(orderVo.getPayerOpenId());
|
||||||
request.setSysSource("OPT");
|
request.setSysSource(sysSource);
|
||||||
|
|
||||||
VaFld vaFld = new VaFld();
|
VaFld vaFld = new VaFld();
|
||||||
vaFld.setNewShopFlag("GWCXS");
|
vaFld.setNewShopFlag("GWCXS");
|
||||||
@@ -169,6 +196,9 @@ public class OrderService {
|
|||||||
param.put("billNo", billVo.getBillNo());
|
param.put("billNo", billVo.getBillNo());
|
||||||
param.put("bizType", billVo.getBizType());
|
param.put("bizType", billVo.getBizType());
|
||||||
String receiver = oaBillService.getBillPayReceiver(param);
|
String receiver = oaBillService.getBillPayReceiver(param);
|
||||||
|
if(StringUtils.isBlank(receiver) || "null".equals(receiver)){
|
||||||
|
throw new RuntimeException("获取账单收款方失败,请联系管理员");
|
||||||
|
}
|
||||||
billVo.setPayee(receiver);
|
billVo.setPayee(receiver);
|
||||||
|
|
||||||
int amountCent = (int) (Double.parseDouble(billVo.getAmount()) * 100);
|
int amountCent = (int) (Double.parseDouble(billVo.getAmount()) * 100);
|
||||||
@@ -184,14 +214,12 @@ public class OrderService {
|
|||||||
if (gyAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (gyAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
SatInfo info = new SatInfo();
|
SatInfo info = new SatInfo();
|
||||||
info.setMerId(gyMid);
|
info.setMerId(gyMid);
|
||||||
info.setFeeBear("Y");
|
|
||||||
info.setSatAmt(gyAmount.toString());
|
info.setSatAmt(gyAmount.toString());
|
||||||
satInfoList.add(info);
|
satInfoList.add(info);
|
||||||
}
|
}
|
||||||
if (fwglAmount.compareTo(BigDecimal.ZERO) > 0) {
|
if (fwglAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
SatInfo info = new SatInfo();
|
SatInfo info = new SatInfo();
|
||||||
info.setMerId(fwglMid);
|
info.setMerId(fwglMid);
|
||||||
info.setFeeBear("Y");
|
|
||||||
info.setSatAmt(fwglAmount.toString());
|
info.setSatAmt(fwglAmount.toString());
|
||||||
satInfoList.add(info);
|
satInfoList.add(info);
|
||||||
}
|
}
|
||||||
@@ -202,39 +230,70 @@ public class OrderService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支付回调(幂等 + 批量更新子订单)
|
* 最终版支付回调(100%幂等 + 无并发问题 + 安全)
|
||||||
*/
|
*/
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void tmPayCallback(String tmOrderNo, String payResult) {
|
public void tmPayCallback(String mainOrderId, String payResult) {
|
||||||
WeAppOrder order = weAppOrderDao.selectByTmOrderId(tmOrderNo);
|
// 1. 查询主订单
|
||||||
if (order == null || "1".equals(order.getPayStatus())) {
|
WeAppOrder order = weAppOrderDao.findByBizId(mainOrderId);
|
||||||
|
if (order == null) {
|
||||||
|
log.warn("[回调] 主订单不存在,bizId:{}", mainOrderId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== 【核心幂等】 ====================
|
||||||
|
// 已支付 -> 直接返回,绝对不重复处理
|
||||||
|
// ======================================================
|
||||||
|
if ("1".equals(order.getPayStatus())) {
|
||||||
|
log.info("[回调幂等] 订单已支付,无需重复处理,bizId:{}", mainOrderId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 支付成功 ====================
|
||||||
if ("SUCCESS".equalsIgnoreCase(payResult)) {
|
if ("SUCCESS".equalsIgnoreCase(payResult)) {
|
||||||
|
// 更新主订单状态
|
||||||
order.setPayStatus("1");
|
order.setPayStatus("1");
|
||||||
|
order.setPayDate(new Date());
|
||||||
weAppOrderDao.updateByPrimaryKeySelective(order);
|
weAppOrderDao.updateByPrimaryKeySelective(order);
|
||||||
|
|
||||||
// 批量更新该主订单下 所有子订单(billNo)状态
|
// 查询该主订单下的所有子订单(只会查一次,因为子订单终身唯一)
|
||||||
List<WeAppSubOrder> subList = weAppSubOrderDao.selectByMainOrderId(order.getId());
|
List<WeAppSubOrder> subList = weAppSubOrderDao.selectByMainOrderId(order.getId());
|
||||||
|
|
||||||
for (WeAppSubOrder sub : subList) {
|
for (WeAppSubOrder sub : subList) {
|
||||||
sub.setPayStatus("1");
|
// ================== 子订单幂等 ==================
|
||||||
weAppSubOrderDao.updateById(sub);
|
if ("1".equals(sub.getPayStatus())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 更新子订单为已支付
|
||||||
|
sub.setPayStatus("1");
|
||||||
|
weAppSubOrderDao.updateByPrimaryKeySelective(sub);
|
||||||
|
String payDate = df.format(order.getPayDate() != null ? order.getPayDate() : new Date());
|
||||||
|
try {
|
||||||
|
TmPayOrderRespVo tmPayOrderRespVo = tmPayService.queryOrder(mid, tid, order.getTmOrderId());
|
||||||
|
if (tmPayOrderRespVo != null && tmPayOrderRespVo.getPayTime() != null) {
|
||||||
|
payDate = tmPayOrderRespVo.getPayTime();
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
log.warn("[回调] 查询银联支付时间失败,使用本地时间,账单号:{}", sub.getBillNo(), ex);
|
||||||
|
}
|
||||||
|
// 通知OA(失败只记录,不影响支付状态)
|
||||||
|
oaBillService.payCallBack(sub.getBillNo(), sub.getBizSubType(), payDate);
|
||||||
|
log.info("[回调] OA通知成功,账单号:{}", sub.getBillNo());
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("[回调] OA通知失败,账单号:{}", sub.getBillNo(), e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.info("[回调] 主订单支付成功处理完成,bizId:{}", mainOrderId);
|
||||||
} else {
|
} else {
|
||||||
|
// ================== 支付失败 ==================
|
||||||
order.setPayStatus("2");
|
order.setPayStatus("2");
|
||||||
weAppOrderDao.updateByPrimaryKeySelective(order);
|
weAppOrderDao.updateByPrimaryKeySelective(order);
|
||||||
|
log.info("[回调] 主订单支付失败,bizId:{}", mainOrderId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void callBack(String bizId) {
|
|
||||||
WeAppOrder order = weAppOrderDao.findByBizId(bizId);
|
|
||||||
if (order != null) {
|
|
||||||
tmPayCallback(order.getTmOrderId(), "SUCCESS");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private UnifiedOrderRequest buildUnifiedOrderRequest(OrderVo orderVo) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
63
src/main/java/org/chenyon/pay/PayOrderCheckTask.java
Normal file
63
src/main/java/org/chenyon/pay/PayOrderCheckTask.java
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
package org.chenyon.pay;
|
||||||
|
|
||||||
|
import org.chenyon.pay.shopcar.TmPayOrderRespVo;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class PayOrderCheckTask {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(PayOrderCheckTask.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private WeAppOrderDao weAppOrderDao;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TmPayService tmPayService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private OrderService orderService;
|
||||||
|
@Value("${chinaums.mid}")
|
||||||
|
private String mid;
|
||||||
|
@Value("${chinaums.tid}")
|
||||||
|
private String tid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 每 5 分钟执行一次:查询支付中订单,修正状态
|
||||||
|
*/
|
||||||
|
@Scheduled(cron = "0 0/5 * * * ?")
|
||||||
|
public void checkUnpaidOrder() {
|
||||||
|
// 查询 超过 5 分钟 还在支付中的订单
|
||||||
|
List<WeAppOrder> orderList = weAppOrderDao.selectTimeoutUnpaidOrder();
|
||||||
|
|
||||||
|
for (WeAppOrder order : orderList) {
|
||||||
|
try {
|
||||||
|
// 1. 调用银联【查询订单状态接口】
|
||||||
|
String tmOrderId = order.getTmOrderId();
|
||||||
|
TmPayOrderRespVo queryResult = tmPayService.queryOrder(mid, tid, tmOrderId);
|
||||||
|
if (queryResult == null) {
|
||||||
|
log.warn("[定时补偿] 银联查询返回空,主订单bizId:{}, tmOrderId:{}", order.getBizId(), tmOrderId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String status = queryResult.getStatus();
|
||||||
|
// 2. 根据银联返回结果,修正本地订单
|
||||||
|
if ("TRADE_SUCCESS".equals(status)) {
|
||||||
|
// 支付成功 → 执行成功回调逻辑(核销、入账、修改状态)
|
||||||
|
orderService.tmPayCallback(order.getBizId(), "SUCCESS");
|
||||||
|
} else if ("TRADE_CLOSED".equals(status)) {
|
||||||
|
// 支付失败 / 已关闭 → 修改订单状态
|
||||||
|
orderService.tmPayCallback(order.getBizId(), "FAIL");
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 异常不影响其他订单
|
||||||
|
log.error("[定时补偿] 处理订单异常,bizId:{}", order.getBizId(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,16 +4,22 @@ package org.chenyon.pay;
|
|||||||
import org.chenyon.pay.shopcar.MiniPayRequest;
|
import org.chenyon.pay.shopcar.MiniPayRequest;
|
||||||
import org.chenyon.pay.shopcar.ShopCarOrderCreateRequest;
|
import org.chenyon.pay.shopcar.ShopCarOrderCreateRequest;
|
||||||
import org.chenyon.pay.shopcar.TmPayOrderRespVo;
|
import org.chenyon.pay.shopcar.TmPayOrderRespVo;
|
||||||
|
import org.chenyon.pay.shopcar.VaFld;
|
||||||
import org.rcy.framework.utils.json.JsonUtils;
|
import org.rcy.framework.utils.json.JsonUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class TmPayService {
|
public class TmPayService {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(TmPayService.class);
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private TmHttpUtil tmHttpUtil;
|
private TmHttpUtil tmHttpUtil;
|
||||||
|
|
||||||
@@ -37,17 +43,50 @@ public class TmPayService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public TmPayOrderRespVo weChatPayCreateSplitOrder(ShopCarOrderCreateRequest request) {
|
public TmPayOrderRespVo queryOrder(String vaMchntNo,String vaTermNo,String tmOrderNo) {
|
||||||
|
//支付结果查询
|
||||||
|
String url = "/v1/inip/upsp/shop/mini/pay-query";
|
||||||
|
try {
|
||||||
|
Map<String,Object> params = new HashMap<>();
|
||||||
|
params.put("mchntOrderId",tmOrderNo);
|
||||||
|
params.put("vaMchntNo",vaMchntNo);
|
||||||
|
params.put("vaTermNo",vaTermNo);
|
||||||
|
VaFld vaFld = new VaFld();
|
||||||
|
vaFld.setNewShopFlag("");
|
||||||
|
params.put("vaFld",vaFld);
|
||||||
|
String paramStr = JsonUtils.convertJson(params);
|
||||||
|
log.info("查询银联支付结果参数为: {}",paramStr );
|
||||||
|
String respStr = tmHttpUtil.post(url, paramStr, TmHttpUtil.AuthMode.SIGNATURE);
|
||||||
|
Map map = JsonUtils.parseObject(respStr, Map.class);
|
||||||
|
String code = (String)map.get("respCode");
|
||||||
|
if(!"0000".equals(code)){
|
||||||
|
throw new RuntimeException("查询失败");
|
||||||
|
}
|
||||||
|
String payTime = (String)map.get("payTime");
|
||||||
|
String status = (String)map.get("status");
|
||||||
|
TmPayOrderRespVo tmPayOrderRespVo = new TmPayOrderRespVo();
|
||||||
|
tmPayOrderRespVo.setPayTime(payTime);
|
||||||
|
tmPayOrderRespVo.setStatus(status);
|
||||||
|
return tmPayOrderRespVo;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e.getMessage(),e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TmPayOrderRespVo weChatPayCreateSplitOrder(ShopCarOrderCreateRequest request) {
|
||||||
String url = "/v1/inip/upsp/shop/mini/pay";
|
String url = "/v1/inip/upsp/shop/mini/pay";
|
||||||
try {
|
try {
|
||||||
String respStr = tmHttpUtil.post(url, JsonUtils.convertJson(request), TmHttpUtil.AuthMode.SIGNATURE);
|
String paramStr = JsonUtils.convertJson(request);
|
||||||
|
log.info("创建银联支付订单参数为: {}",paramStr );
|
||||||
|
String respStr = tmHttpUtil.post(url, paramStr, TmHttpUtil.AuthMode.SIGNATURE);
|
||||||
Map map = JsonUtils.parseObject(respStr, Map.class);
|
Map map = JsonUtils.parseObject(respStr, Map.class);
|
||||||
String code = (String)map.get("respCode");
|
String code = (String)map.get("respCode");
|
||||||
if(!"0000".equals(code)){
|
if(!"0000".equals(code)){
|
||||||
throw new RuntimeException("创建订单失败");
|
throw new RuntimeException("创建订单失败");
|
||||||
}
|
}
|
||||||
String forwardUrl = (String)map.get("url");
|
String forwardUrl = (String)map.get("url");
|
||||||
Map<String,String> miniRequestMap = (Map<String, String>) map.get("miniPayRequest");
|
Map<String,String> miniRequestMap = JsonUtils.parseObject((String)map.get("miniPayRequest"), Map.class);
|
||||||
MiniPayRequest miniPayRequest = new MiniPayRequest();
|
MiniPayRequest miniPayRequest = new MiniPayRequest();
|
||||||
miniPayRequest.setAppId(miniRequestMap.get("appId"));
|
miniPayRequest.setAppId(miniRequestMap.get("appId"));
|
||||||
miniPayRequest.setNonceStr(miniRequestMap.get("nonceStr"));
|
miniPayRequest.setNonceStr(miniRequestMap.get("nonceStr"));
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import javax.persistence.Table;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "ORDER")
|
@Table(name = "WEAPP_ORDER")
|
||||||
public class WeAppOrder extends BaseEntity {
|
public class WeAppOrder extends BaseEntity {
|
||||||
|
|
||||||
private String bizId;
|
private String bizId;
|
||||||
@@ -18,6 +18,7 @@ public class WeAppOrder extends BaseEntity {
|
|||||||
private String payStatus; //支付状态
|
private String payStatus; //支付状态
|
||||||
private String payerOpenId; //
|
private String payerOpenId; //
|
||||||
private String tmOrderId; //银联支付订单号
|
private String tmOrderId; //银联支付订单号
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
|
|
||||||
public String getBizId() {
|
public String getBizId() {
|
||||||
@@ -83,4 +84,12 @@ public class WeAppOrder extends BaseEntity {
|
|||||||
public void setTmOrderId(String tmOrderId) {
|
public void setTmOrderId(String tmOrderId) {
|
||||||
this.tmOrderId = tmOrderId;
|
this.tmOrderId = tmOrderId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Date getCreateTime() {
|
||||||
|
return createTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreateTime(Date createTime) {
|
||||||
|
this.createTime = createTime;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,10 @@ package org.chenyon.pay;
|
|||||||
|
|
||||||
import org.rcy.framework.data.dao.BaseDao;
|
import org.rcy.framework.data.dao.BaseDao;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public interface WeAppOrderDao extends BaseDao<WeAppOrder> {
|
public interface WeAppOrderDao extends BaseDao<WeAppOrder> {
|
||||||
WeAppOrder findByBizId(String bizId);
|
WeAppOrder findByBizId(String bizId);
|
||||||
WeAppOrder selectByTmOrderId(String tmOrderNo);
|
WeAppOrder selectByTmOrderId(String tmOrderNo);
|
||||||
|
List<WeAppOrder> selectTimeoutUnpaidOrder();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,14 @@
|
|||||||
|
|
||||||
<mapper namespace="org.chenyon.pay.WeAppOrderDao">
|
<mapper namespace="org.chenyon.pay.WeAppOrderDao">
|
||||||
<select id="findByBizId" resultType="WeAppOrder">
|
<select id="findByBizId" resultType="WeAppOrder">
|
||||||
select * from order where bizId = #{bizId};
|
select * from `weapp_order` where bizId = #{bizId}
|
||||||
</select>
|
</select>
|
||||||
<select id="selectByTmOrderId" resultType="WeAppOrder">
|
<select id="selectByTmOrderId" resultType="WeAppOrder">
|
||||||
select * from order where bizId = #{bizId};
|
select * from `weapp_order` where tmOrderId = #{tmOrderNo}
|
||||||
|
</select>
|
||||||
|
<select id="selectTimeoutUnpaidOrder" resultType="WeAppOrder">
|
||||||
|
select * from `weapp_order` where payStatus = '0'
|
||||||
|
and TIMESTAMPDIFF(MINUTE, createTime, NOW()) > 5
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
@@ -4,6 +4,7 @@ import org.rcy.framework.api.entity.BaseEntity;
|
|||||||
|
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "SUB_ORDER")
|
@Table(name = "SUB_ORDER")
|
||||||
@@ -13,6 +14,7 @@ public class WeAppSubOrder extends BaseEntity {
|
|||||||
private String amount;
|
private String amount;
|
||||||
private Long mainOrderId;
|
private Long mainOrderId;
|
||||||
private String payStatus;
|
private String payStatus;
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
public String getBillNo() {
|
public String getBillNo() {
|
||||||
return billNo;
|
return billNo;
|
||||||
@@ -53,4 +55,12 @@ public class WeAppSubOrder extends BaseEntity {
|
|||||||
public void setPayStatus(String payStatus) {
|
public void setPayStatus(String payStatus) {
|
||||||
this.payStatus = payStatus;
|
this.payStatus = payStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Date getCreateTime() {
|
||||||
|
return createTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreateTime(Date createTime) {
|
||||||
|
this.createTime = createTime;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ public interface WeAppSubOrderDao extends BaseDao<WeAppSubOrder> {
|
|||||||
|
|
||||||
WeAppSubOrder selectByBillNo(String billNo);
|
WeAppSubOrder selectByBillNo(String billNo);
|
||||||
|
|
||||||
|
WeAppSubOrder selectByBillNoForUpdate(String billNo);
|
||||||
|
|
||||||
List<WeAppSubOrder> selectByMainOrderId(Long mainOrderId);
|
List<WeAppSubOrder> selectByMainOrderId(Long mainOrderId);
|
||||||
|
|
||||||
Integer updateById(WeAppSubOrder subOrder);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,5 +3,13 @@
|
|||||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
|
||||||
<mapper namespace="org.chenyon.pay.WeAppSubOrderDao">
|
<mapper namespace="org.chenyon.pay.WeAppSubOrderDao">
|
||||||
|
<select id="selectByBillNo" resultType="WeAppSubOrder">
|
||||||
|
select * from sub_order where billNo = #{billNo}
|
||||||
|
</select>
|
||||||
|
<select id="selectByBillNoForUpdate" resultType="WeAppSubOrder">
|
||||||
|
select * from sub_order where billNo = #{billNo} FOR UPDATE
|
||||||
|
</select>
|
||||||
|
<select id="selectByMainOrderId" resultType="WeAppSubOrder">
|
||||||
|
select * from sub_order where mainOrderId = #{mainOrderId}
|
||||||
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
@@ -4,6 +4,9 @@ public class TmPayOrderRespVo {
|
|||||||
|
|
||||||
private String url;
|
private String url;
|
||||||
private MiniPayRequest miniPayRequest;
|
private MiniPayRequest miniPayRequest;
|
||||||
|
private Long mainOrderId;
|
||||||
|
private String status;
|
||||||
|
private String payTime;
|
||||||
|
|
||||||
public String getUrl() {
|
public String getUrl() {
|
||||||
return url;
|
return url;
|
||||||
@@ -20,4 +23,28 @@ public class TmPayOrderRespVo {
|
|||||||
public void setMiniPayRequest(MiniPayRequest miniPayRequest) {
|
public void setMiniPayRequest(MiniPayRequest miniPayRequest) {
|
||||||
this.miniPayRequest = miniPayRequest;
|
this.miniPayRequest = miniPayRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getMainOrderId() {
|
||||||
|
return mainOrderId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMainOrderId(Long mainOrderId) {
|
||||||
|
this.mainOrderId = mainOrderId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(String status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPayTime() {
|
||||||
|
return payTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPayTime(String payTime) {
|
||||||
|
this.payTime = payTime;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,30 +38,54 @@ public class LoginController {
|
|||||||
|
|
||||||
@PostMapping("/weChatLogin")
|
@PostMapping("/weChatLogin")
|
||||||
public ResultMessage weChatLogin(@RequestBody LoginVo loginVo) throws Exception{
|
public ResultMessage weChatLogin(@RequestBody LoginVo loginVo) throws Exception{
|
||||||
String accessToken = weChatAccessTokenService.getAccessToken();
|
// 1. 通过 code 获取微信 session_key + openid
|
||||||
WeChatAuthInfo sessionInfo = weChatApi.getSessionInfo(loginVo.getLoginCode());
|
WeChatAuthInfo sessionInfo = weChatApi.getSessionInfo(loginVo.getLoginCode());
|
||||||
|
|
||||||
|
// 2. 生成第三方会话 key
|
||||||
|
String thirdSessionKey = UUID.randomUUID().toString().replace("-", "");
|
||||||
|
|
||||||
|
// 3. 构建 session 对象(核心:设置2小时过期)
|
||||||
WxUserSession wxUserSession = new WxUserSession();
|
WxUserSession wxUserSession = new WxUserSession();
|
||||||
wxUserSession.setSessionKey(sessionInfo.getSession_key());
|
wxUserSession.setSessionKey(sessionInfo.getSession_key());
|
||||||
wxUserSession.setOpenId(sessionInfo.getOpenid());
|
wxUserSession.setOpenId(sessionInfo.getOpenid());
|
||||||
wxUserSession.setUnionid(sessionInfo.getUnionid());
|
wxUserSession.setUnionid(sessionInfo.getUnionid());
|
||||||
String thirdSessionKey = UUID.randomUUID().toString().replace("-", "");
|
|
||||||
wxUserSession.setThirdSession(thirdSessionKey);
|
wxUserSession.setThirdSession(thirdSessionKey);
|
||||||
String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + accessToken;
|
|
||||||
HttpResponse httpResponse = HttpRequestUtils.sendPost(url, "{\"code\":\"" + loginVo.getPhoneGetCode() + "\"}", null);
|
// ===================== 关键修复 =====================
|
||||||
String respStr = httpResponse.getRespStr();
|
// 过期时间:当前时间 + 2小时(微信session_key标准有效期)
|
||||||
Map<String, Object> respMap = JsonUtils.parseObject(respStr, Map.class);
|
wxUserSession.setExpiresAt(System.currentTimeMillis() + 7200 * 1000);
|
||||||
Map<String, Object> phoneInfo = (Map<String, Object>) respMap.get("phone_info");
|
// ====================================================
|
||||||
User user = new User();
|
|
||||||
if (phoneInfo != null) {
|
// 4. 获取用户手机号(安全获取,带异常处理)
|
||||||
String phoneNumber = (String) phoneInfo.get("purePhoneNumber");
|
String accessToken = weChatAccessTokenService.getAccessToken();
|
||||||
|
String phoneNumber = null;
|
||||||
|
try {
|
||||||
|
String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + accessToken;
|
||||||
|
HttpResponse httpResponse = HttpRequestUtils.sendPost(url, "{\"code\":\"" + loginVo.getPhoneGetCode() + "\"}", null);
|
||||||
|
String respStr = httpResponse.getRespStr();
|
||||||
|
Map<String, Object> respMap = JsonUtils.parseObject(respStr, Map.class);
|
||||||
|
Map<String, Object> phoneInfo = (Map<String, Object>) respMap.get("phone_info");
|
||||||
|
if (phoneInfo != null) {
|
||||||
|
phoneNumber = (String) phoneInfo.get("purePhoneNumber");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("获取微信手机号失败", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 保存/更新用户
|
||||||
|
if (phoneNumber != null) {
|
||||||
|
User user = new User();
|
||||||
user.setOpenId(sessionInfo.getOpenid());
|
user.setOpenId(sessionInfo.getOpenid());
|
||||||
user.setPhone(phoneNumber);
|
user.setPhone(phoneNumber);
|
||||||
user.setUserType(loginVo.getLoginType());
|
user.setUserType(loginVo.getLoginType());
|
||||||
userService.upsert(user);
|
userService.upsert(user);
|
||||||
}
|
}
|
||||||
wxUserSessionService.upsertWxUserSession(wxUserSession);
|
|
||||||
return ResultMessage.success(wxUserSession.getThirdSession());
|
|
||||||
|
|
||||||
|
// 6. 保存会话(你原来的 upsert 会自动更新)
|
||||||
|
wxUserSessionService.upsertWxUserSession(wxUserSession);
|
||||||
|
|
||||||
|
// 7. 返回 thirdSession 给前端
|
||||||
|
return ResultMessage.success(wxUserSession.getThirdSession());
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/checkExpiration")
|
@GetMapping("/checkExpiration")
|
||||||
@@ -103,9 +127,9 @@ public class LoginController {
|
|||||||
public ResultMessage updateVerifyCode(HttpServletRequest request,@RequestBody AuthInfoVo authInfoVo) throws Exception {
|
public ResultMessage updateVerifyCode(HttpServletRequest request,@RequestBody AuthInfoVo authInfoVo) throws Exception {
|
||||||
String token = request.getHeader("WT");
|
String token = request.getHeader("WT");
|
||||||
WxUserSession wxUserSession = wxUserSessionService.getSessionInfoByThirdSession(token);
|
WxUserSession wxUserSession = wxUserSessionService.getSessionInfoByThirdSession(token);
|
||||||
userService.updateAuthInfo(wxUserSession.getOpenId(),
|
boolean authSuccess = userService.updateAuthInfo(wxUserSession.getOpenId(),
|
||||||
authInfoVo.getUserType(),
|
authInfoVo.getUserType(),
|
||||||
"0".equals(authInfoVo.getUserType()) ? RSAUtil.decrypt(authInfoVo.getCode(),rasPrivateKey) : authInfoVo.getCode());
|
"0".equals(authInfoVo.getUserType()) ? RSAUtil.decrypt(authInfoVo.getCode(),rasPrivateKey) : authInfoVo.getCode());
|
||||||
return ResultMessage.success();
|
return ResultMessage.success(authSuccess);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ public class UserService {
|
|||||||
return userVo;
|
return userVo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateAuthInfo(String openId,String userType,String verifyCode) throws Exception {
|
public boolean updateAuthInfo(String openId,String userType,String verifyCode) throws Exception {
|
||||||
//调用oa接口客商信息
|
//调用oa接口客商信息
|
||||||
User user = userDao.findByOpenIdAndUserType(openId, userType);
|
User user = userDao.findByOpenIdAndUserType(openId, userType);
|
||||||
if(user == null) {
|
if(user == null) {
|
||||||
@@ -76,7 +76,7 @@ public class UserService {
|
|||||||
}
|
}
|
||||||
String cusNo = null;
|
String cusNo = null;
|
||||||
if("0".equals(userType)) {
|
if("0".equals(userType)) {
|
||||||
CusVo cusVo = oaCusService.matchPersonCus(user.getPhone());
|
CusVo cusVo = oaCusService.matchPersonCus(verifyCode);
|
||||||
cusNo = cusVo == null ? null : cusVo.getCusNo();
|
cusNo = cusVo == null ? null : cusVo.getCusNo();
|
||||||
user.setCardNo(AESUtils.encrypt(verifyCode,"abc123"));
|
user.setCardNo(AESUtils.encrypt(verifyCode,"abc123"));
|
||||||
}else if("1".equals(user.getUserType())) {
|
}else if("1".equals(user.getUserType())) {
|
||||||
@@ -89,5 +89,6 @@ public class UserService {
|
|||||||
user.setOaAuth(true);
|
user.setOaAuth(true);
|
||||||
userDao.updateByPrimaryKeySelective(user);
|
userDao.updateByPrimaryKeySelective(user);
|
||||||
}
|
}
|
||||||
|
return cusNo != null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,14 +53,17 @@ public class WeChatAccessTokenService {
|
|||||||
HttpResponse response = HttpRequestUtils.sendGet(url, headers);
|
HttpResponse response = HttpRequestUtils.sendGet(url, headers);
|
||||||
Map respMap = JsonUtils.parseObject(response.getRespStr(), Map.class);
|
Map respMap = JsonUtils.parseObject(response.getRespStr(), Map.class);
|
||||||
if (respMap.get("errcode") != null) {
|
if (respMap.get("errcode") != null) {
|
||||||
throw new IOException("获取 access_token 请求失败: " + respMap.get("errmsg"));
|
log.error("获取access_token失败: {}", respMap);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
String tokenStr = respMap.get("access_token") + "";
|
String tokenStr = respMap.get("access_token") + "";
|
||||||
long ttl = Long.parseLong(respMap.get("expires_in") + "");
|
long ttl = Long.parseLong(respMap.get("expires_in") + "");
|
||||||
|
// 提前 100 秒过期,更安全
|
||||||
WxTokenCache tokenCache = new WxTokenCache();
|
WxTokenCache tokenCache = new WxTokenCache();
|
||||||
tokenCache.setToken(tokenStr);
|
tokenCache.setToken(tokenStr);
|
||||||
tokenCache.setExpireTime(now + (ttl - 20000));
|
tokenCache.setExpireTime(now + (ttl - 100) * 1000);
|
||||||
cache.put(appId, tokenCache);
|
cache.put(appId, tokenCache);
|
||||||
|
|
||||||
return tokenStr;
|
return tokenStr;
|
||||||
}catch (Exception e){
|
}catch (Exception e){
|
||||||
log.error(e.getMessage(),e);
|
log.error(e.getMessage(),e);
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ public class WxUserSession extends BaseEntity {
|
|||||||
|
|
||||||
private String unionid;
|
private String unionid;
|
||||||
|
|
||||||
|
private Long expiresAt; // 会话过期时间戳(毫秒)
|
||||||
|
|
||||||
public String getOpenId() {
|
public String getOpenId() {
|
||||||
return openId;
|
return openId;
|
||||||
}
|
}
|
||||||
@@ -69,4 +71,12 @@ public class WxUserSession extends BaseEntity {
|
|||||||
public void setUnionid(String unionid) {
|
public void setUnionid(String unionid) {
|
||||||
this.unionid = unionid;
|
this.unionid = unionid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getExpiresAt() {
|
||||||
|
return expiresAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpiresAt(Long expiresAt) {
|
||||||
|
this.expiresAt = expiresAt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,28 +42,54 @@ public class WxUserSessionService {
|
|||||||
return wxUserSession;
|
return wxUserSession;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验session是否过期 + 自动续期(纯数据库版)
|
||||||
|
* 返回 true = 过期
|
||||||
|
* 返回 false = 有效(且会自动续期)
|
||||||
|
*/
|
||||||
public Boolean sessionIsExpired(String thirdSession) {
|
public Boolean sessionIsExpired(String thirdSession) {
|
||||||
try {
|
if (thirdSession == null || thirdSession.isEmpty()) {
|
||||||
WxUserSession session = wxUserSessionDao.findByThirdSession(thirdSession);
|
return true;
|
||||||
if(session == null) {
|
}
|
||||||
return true;
|
|
||||||
}
|
try {
|
||||||
String accessToken = tokenService.getAccessToken();
|
// 1. 查数据库
|
||||||
String url = "https://api.weixin.qq.com/wxa/checksession?access_token=" + accessToken + "&signature=" + HmacSha256Util.hmacSha256Hex("",session.getSessionKey()) + "&openid=" + session.getOpenId() +"&sig_method=hmac_sha256";
|
WxUserSession session = wxUserSessionDao.findByThirdSession(thirdSession);
|
||||||
HttpResponse response = HttpRequestUtils.sendGet(url, null);
|
if (session == null) {
|
||||||
if(response.getCode() != 200) {
|
return true;
|
||||||
return true;
|
}
|
||||||
}
|
|
||||||
Map<String,Object> map = JsonUtils.parseObject(response.getRespStr(), Map.class);
|
Long now = System.currentTimeMillis();
|
||||||
if((Integer) map.get("errcode") == 0) {
|
Long expiresAt = session.getExpiresAt();
|
||||||
return false;
|
|
||||||
}else {
|
// 2. 已经过期
|
||||||
return true;
|
if (expiresAt == null || expiresAt <= now) {
|
||||||
}
|
return true;
|
||||||
}catch (Exception e) {
|
}
|
||||||
log.error(e.getMessage(),e);
|
|
||||||
|
// ===================== 自动续期逻辑 =====================
|
||||||
|
// 规则:如果剩余时间 < 30分钟,自动续期 2小时
|
||||||
|
long remainTime = expiresAt - now;
|
||||||
|
long thirtyMinutes = 30 * 60 * 1000; // 30分钟
|
||||||
|
|
||||||
|
if (remainTime < thirtyMinutes) {
|
||||||
|
// 新过期时间 = 当前 + 2小时
|
||||||
|
long newExpiresAt = now + 7200 * 1000;
|
||||||
|
session.setExpiresAt(newExpiresAt);
|
||||||
|
|
||||||
|
// 更新数据库
|
||||||
|
wxUserSessionDao.updateByPrimaryKeySelective(session);
|
||||||
|
log.info("thirdSession自动续期成功:{}", thirdSession);
|
||||||
|
}
|
||||||
|
// ==========================================================
|
||||||
|
|
||||||
|
// 3. 有效
|
||||||
|
return false;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("session校验&续期异常", e);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public CusVo matchCus(String phone, String orgNo, String loginType) throws Exception {
|
public CusVo matchCus(String phone, String orgNo, String loginType) throws Exception {
|
||||||
|
|||||||
@@ -1,19 +1,102 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
# ====================== 配置项(你只需要改这里)======================
|
||||||
APP_NAME=/usr/local/qichenrent/qichenrent.jar
|
APP_NAME=/usr/local/qichenrent/qichenrent.jar
|
||||||
CONFIG_DIR=file:/usr/local/qichenrent/config/
|
CONFIG_DIR=/usr/local/qichenrent/config/
|
||||||
LOG_DIR=/usr/local/qichenrent/logs
|
LOG_DIR=/usr/local/qichenrent/logs
|
||||||
PID_FILE=/usr/local/qichenrent/qichenrent.pid
|
PID_FILE=/usr/local/qichenrent/qichenrent.pid
|
||||||
JAVA_OPTS="-Xms512m -Xmx1024m -Dfile.encoding=UTF-8"
|
JAVA_OPTS="-Xms512m -Xmx1024m -Dfile.encoding=UTF-8"
|
||||||
|
# ====================================================================
|
||||||
|
|
||||||
|
# 创建目录
|
||||||
mkdir -p $LOG_DIR
|
mkdir -p $LOG_DIR
|
||||||
|
mkdir -p $CONFIG_DIR
|
||||||
|
|
||||||
echo "Starting $APP_NAME ..."
|
# 获取当前PID
|
||||||
|
get_pid() {
|
||||||
|
if [ -f "$PID_FILE" ]; then
|
||||||
|
cat $PID_FILE
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
nohup java $JAVA_OPTS -jar $APP_NAME \
|
# 检查是否正在运行
|
||||||
--spring.config.additional-location=$CONFIG_DIR \
|
is_running() {
|
||||||
> $LOG_DIR/console.log 2>&1 &
|
pid=$(get_pid)
|
||||||
|
if [ -n "$pid" ] && ps -p $pid > /dev/null 2>&1; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
echo $! > $PID_FILE
|
# 启动
|
||||||
|
start() {
|
||||||
|
if is_running; then
|
||||||
|
echo "应用已启动,PID=$(get_pid),无需重复启动"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Application started, PID=$(cat $PID_FILE)"
|
echo "正在启动应用:$APP_NAME ..."
|
||||||
|
|
||||||
|
# 后台启动 SpringBoot
|
||||||
|
nohup java $JAVA_OPTS -jar $APP_NAME \
|
||||||
|
--spring.config.additional-location=file:$CONFIG_DIR \
|
||||||
|
> $LOG_DIR/console.log 2>&1 &
|
||||||
|
|
||||||
|
# 记录PID
|
||||||
|
echo $! > $PID_FILE
|
||||||
|
sleep 1
|
||||||
|
echo "应用启动成功!PID=$(get_pid)"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 停止
|
||||||
|
stop() {
|
||||||
|
if ! is_running; then
|
||||||
|
echo "应用未运行"
|
||||||
|
rm -f $PID_FILE
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
pid=$(get_pid)
|
||||||
|
echo "正在停止应用,PID=$pid ..."
|
||||||
|
kill -15 $pid
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
# 强制kill
|
||||||
|
if ps -p $pid > /dev/null 2>&1; then
|
||||||
|
kill -9 $pid
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f $PID_FILE
|
||||||
|
echo "应用已停止"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 状态
|
||||||
|
status() {
|
||||||
|
if is_running; then
|
||||||
|
echo "应用运行中,PID=$(get_pid)"
|
||||||
|
else
|
||||||
|
echo "应用未运行"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# 命令入口
|
||||||
|
case "$1" in
|
||||||
|
start)
|
||||||
|
start
|
||||||
|
;;
|
||||||
|
stop)
|
||||||
|
stop
|
||||||
|
;;
|
||||||
|
restart)
|
||||||
|
stop
|
||||||
|
start
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
status
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "用法:$0 {start|stop|restart|status}"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
Reference in New Issue
Block a user