工单新增提醒与强制办结;新增普通微信支付;添加线索渠道
This commit is contained in:
parent
28759c5d68
commit
7cf5e83e4c
@ -1,11 +1,13 @@
|
||||
package com.cpop.core.utils;
|
||||
|
||||
import com.cpop.core.base.exception.UtilException;
|
||||
import org.quartz.*;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
@ -30,7 +32,11 @@ public class QuartzUtils {
|
||||
*/
|
||||
public String getJobInfo(String name, String group) throws SchedulerException {
|
||||
TriggerKey triggerKey = new TriggerKey(name, group);
|
||||
CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
|
||||
Trigger trigger = scheduler.getTrigger(triggerKey);
|
||||
if (trigger == null) {
|
||||
throw new UtilException("获取定时任务失败");
|
||||
}
|
||||
CronTrigger cronTrigger = (CronTrigger) trigger;
|
||||
return String.format("time:%s,state:%s", cronTrigger.getCronExpression(),
|
||||
scheduler.getTriggerState(triggerKey).name());
|
||||
}
|
||||
@ -47,15 +53,20 @@ public class QuartzUtils {
|
||||
public boolean modifyJob(String name, String group, String time) throws SchedulerException {
|
||||
Date date = null;
|
||||
TriggerKey triggerKey = new TriggerKey(name, group);
|
||||
CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
|
||||
String oldTime = cronTrigger.getCronExpression();
|
||||
if (!oldTime.equalsIgnoreCase(time)) {
|
||||
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(time);
|
||||
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(name, group)
|
||||
.withSchedule(cronScheduleBuilder).build();
|
||||
date = scheduler.rescheduleJob(triggerKey, trigger);
|
||||
Trigger triggerResult = scheduler.getTrigger(triggerKey);
|
||||
if (triggerResult != null) {
|
||||
CronTrigger cronTrigger = (CronTrigger) triggerResult;
|
||||
String oldTime = cronTrigger.getCronExpression();
|
||||
if (!oldTime.equalsIgnoreCase(time)) {
|
||||
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(time);
|
||||
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(name, group)
|
||||
.withSchedule(cronScheduleBuilder).build();
|
||||
date = scheduler.rescheduleJob(triggerKey, trigger);
|
||||
}
|
||||
return date != null;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return date != null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -156,4 +167,17 @@ public class QuartzUtils {
|
||||
"? " + year;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取任务执行时间
|
||||
* @author DB
|
||||
* @since 2024/2/22
|
||||
* @param name
|
||||
* @param group
|
||||
* @return LocalDateTime
|
||||
*/
|
||||
public LocalDateTime getJobExecuteTime(String name, String group) throws SchedulerException {
|
||||
String jobInfo = getJobInfo(name, group);
|
||||
String[] split = jobInfo.split(",")[0].replaceAll("time:", "").split(" ");
|
||||
return LocalDateTime.of(Integer.parseInt(split[6]), Integer.parseInt(split[4]), Integer.parseInt(split[3]), Integer.parseInt(split[2]), Integer.parseInt(split[1]), Integer.parseInt(split[0]));
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,6 +10,9 @@ import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* @author DB
|
||||
* @version 1.0.0
|
||||
@ -74,4 +77,14 @@ public class CallBackEasyLearnController {
|
||||
easyLearnOrderService.unionPayResult(xmlData);
|
||||
return WxPayNotifyResponse.success("成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信支付联合支付普通订单通知
|
||||
* @return java.lang.String
|
||||
*/
|
||||
@ApiOperation("微信支付联合支付普通订单通知")
|
||||
@PostMapping("/notify/normalUnionPay")
|
||||
public String normalUnionPay(HttpServletRequest request, HttpServletResponse response){
|
||||
return easyLearnOrderService.normalUnionPay(request,response);
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,6 +9,8 @@ import com.github.binarywang.wxpay.bean.payscore.WxPartnerPayScoreUserSignPlanRe
|
||||
import com.mybatisflex.core.paginate.Page;
|
||||
import com.mybatisflex.core.service.IService;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -125,4 +127,12 @@ public interface EasyLearnOrderService extends IService<EasyLearnOrder> {
|
||||
* @param phone 手机号
|
||||
*/
|
||||
void sendEcppMsmCode(String phone);
|
||||
|
||||
/**
|
||||
* 微信支付联合支付普通订单通知
|
||||
* @author DB
|
||||
* @since 2024/2/22
|
||||
* @return String
|
||||
*/
|
||||
String normalUnionPay(HttpServletRequest request, HttpServletResponse response);
|
||||
}
|
||||
|
||||
@ -29,6 +29,8 @@ import com.cpop.pay.framewok.core.request.ecpp.EcppSmsCodeRequest;
|
||||
import com.cpop.pay.framewok.core.response.ecpp.EcppSmsCodeResponse;
|
||||
import com.cpop.pay.framewok.handler.ecpp.EcppHandler;
|
||||
import com.cpop.pay.framewok.handler.wxPay.WxPayHandler;
|
||||
import com.cpop.pay.framewok.handler.wxPay.WxPayNormalHandler;
|
||||
import com.cpop.pay.framewok.handler.wxPay.WxUtils;
|
||||
import com.cpop.pay.framewok.task.WxPayAsyncTask;
|
||||
import com.cpop.system.business.entity.Store;
|
||||
import com.cpop.system.business.entity.WxPayScore;
|
||||
@ -62,12 +64,16 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
import static com.cpop.jambox.business.entity.table.BrandExtendTableDef.BRAND_EXTEND;
|
||||
@ -529,6 +535,16 @@ public class EasyLearnOrderServiceImpl extends ServiceImpl<EasyLearnOrderMapper,
|
||||
*/
|
||||
private final String UNION_PAY_TEST_NOTIFY_URL = "https://test.cpopsz.com/Cpop-Oam/callback/easyLearn/notify/unionPay";
|
||||
|
||||
/**
|
||||
* 联合支付回调地址(本地内网穿透)
|
||||
*/
|
||||
private final String UNION_PAY_DEV_NORMAL_NOTIFY_URL = "https://frp-bid.top:60778/Cpop-Oam/callback/easyLearn/notify/normalUnionPay";
|
||||
|
||||
/**
|
||||
* 联合支付回调地址(测试地址)
|
||||
*/
|
||||
private final String UNION_PAY_TEST_NORMAL_NOTIFY_URL = "https://test.cpopsz.com/Cpop-Oam/callback/easyLearn/notify/normalUnionPay";
|
||||
|
||||
/**
|
||||
* 放心学统一支付
|
||||
* @author DB
|
||||
@ -544,6 +560,7 @@ public class EasyLearnOrderServiceImpl extends ServiceImpl<EasyLearnOrderMapper,
|
||||
//分布式锁进行幂等处理
|
||||
Lock userIdLock = redisService.distributedLock(JamboxRedisConstant.ONCE_PAY_LOCK_USER_PAY + bo.getCustomerPhone());
|
||||
if (userIdLock.tryLock()) {
|
||||
WxPayService wxPayService = null;
|
||||
try {
|
||||
//创建订单
|
||||
EasyLearnOrder easyLearnOrder = BeanUtils.mapToClass(bo, EasyLearnOrder.class);
|
||||
@ -573,22 +590,34 @@ public class EasyLearnOrderServiceImpl extends ServiceImpl<EasyLearnOrderMapper,
|
||||
payNotifyUrl = UNION_PAY_DEV_NOTIFY_URL;
|
||||
}
|
||||
//获取商户信息
|
||||
WxPayService wxPayService = wxPayHandler.getWxPayService(null, wxPayHandler.getSubMchId(easyLearnOrder.getBrandId(), easyLearnOrder.getStoreId()), payNotifyUrl);
|
||||
WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
|
||||
//需要分账
|
||||
if (easyLearnOrder.getRate() != null && easyLearnOrder.getTotalAmount().scaleByPowerOfTen(2).intValue() >= Math.ceil(1 / easyLearnOrder.getRate())) {
|
||||
wxPayService = wxPayHandler.getWxPayService(null, wxPayHandler.getSubMchId(easyLearnOrder.getBrandId(), easyLearnOrder.getStoreId()), payNotifyUrl);
|
||||
if (StringUtils.isBlank(wxPayService.getConfig().getSubMchId())){
|
||||
if (StringUtils.equals("prod", SpringUtils.getActiveProfile())) {
|
||||
//联合支付
|
||||
payNotifyUrl = SpringUtils.getBean(WxPayConfiguration.class).getProperties().getEasyLearnUnionPayNormalNotifyUrl();
|
||||
} else if (StringUtils.equals("test", SpringUtils.getActiveProfile())){
|
||||
payNotifyUrl = UNION_PAY_TEST_NORMAL_NOTIFY_URL;
|
||||
} else {
|
||||
payNotifyUrl = UNION_PAY_DEV_NORMAL_NOTIFY_URL;
|
||||
}
|
||||
return SpringUtils.getBean(WxPayNormalHandler.class).createOrder(easyLearnOrder.getId(),bo.getOpenId(), easyLearnOrder.getTotalPayAmount(), "联合支付", IpUtils.getHostIp(), payNotifyUrl);
|
||||
} else {
|
||||
WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
|
||||
//需要分账
|
||||
orderRequest.setProfitSharing("Y");
|
||||
if (easyLearnOrder.getRate() != null && easyLearnOrder.getTotalAmount().scaleByPowerOfTen(2).intValue() >= Math.ceil(1 / easyLearnOrder.getRate())) {
|
||||
//需要分账
|
||||
orderRequest.setProfitSharing("Y");
|
||||
}
|
||||
orderRequest.setSpbillCreateIp(IpUtils.getHostIp())
|
||||
.setOpenid(bo.getOpenId())
|
||||
//商品描述
|
||||
.setBody("联合支付")
|
||||
.setOutTradeNo(easyLearnOrder.getId())
|
||||
//元转分
|
||||
.setTotalFee(easyLearnOrder.getTotalAmount().scaleByPowerOfTen(2).intValue())
|
||||
.setTradeType("JSAPI");
|
||||
return wxPayService.createOrder(orderRequest);
|
||||
}
|
||||
orderRequest.setSpbillCreateIp(IpUtils.getHostIp())
|
||||
.setOpenid(bo.getOpenId())
|
||||
//商品描述
|
||||
.setBody("联合支付")
|
||||
.setOutTradeNo(easyLearnOrder.getId())
|
||||
//元转分
|
||||
.setTotalFee(easyLearnOrder.getTotalAmount().scaleByPowerOfTen(2).intValue())
|
||||
.setTradeType("JSAPI");
|
||||
return wxPayService.createOrder(orderRequest);
|
||||
} catch (Exception e) {
|
||||
throw new ServiceException(e.getMessage());
|
||||
} finally {
|
||||
@ -1005,4 +1034,60 @@ public class EasyLearnOrderServiceImpl extends ServiceImpl<EasyLearnOrderMapper,
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信支付联合支付普通订单通知
|
||||
* @author DB
|
||||
* @since 2024/2/22
|
||||
* @return String
|
||||
*/
|
||||
@Override
|
||||
public String normalUnionPay(HttpServletRequest request, HttpServletResponse response) {
|
||||
WxPayNormalHandler wxPayNormalHandler = SpringUtils.getBean(WxPayNormalHandler.class);
|
||||
// 预先设定返回的 response 类型为 xml
|
||||
response.setHeader("Content-type", "application/xml");
|
||||
WxUtils wxUtils = SpringUtils.getBean(WxUtils.class);
|
||||
// 读取参数,解析Xml为map
|
||||
Map<String, String> map = null;
|
||||
Response okResponse = null;
|
||||
try {
|
||||
map = wxUtils.transferXmlToMap(wxUtils.readRequest(request));
|
||||
// 转换为有序 map,判断签名是否正确
|
||||
boolean isSignSuccess = wxUtils.checkSign(new TreeMap<String, Object>(map), "JamBox20220329174000000000000002");
|
||||
if (isSignSuccess) {
|
||||
// 签名校验成功,说明是微信服务器发出的数据
|
||||
String orderId = map.get("out_trade_no");
|
||||
//获取订单信息
|
||||
EasyLearnOrder easyLearnOrder = this.getById(orderId);
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
EasyLearnPayPayEnum easyLearnPayPayEnum = EasyLearnPayPayEnum.getEasyLearnPayPayEnum(easyLearnOrder.getOrderType());
|
||||
jsonObject.put("wxOrderId", easyLearnOrder.getId());
|
||||
jsonObject.put("unionPayOutOrderId", easyLearnOrder.getUnionPayOutOrderId());
|
||||
jsonObject.put("easyLearnUnionPay", easyLearnPayPayEnum.toString());
|
||||
String url;
|
||||
if (StringUtils.equals("prod", SpringUtils.getActiveProfile())) {
|
||||
url = UNION_PAY_PROD_JAMBOX_NOTIFY_URL;
|
||||
} else if (StringUtils.equals("test", SpringUtils.getActiveProfile())) {
|
||||
url = UNION_PAY_TEST_JAMBOX_NOTIFY_URL;
|
||||
} else {
|
||||
url = UNION_PAY_DEV_JAMBOX_NOTIFY_URL;
|
||||
}
|
||||
//通知晖哥
|
||||
okResponse = HttpUtils.sendOkHttpPost(url, jsonObject.toJSONString());
|
||||
//更新订单
|
||||
this.updateChain().set(EASY_LEARN_ORDER.OUT_ORDER_NO, map.get("transaction_id"))
|
||||
.set(EASY_LEARN_ORDER.ORDER_STATUS, 1)
|
||||
.where(EASY_LEARN_ORDER.ID.eq(orderId)).update();
|
||||
return wxPayNormalHandler.success();
|
||||
} else {
|
||||
// 签名校验失败(可能不是微信服务器发出的数据)
|
||||
return wxPayNormalHandler.fail();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return wxPayNormalHandler.fail();
|
||||
} finally {
|
||||
assert okResponse != null;
|
||||
okResponse.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,4 +3,6 @@ wx:
|
||||
#支付通知地址
|
||||
easy-learn-once-pay-notify-url: https://oamapi.cpopsz.com/Cpop-Oam/callback/easyLearn/notify/oncePay
|
||||
#放心学联合支付
|
||||
easy-learn-union-pay-notify-url: https://oamapi.cpopsz.com/Cpop-Oam/callback/easyLearn/notify/unionPay
|
||||
easy-learn-union-pay-notify-url: https://oamapi.cpopsz.com/Cpop-Oam/callback/easyLearn/notify/unionPay
|
||||
#放心学普通支付
|
||||
easy-learn-union-pay-normal-notify-url: https://oamapi.cpopsz.com/Cpop-Oam/callback/easyLearn/notify/normalUnionPay
|
||||
@ -137,7 +137,7 @@ public class CpopWxPayTests {
|
||||
public void getOrderInfo() throws WxPayException {
|
||||
WxPayConfig config = wxPayService.getConfig();
|
||||
config.setSubMchId("1661323640");
|
||||
WxPayOrderQueryResult wxPayOrderQueryResult = wxPayService.queryOrder("4200002096202402199975156147", null);
|
||||
WxPayOrderQueryResult wxPayOrderQueryResult = wxPayService.queryOrder("4200002123202312279635916930", null);
|
||||
System.out.println(JSONObject.toJSONString(wxPayOrderQueryResult));
|
||||
}
|
||||
|
||||
@ -150,7 +150,7 @@ public class CpopWxPayTests {
|
||||
@Test
|
||||
public void getSharingInfo() throws WxPayException {
|
||||
ProfitSharingQueryRequest profitSharingQueryRequest = new ProfitSharingQueryRequest();
|
||||
profitSharingQueryRequest.setOutOrderNo("1736629608413073417").setTransactionId("4200002111202402019716818254");
|
||||
profitSharingQueryRequest.setOutOrderNo("1736629608413073417").setTransactionId("4200002123202312279635916930");
|
||||
profitSharingQueryRequest.setSubMchId("1661323640");
|
||||
ProfitSharingQueryResult result = wxPayService.getProfitSharingService().profitSharingQuery(profitSharingQueryRequest);
|
||||
System.out.println(result.getResultCode());
|
||||
|
||||
@ -328,8 +328,8 @@ public class CpopEasyLearnTest {
|
||||
|
||||
@Test
|
||||
public void queryOrder() throws WxPayException {
|
||||
WxPayService wxPayService = wxPayHandler.getWxPayService(null, "1661323640");
|
||||
WxPayOrderQueryResult wxPayOrderQueryResult = wxPayService.queryOrder("4200002111202401103536519415",null);
|
||||
WxPayService wxPayService = wxPayHandler.getWxPayService(null, "1666928264");
|
||||
WxPayOrderQueryResult wxPayOrderQueryResult = wxPayService.queryOrder("4200002130202402224927801847",null);
|
||||
System.out.println(JSONObject.toJSONString(wxPayOrderQueryResult));
|
||||
|
||||
}
|
||||
|
||||
@ -5,11 +5,16 @@ import com.cpop.core.utils.SpringUtils;
|
||||
import com.cpop.oam.business.entity.Task;
|
||||
import com.cpop.oam.business.service.TaskService;
|
||||
import com.cpop.oam.business.service.TaskStaffGroupService;
|
||||
import com.cpop.oam.framework.enums.QuartzEnums;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static com.cpop.oam.business.entity.table.TaskStaffGroupTableDef.TASK_STAFF_GROUP;
|
||||
|
||||
/**
|
||||
@ -63,4 +68,10 @@ public class CpopQrtzTest {
|
||||
.update();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getJobInfo() throws SchedulerException {
|
||||
LocalDateTime jobExecuteTime = quartzUtils.getJobExecuteTime(QuartzEnums.WORK_ORDER_OVERTIME_TASK.getName() + "118089232185462784", QuartzEnums.WORK_ORDER_OVERTIME_TASK.getGroup());
|
||||
System.out.println(jobExecuteTime);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
package com.cpop.oam.business.bo;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* @author DB
|
||||
* @version 1.0.0
|
||||
* @since 2024-02-21 18:27
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@ApiModel(value = "AgreeOrRejectEnforceFinishBo对象")
|
||||
public class AgreeOrRejectEnforceFinishBo {
|
||||
|
||||
/**
|
||||
* 工单id
|
||||
*/
|
||||
@ApiModelProperty(value = "工单id")
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 同意或拒绝
|
||||
*/
|
||||
@ApiModelProperty(value = "同意或拒绝")
|
||||
private Boolean agreeOrReject;
|
||||
}
|
||||
@ -53,8 +53,9 @@ public class BackstageClueController {
|
||||
@ApiParam(value = "品牌") @RequestParam(value = "brandId", required = false) String brandId,
|
||||
@ApiParam(value = "校区") @RequestParam(value = "storeId", required = false) String storeId,
|
||||
@ApiParam(value = "负责人或手机号") @RequestParam(value = "chargeOrPhone", required = false) String chargeOrPhone,
|
||||
@ApiParam(value = "员工id") @RequestParam(value = "staffId", required = false) String staffId) {
|
||||
Page<CluePageVo> pageVo = clueService.getPersonCluePage(clueStatus, city, brandId, storeId, chargeOrPhone, staffId);
|
||||
@ApiParam(value = "员工id") @RequestParam(value = "staffId", required = false) String staffId,
|
||||
@ApiParam(value = "签约月份") @RequestParam(value = "signMonth", required = false) String signMonth) {
|
||||
Page<CluePageVo> pageVo = clueService.getPersonCluePage(clueStatus, city, brandId, storeId, chargeOrPhone, staffId, signMonth);
|
||||
return R.ok(pageVo);
|
||||
}
|
||||
|
||||
@ -98,11 +99,12 @@ public class BackstageClueController {
|
||||
@GetMapping("/getClueFollowUpRecord")
|
||||
public R<List<ClueFollowUpRecordVo>> getClueFollowUpRecord(@ApiParam(value = "线索id") @RequestParam(value = "clueId") String clueId) {
|
||||
List<ClueFollowUpRecordVo> vos = clueRecordService.listAs(QueryWrapper.create()
|
||||
.select(CLUE_RECORD.CREATE_TIME,CLUE_RECORD.RECORD_CONTENT,CLUE_RECORD.RECORD_FILE_URL)
|
||||
.select(CLUE_RECORD.CREATE_TIME, CLUE_RECORD.RECORD_CONTENT, CLUE_RECORD.RECORD_FILE_URL)
|
||||
.select(STAFF.NAME.as(ClueFollowUpRecordVo::getStaffName))
|
||||
.leftJoin(STAFF).on(STAFF.ID.eq(CLUE_RECORD.RECORD_STAFF_ID))
|
||||
.where(CLUE_RECORD.RECORD_TYPE.eq(2)
|
||||
.and(CLUE_RECORD.CLUE_ID.eq(clueId))),
|
||||
.and(CLUE_RECORD.CLUE_ID.eq(clueId)))
|
||||
.orderBy(CLUE_RECORD.CREATE_TIME.desc()),
|
||||
ClueFollowUpRecordVo.class);
|
||||
return R.ok(vos);
|
||||
}
|
||||
@ -118,8 +120,9 @@ public class BackstageClueController {
|
||||
@GetMapping("/getClueRecordList")
|
||||
public R<List<ClueRecordVo>> getClueRecordList(@ApiParam(value = "线索id") @RequestParam(value = "clueId") String clueId) {
|
||||
List<ClueRecordVo> vos = clueRecordService.listAs(QueryWrapper.create()
|
||||
.select(CLUE_RECORD.CREATE_TIME, CLUE_RECORD.RECORD_CONTENT)
|
||||
.and(CLUE_RECORD.CLUE_ID.eq(clueId)),
|
||||
.select(CLUE_RECORD.CREATE_TIME, CLUE_RECORD.RECORD_CONTENT,CLUE_RECORD.RECORD_TYPE)
|
||||
.and(CLUE_RECORD.CLUE_ID.eq(clueId))
|
||||
.orderBy(CLUE_RECORD.CREATE_TIME.desc()),
|
||||
ClueRecordVo.class);
|
||||
return R.ok(vos);
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ package com.cpop.oam.business.controller.backstage;
|
||||
|
||||
import com.cpop.core.base.R;
|
||||
import com.cpop.jambox.business.vo.BrandListVo;
|
||||
import com.cpop.oam.business.bo.AgreeOrRejectEnforceFinishBo;
|
||||
import com.cpop.oam.business.bo.PauseWorkOrderBo;
|
||||
import com.cpop.oam.business.bo.TaskWorkOrderBo;
|
||||
import com.cpop.oam.business.bo.TaskWorkOrderRecordBo;
|
||||
@ -217,4 +218,18 @@ public class BackstageTaskWorkOrderController {
|
||||
Page<TaskWorkOrderStatPageVo> page = taskWorkOrderService.getWorkOrderStatPage(staffId, startDate, endDate);
|
||||
return R.ok(page);
|
||||
}
|
||||
|
||||
/**
|
||||
* 同意与拒绝强制办结
|
||||
* @author DB
|
||||
* @since 2024/2/21
|
||||
* @param bo 请求参数
|
||||
* @return R<Void>
|
||||
*/
|
||||
@ApiOperation("工单模块-工单提交-同意与拒绝强制办结")
|
||||
@PutMapping("/agreeOrRejectEnforceFinish")
|
||||
public R<Void> agreeOrRejectEnforceFinish(@RequestBody @Validated AgreeOrRejectEnforceFinishBo bo) {
|
||||
taskWorkOrderService.agreeOrRejectEnforceFinish(bo);
|
||||
return R.ok();
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package com.cpop.oam.business.entity;
|
||||
import com.cpop.core.base.entity.BaseEntity;
|
||||
import com.cpop.core.base.entity.BaseInsertListener;
|
||||
import com.cpop.core.base.entity.BaseUpdateListener;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.mybatisflex.annotation.Column;
|
||||
import com.mybatisflex.annotation.Id;
|
||||
import com.mybatisflex.annotation.Table;
|
||||
@ -74,6 +75,16 @@ public class Clue extends BaseEntity implements Serializable {
|
||||
*/
|
||||
private Integer clueStatus;
|
||||
|
||||
/**
|
||||
* 最后接收时间
|
||||
*/
|
||||
private LocalDateTime lastReceiptTime;
|
||||
|
||||
/**
|
||||
* 最后接收员工id
|
||||
*/
|
||||
private String lastReceiptStaffId;
|
||||
|
||||
/**
|
||||
* 是否删除(0否1是)
|
||||
*/
|
||||
|
||||
@ -45,7 +45,7 @@ public class Task extends BaseEntity implements Serializable {
|
||||
private String responsibleStaffId;
|
||||
|
||||
/**
|
||||
* 任务状态(-1:失败;0:待审核;1:待接受;2:进行中;3:待测试;5:暂停;7:接收超时;8:待部署;9:已归档;10:审核不通过)
|
||||
* 任务状态(-1:失败;0:待审核;1:待接受;2:进行中;3:待测试;5:暂停;6:强制办结;7:接收超时;8:待部署;9:已归档;10:审核不通过)
|
||||
*/
|
||||
private Integer taskStatus;
|
||||
|
||||
|
||||
@ -88,6 +88,21 @@ public class TaskWorkOrder extends BaseEntity implements Serializable {
|
||||
*/
|
||||
private String enforceFinishReason;
|
||||
|
||||
/**
|
||||
* 强制办结员工id
|
||||
*/
|
||||
private String enforceFinishStaffId;
|
||||
|
||||
/**
|
||||
* 强制办结时间
|
||||
*/
|
||||
private LocalDateTime enforceFinishTime;
|
||||
|
||||
/**
|
||||
* 强制办结剩余时间
|
||||
*/
|
||||
private Integer enforceFinishSurplusTime;
|
||||
|
||||
/**
|
||||
* 是否删除(0否1是)
|
||||
*/
|
||||
|
||||
@ -24,7 +24,7 @@ public interface ClueService extends IService<Clue> {
|
||||
* @since 2024/2/19
|
||||
* @return R<Page<SignGoalPageVo>>
|
||||
*/
|
||||
Page<CluePageVo> getPersonCluePage(Integer clueStatus, String city, String brandId, String storeId, String chargeOrPhone, String staffId);
|
||||
Page<CluePageVo> getPersonCluePage(Integer clueStatus, String city, String brandId, String storeId, String chargeOrPhone, String staffId, String signMonth);
|
||||
|
||||
/**
|
||||
* 个人签约目标
|
||||
|
||||
@ -1,12 +1,9 @@
|
||||
package com.cpop.oam.business.service;
|
||||
|
||||
import com.cpop.oam.business.bo.EnforceFinishWorkOrderBo;
|
||||
import com.cpop.oam.business.bo.*;
|
||||
import com.cpop.oam.business.vo.*;
|
||||
import com.mybatisflex.core.paginate.Page;
|
||||
import com.mybatisflex.core.service.IService;
|
||||
import com.cpop.oam.business.bo.PauseWorkOrderBo;
|
||||
import com.cpop.oam.business.bo.TaskWorkOrderBo;
|
||||
import com.cpop.oam.business.bo.TaskWorkOrderRecordBo;
|
||||
import com.cpop.oam.business.entity.TaskWorkOrder;
|
||||
|
||||
import java.time.LocalDate;
|
||||
@ -131,4 +128,12 @@ public interface TaskWorkOrderService extends IService<TaskWorkOrder> {
|
||||
* @param bo 请求参数
|
||||
*/
|
||||
void enforceFinishWorkOrder(EnforceFinishWorkOrderBo bo);
|
||||
|
||||
/**
|
||||
* 工单模块-工单提交-同意与拒绝强制办结
|
||||
* @author DB
|
||||
* @since 2024/2/21
|
||||
* @param bo 请求参数
|
||||
*/
|
||||
void agreeOrRejectEnforceFinish(AgreeOrRejectEnforceFinishBo bo);
|
||||
}
|
||||
|
||||
@ -400,6 +400,7 @@ public class BusinessServiceImpl extends ServiceImpl<BusinessMapper, Business> i
|
||||
StoreSign storeSign = new StoreSign();
|
||||
storeSign.setStoreId(id);
|
||||
storeSign.setSignStaffId(loginUserInfo.getString("id"));
|
||||
storeSign.setSignMonth(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM")));
|
||||
StoreSignService storeSignService = SpringUtils.getBean(StoreSignService.class);
|
||||
storeSignService.save(storeSign);
|
||||
SpringUtils.getBean(StoreService.class).updateChain()
|
||||
|
||||
@ -28,15 +28,18 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
|
||||
import static com.cpop.oam.business.entity.table.CluePutOffTableDef.CLUE_PUT_OFF;
|
||||
import static com.cpop.oam.business.entity.table.ClueRecordTableDef.CLUE_RECORD;
|
||||
import static com.cpop.oam.business.entity.table.ClueTableDef.CLUE;
|
||||
import static com.cpop.oam.business.entity.table.ClueUpdateTableDef.CLUE_UPDATE;
|
||||
import static com.cpop.oam.business.entity.table.SignAreaTableDef.SIGN_AREA;
|
||||
import static com.cpop.oam.business.entity.table.SignGoalTableDef.SIGN_GOAL;
|
||||
import static com.cpop.oam.business.entity.table.StaffTableDef.STAFF;
|
||||
import static com.cpop.system.business.entity.table.BrandTableDef.BRAND;
|
||||
import static com.cpop.system.business.entity.table.StoreSignTableDef.STORE_SIGN;
|
||||
import static com.cpop.system.business.entity.table.StoreTableDef.STORE;
|
||||
import static com.mybatisflex.core.query.QueryMethods.*;
|
||||
|
||||
@ -56,7 +59,7 @@ public class ClueServiceImpl extends ServiceImpl<ClueMapper, Clue> implements Cl
|
||||
* @return R<Page<SignGoalPageVo>>
|
||||
*/
|
||||
@Override
|
||||
public Page<CluePageVo> getPersonCluePage(Integer clueStatus, String city, String brandId, String storeId, String chargeOrPhone, String staffId) {
|
||||
public Page<CluePageVo> getPersonCluePage(Integer clueStatus, String city, String brandId, String storeId, String chargeOrPhone, String staffId, String signMonth) {
|
||||
PageDomain pageDomain = SqlUtils.getInstance().getPageDomain();
|
||||
QueryWrapper queryWrapper = QueryWrapper.create();
|
||||
if (clueStatus != null){
|
||||
@ -78,6 +81,7 @@ public class ClueServiceImpl extends ServiceImpl<ClueMapper, Clue> implements Cl
|
||||
.select(CLUE.CITY,CLUE.ID,CLUE.CREATE_TIME,CLUE.DEV_STAFF_ID,CLUE.LAST_FOLLOW_UP_TIME,CLUE.LAST_FOLLOW_UP_CONTENT,CLUE.RECEIPT_TIME,CLUE.STORE_ID)
|
||||
.select(STORE.STORE_NAME,STORE.STORE_ADDR,STORE.PERSON_CHARGE,STORE.PHONE)
|
||||
.select(BRAND.BRAND_NAME)
|
||||
.select(STORE_SIGN.EXPIRE_DATE)
|
||||
// 跟进间隔
|
||||
.select(dateDiff(now(), CLUE.LAST_FOLLOW_UP_TIME).as(CluePageVo::getFollowUpInterval))
|
||||
// 签约时间
|
||||
@ -85,6 +89,7 @@ public class ClueServiceImpl extends ServiceImpl<ClueMapper, Clue> implements Cl
|
||||
.from(CLUE)
|
||||
.leftJoin(STORE).on(STORE.ID.eq(CLUE.STORE_ID))
|
||||
.leftJoin(BRAND).on(BRAND.ID.eq(STORE.BRAND_ID))
|
||||
.leftJoin(STORE_SIGN).on(STORE_SIGN.STORE_ID.eq(STORE.ID))
|
||||
//地区
|
||||
.and(CLUE.CITY.eq(city))
|
||||
//品牌
|
||||
@ -92,6 +97,7 @@ public class ClueServiceImpl extends ServiceImpl<ClueMapper, Clue> implements Cl
|
||||
//校区
|
||||
.and(CLUE.STORE_ID.eq(storeId))
|
||||
.and(STORE.PERSON_CHARGE.likeLeft(chargeOrPhone).or(STORE.PHONE.eq(chargeOrPhone)))
|
||||
.and(STORE_SIGN.SIGN_MONTH.eq(signMonth))
|
||||
.orderBy(changeOrderColumn(pageDomain)),
|
||||
CluePageVo.class,
|
||||
//开发员工
|
||||
@ -156,6 +162,9 @@ public class ClueServiceImpl extends ServiceImpl<ClueMapper, Clue> implements Cl
|
||||
queryWrapper.and(SIGN_GOAL.STAFF_ID.eq(loginUserInfo.getString("id")));
|
||||
}
|
||||
SignGoalService signGoalService = SpringUtils.getBean(SignGoalService.class);
|
||||
if (StringUtils.isBlank(signMonth)) {
|
||||
signMonth = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM"));
|
||||
}
|
||||
String[] split = signMonth.split("-");
|
||||
SignGoal signGoal = signGoalService.getOne(queryWrapper.where(SIGN_GOAL.YEAR.eq(Integer.parseInt(split[0]))));
|
||||
PersonSignGoalVo vo = new PersonSignGoalVo();
|
||||
@ -284,6 +293,7 @@ public class ClueServiceImpl extends ServiceImpl<ClueMapper, Clue> implements Cl
|
||||
.select(STAFF.NAME.as(ClueUpdateVo.ClueUpdateRecordVo::getStaffName))
|
||||
.leftJoin(STAFF).on(STAFF.ID.eq(CLUE_UPDATE.UPDATE_STAFF_ID))
|
||||
.where(CLUE_UPDATE.CLUE_ID.eq(clueId))
|
||||
.orderBy(CLUE_UPDATE.CREATE_TIME.desc())
|
||||
.listAs(ClueUpdateVo.ClueUpdateRecordVo.class);
|
||||
clueUpdateVo.setRecordVos(recordVos);
|
||||
//获取现有校区数据
|
||||
@ -328,7 +338,9 @@ public class ClueServiceImpl extends ServiceImpl<ClueMapper, Clue> implements Cl
|
||||
@Override
|
||||
public List<CluePutOffVo> getCluePutOffRecord(String clueId) {
|
||||
return SpringUtils.getBean(CluePutOffService.class).getMapper().selectListByQueryAs(QueryWrapper.create()
|
||||
.select(CLUE_PUT_OFF.PUT_OFF_DATE, CLUE_PUT_OFF.PUT_OFF_REASON, CLUE_PUT_OFF.CREATE_TIME, CLUE_PUT_OFF.PUT_OFF_STAFF_ID, CLUE_PUT_OFF.AUDIT_STAFF_ID, CLUE_PUT_OFF.AUDIT_STATUS),
|
||||
.select(CLUE_PUT_OFF.PUT_OFF_DATE, CLUE_PUT_OFF.PUT_OFF_REASON, CLUE_PUT_OFF.CREATE_TIME, CLUE_PUT_OFF.PUT_OFF_STAFF_ID, CLUE_PUT_OFF.AUDIT_STAFF_ID, CLUE_PUT_OFF.AUDIT_STATUS,
|
||||
CLUE_PUT_OFF.CREATE_TIME,CLUE_PUT_OFF.PUT_OFF_FILE_URL)
|
||||
.orderBy(CLUE_PUT_OFF.CREATE_TIME.desc()),
|
||||
CluePutOffVo.class,
|
||||
//延迟员工
|
||||
item -> item.field(CluePutOffVo::getPutOffStaffName)
|
||||
@ -367,8 +379,10 @@ public class ClueServiceImpl extends ServiceImpl<ClueMapper, Clue> implements Cl
|
||||
if (clue.getClueStatus() == 1) {
|
||||
throw new ServiceException("当前线索已签约,不允许脱离");
|
||||
}
|
||||
clue.setClueStatus(0).setResponsibleStaffId(null);
|
||||
this.updateById(clue);
|
||||
this.updateChain().set(CLUE.CLUE_STATUS, 0)
|
||||
.set(CLUE.RESPONSIBLE_STAFF_ID, null)
|
||||
.where(CLUE.ID.eq(clue.getId()))
|
||||
.update();
|
||||
JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo();
|
||||
ClueRecord clueRecord = new ClueRecord();
|
||||
clueRecord.setClueId(id)
|
||||
@ -406,7 +420,7 @@ public class ClueServiceImpl extends ServiceImpl<ClueMapper, Clue> implements Cl
|
||||
}
|
||||
return this.mapper.paginateAs(Page.of(pageDomain.getPageNum(),pageDomain.getPageSize()),
|
||||
queryWrapper
|
||||
.select(CLUE.CITY,CLUE.ID,CLUE.CREATE_TIME,CLUE.DEV_STAFF_ID,CLUE.LAST_FOLLOW_UP_TIME,CLUE.LAST_FOLLOW_UP_CONTENT,CLUE.RECEIPT_TIME,CLUE.STORE_ID)
|
||||
.select(CLUE.CITY,CLUE.ID,CLUE.CREATE_TIME,CLUE.DEV_STAFF_ID,CLUE.LAST_FOLLOW_UP_TIME,CLUE.LAST_FOLLOW_UP_CONTENT,CLUE.RECEIPT_TIME,CLUE.STORE_ID,CLUE.LAST_RECEIPT_TIME,CLUE.LAST_RECEIPT_STAFF_ID)
|
||||
.select(STORE.STORE_NAME,STORE.STORE_ADDR,STORE.PERSON_CHARGE,STORE.PHONE)
|
||||
.select(BRAND.BRAND_NAME)
|
||||
// 跟进间隔
|
||||
@ -437,6 +451,17 @@ public class ClueServiceImpl extends ServiceImpl<ClueMapper, Clue> implements Cl
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}),
|
||||
//最后领取员工
|
||||
item -> item.field(CluePageVo::getLastReceiptStaffName)
|
||||
.queryWrapper(lastReceiptStaff -> {
|
||||
if (StringUtils.isNotBlank(lastReceiptStaff.getLastReceiptStaffId())) {
|
||||
return queryChain().select(STAFF.NAME.as(CluePageVo::getDevStaffName))
|
||||
.from(STAFF)
|
||||
.where(STAFF.ID.eq(lastReceiptStaff.getLastReceiptStaffId()));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@ -465,7 +490,7 @@ public class ClueServiceImpl extends ServiceImpl<ClueMapper, Clue> implements Cl
|
||||
}
|
||||
return this.mapper.paginateAs(Page.of(pageDomain.getPageNum(),pageDomain.getPageSize()),
|
||||
queryWrapper
|
||||
.select(CLUE.CITY,CLUE.ID,CLUE.CREATE_TIME,CLUE.DEV_STAFF_ID,CLUE.LAST_FOLLOW_UP_TIME,CLUE.LAST_FOLLOW_UP_CONTENT,CLUE.RECEIPT_TIME,CLUE.STORE_ID)
|
||||
.select(CLUE.CITY,CLUE.ID,CLUE.CREATE_TIME,CLUE.DEV_STAFF_ID,CLUE.LAST_FOLLOW_UP_TIME,CLUE.LAST_FOLLOW_UP_CONTENT,CLUE.RECEIPT_TIME,CLUE.STORE_ID,CLUE.LAST_RECEIPT_TIME,CLUE.LAST_RECEIPT_STAFF_ID)
|
||||
.select(STORE.STORE_NAME,STORE.STORE_ADDR,STORE.PERSON_CHARGE,STORE.PHONE)
|
||||
.select(BRAND.BRAND_NAME)
|
||||
// 跟进间隔
|
||||
@ -496,6 +521,17 @@ public class ClueServiceImpl extends ServiceImpl<ClueMapper, Clue> implements Cl
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}),
|
||||
//最后领取员工
|
||||
item -> item.field(CluePageVo::getLastReceiptStaffName)
|
||||
.queryWrapper(lastReceiptStaff -> {
|
||||
if (StringUtils.isNotBlank(lastReceiptStaff.getLastReceiptStaffId())) {
|
||||
return queryChain().select(STAFF.NAME.as(CluePageVo::getDevStaffName))
|
||||
.from(STAFF)
|
||||
.where(STAFF.ID.eq(lastReceiptStaff.getLastReceiptStaffId()));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@ -518,7 +554,9 @@ public class ClueServiceImpl extends ServiceImpl<ClueMapper, Clue> implements Cl
|
||||
clue.setResponsibleStaffId(loginUserInfo.getString("id"))
|
||||
.setReceiptTime(now)
|
||||
.setLastFollowUpTime(now)
|
||||
.setLastFollowUpContent(content);
|
||||
.setLastFollowUpContent(content)
|
||||
.setLastReceiptStaffId(loginUserInfo.getString("id"))
|
||||
.setLastReceiptTime(now);
|
||||
this.updateById(clue);
|
||||
//插入记录
|
||||
ClueRecord clueRecord = new ClueRecord();
|
||||
|
||||
@ -48,7 +48,7 @@ public class SignGoalServiceImpl extends ServiceImpl<SignGoalMapper, SignGoal> i
|
||||
PageDomain pageDomain = SqlUtils.getInstance().getPageDomain();
|
||||
return this.mapper.paginateAs(Page.of(pageDomain.getPageNum(),pageDomain.getPageSize()),
|
||||
QueryWrapper.create()
|
||||
.select(SIGN_GOAL.ID,SIGN_GOAL.YEAR,SIGN_GOAL.JAN_GOAL,SIGN_GOAL.JAN_FINISH,SIGN_GOAL.FEB_GOAL,SIGN_GOAL.FEB_FINISH,SIGN_GOAL.MAR_GOAL,SIGN_GOAL.MAR_FINISH,
|
||||
.select(SIGN_GOAL.ID,SIGN_GOAL.STAFF_ID,SIGN_GOAL.YEAR,SIGN_GOAL.JAN_GOAL,SIGN_GOAL.JAN_FINISH,SIGN_GOAL.FEB_GOAL,SIGN_GOAL.FEB_FINISH,SIGN_GOAL.MAR_GOAL,SIGN_GOAL.MAR_FINISH,
|
||||
SIGN_GOAL.APR_GOAL,SIGN_GOAL.APR_FINISH,SIGN_GOAL.MAY_GOAL,SIGN_GOAL.MAY_FINISH,SIGN_GOAL.JUN_GOAL,SIGN_GOAL.JUN_FINISH,SIGN_GOAL.JUL_GOAL,
|
||||
SIGN_GOAL.JUL_FINISH,SIGN_GOAL.AUG_GOAL,SIGN_GOAL.AUG_FINISH,SIGN_GOAL.SEP_GOAL,SIGN_GOAL.SEP_FINISH,SIGN_GOAL.OCT_GOAL,SIGN_GOAL.OCT_FINISH,
|
||||
SIGN_GOAL.NOV_GOAL,SIGN_GOAL.NOV_FINISH,SIGN_GOAL.DEC_GOAL,SIGN_GOAL.DEC_FINISH)
|
||||
|
||||
@ -811,7 +811,7 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
|
||||
.select(TASK.ID, TASK.TASK_CONTENT, TASK.TASK_STATUS)
|
||||
.select(TASK_STAFF_GROUP.GRADE_POINT, TASK_STAFF_GROUP.REMARK)
|
||||
.leftJoin(TASK_STAFF_GROUP).on(TASK_STAFF_GROUP.TASK_ID.eq(TASK.ID))
|
||||
.where(TASK.TASK_STATUS.in(2, 3, 5, 7, 8, 9))
|
||||
.where(TASK.TASK_STATUS.in(2, 3, 5, 6, 7, 8, 9))
|
||||
, TaskIndividualGpaDetailVo.class);
|
||||
TaskIndividualGpaVo vo = new TaskIndividualGpaVo();
|
||||
if (individualGpas.isEmpty()) {
|
||||
|
||||
@ -7,6 +7,7 @@ import com.cpop.common.utils.StringUtils;
|
||||
import com.cpop.common.utils.bean.BeanUtils;
|
||||
import com.cpop.core.base.entity.PageDomain;
|
||||
import com.cpop.core.base.exception.ServiceException;
|
||||
import com.cpop.core.base.exception.UtilException;
|
||||
import com.cpop.core.service.RedisService;
|
||||
import com.cpop.core.utils.QuartzUtils;
|
||||
import com.cpop.core.utils.SecurityUtils;
|
||||
@ -101,7 +102,7 @@ public class TaskWorkOrderServiceImpl extends ServiceImpl<TaskWorkOrderMapper, T
|
||||
.on(STORE.ID.eq(TASK_WORK_ORDER.STORE_ID))
|
||||
// 工单
|
||||
.where(TASK.TASK_TYPE.eq(2))
|
||||
.and(TASK.TASK_STATUS.in(1, 2, 4, 5, 7)),
|
||||
.and(TASK.TASK_STATUS.in(1, 2, 4, 5, 6, 7)),
|
||||
TaskWorkOrderReceiveDealPauseDto.class,
|
||||
// 提交人
|
||||
item -> item.field(TaskWorkOrderReceiveDealPauseDto::getRecordStaffName)
|
||||
@ -139,6 +140,7 @@ public class TaskWorkOrderServiceImpl extends ServiceImpl<TaskWorkOrderMapper, T
|
||||
taskWorkOrderReceiveDealPauseVo.getReceiveList().addAll(receiveList);
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
// 进行中
|
||||
case 2:
|
||||
// 逾期
|
||||
@ -334,7 +336,7 @@ public class TaskWorkOrderServiceImpl extends ServiceImpl<TaskWorkOrderMapper, T
|
||||
QuartzEnums acceptEnums = QuartzEnums.WORK_ORDER_FINISH_OVERTIME_REMIND_TASK;
|
||||
// 开始
|
||||
if (status == 0) {
|
||||
LocalDateTime localDateTime = dateTime.plusMinutes(105);
|
||||
LocalDateTime localDateTime = dateTime.plusMinutes(150);
|
||||
ZoneId zoneId = ZoneId.systemDefault();
|
||||
String cron = quartzUtils.convertToCron(Date.from(localDateTime.atZone(zoneId).toInstant()));
|
||||
// 通过JobBuilder构建JobDetail实例,JobDetail规定其job只能是实现Job接口的实例
|
||||
@ -350,7 +352,7 @@ public class TaskWorkOrderServiceImpl extends ServiceImpl<TaskWorkOrderMapper, T
|
||||
.build();
|
||||
scheduler.scheduleJob(jobDetail, cronTrigger);
|
||||
} else if (status == 1) {
|
||||
LocalDateTime localDateTime = dateTime.plusMinutes(105);
|
||||
LocalDateTime localDateTime = dateTime.plusMinutes(150);
|
||||
ZoneId zoneId = ZoneId.systemDefault();
|
||||
String cron = quartzUtils.convertToCron(Date.from(localDateTime.atZone(zoneId).toInstant()));
|
||||
//修改
|
||||
@ -410,15 +412,16 @@ public class TaskWorkOrderServiceImpl extends ServiceImpl<TaskWorkOrderMapper, T
|
||||
* @param workOrderId 工单id
|
||||
* @param isUpdate 是否更新
|
||||
* @param dateTime 开始时间
|
||||
* @param minute 延迟多少分钟
|
||||
* @author DB
|
||||
* @since 2023-11-29 16:09:02
|
||||
*/
|
||||
private void startOrUpdateWorkOrderOvertimeTask(String workOrderId, Boolean isUpdate, LocalDateTime dateTime) {
|
||||
private void startOrUpdateWorkOrderOvertimeTask(String workOrderId, Boolean isUpdate, LocalDateTime dateTime,Integer minute) {
|
||||
// 基于表达式构建触发器
|
||||
QuartzUtils quartzUtils = SpringUtils.getBean(QuartzUtils.class);
|
||||
try {
|
||||
//实际两小时
|
||||
LocalDateTime localDateTime = dateTime.plusHours(2);
|
||||
//实际三小时
|
||||
LocalDateTime localDateTime = dateTime.plusMinutes(minute);
|
||||
ZoneId zoneId = ZoneId.systemDefault();
|
||||
String cron = quartzUtils.convertToCron(Date.from(localDateTime.atZone(zoneId).toInstant()));
|
||||
if (isUpdate) {
|
||||
@ -447,6 +450,19 @@ public class TaskWorkOrderServiceImpl extends ServiceImpl<TaskWorkOrderMapper, T
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成工单超时任务
|
||||
*
|
||||
* @param workOrderId 工单id
|
||||
* @param isUpdate 是否更新
|
||||
* @param dateTime 开始时间
|
||||
* @author DB
|
||||
* @since 2023-11-29 16:09:02
|
||||
*/
|
||||
private void startOrUpdateWorkOrderOvertimeTask(String workOrderId, Boolean isUpdate, LocalDateTime dateTime) {
|
||||
startOrUpdateWorkOrderOvertimeTask(workOrderId, isUpdate, dateTime, 180);
|
||||
}
|
||||
|
||||
/**
|
||||
* 工单模块-工单提交-工单记录列表
|
||||
*
|
||||
@ -743,7 +759,7 @@ public class TaskWorkOrderServiceImpl extends ServiceImpl<TaskWorkOrderMapper, T
|
||||
.select(SYS_USER.PHONE_NUMBER.as(StaffInfoVo::getPhoneNumber))
|
||||
.from(STAFF)
|
||||
.leftJoin(SYS_USER)
|
||||
.on(SYS_USER.ID.eq(STAFF.ID))
|
||||
.on(SYS_USER.ID.eq(STAFF.USER_ID))
|
||||
.where(STAFF.ID.in(staffIds)),
|
||||
StaffInfoVo.class)
|
||||
.stream().collect(Collectors.toMap(StaffInfoVo::getId, item -> item));
|
||||
@ -800,7 +816,7 @@ public class TaskWorkOrderServiceImpl extends ServiceImpl<TaskWorkOrderMapper, T
|
||||
.on(BRAND.ID.eq(TASK_WORK_ORDER.BRAND_ID))
|
||||
.leftJoin(STORE)
|
||||
.on(STORE.ID.eq(TASK_WORK_ORDER.STORE_ID))
|
||||
.where(TASK.TASK_STATUS.in(1, 2, 5, 7)),
|
||||
.where(TASK.TASK_STATUS.in(1, 2, 4, 5, 7)),
|
||||
TaskWorkOrderPersonVo.class,
|
||||
// 提交人
|
||||
item -> item.field(TaskWorkOrderPersonVo::getRecordStaffName)
|
||||
@ -943,7 +959,148 @@ public class TaskWorkOrderServiceImpl extends ServiceImpl<TaskWorkOrderMapper, T
|
||||
* @param bo 请求参数
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void enforceFinishWorkOrder(EnforceFinishWorkOrderBo bo) {
|
||||
throw new ServiceException("功能未实现");
|
||||
// 获取工单信息
|
||||
TaskWorkOrder taskWorkOrder = this.getById(bo.getId());
|
||||
JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo();
|
||||
taskWorkOrder.setEnforceFinishStaffId(loginUserInfo.getString("id"));
|
||||
LocalDateTime finishTime = LocalDateTime.now();
|
||||
taskWorkOrder.setEnforceFinishTime(finishTime);
|
||||
taskWorkOrder.setEnforceFinishReason(bo.getEnforceFinishReason());
|
||||
// 读取工单办结定时任务
|
||||
QuartzUtils quartzUtils = SpringUtils.getBean(QuartzUtils.class);
|
||||
try {
|
||||
LocalDateTime jobExecuteTime = quartzUtils.getJobExecuteTime(QuartzEnums.WORK_ORDER_OVERTIME_TASK.getName() + bo.getId(), QuartzEnums.WORK_ORDER_OVERTIME_TASK.getGroup());
|
||||
Duration duration = Duration.between(finishTime, jobExecuteTime);
|
||||
Long minutes = duration.toMinutes();
|
||||
taskWorkOrder.setEnforceFinishSurplusTime(minutes.intValue());
|
||||
} catch (SchedulerException e) {
|
||||
throw new UtilException(e);
|
||||
}
|
||||
// 设置工单强制办结
|
||||
TaskService taskService = SpringUtils.getBean(TaskService.class);
|
||||
Task task = taskService.getOne(QueryWrapper.create().where(TASK.ID.eq(taskWorkOrder.getTaskId())));
|
||||
//检查工单接受时间距离现在是否大于120分钟
|
||||
Duration between = Duration.between(task.getTaskReceiptTime(), finishTime);
|
||||
long minutes = between.toMinutes();
|
||||
if (minutes - 120 <= 0) {
|
||||
throw new ServiceException("强制办结工单的接受时间距离现在必须大于120分钟");
|
||||
}
|
||||
//设置强制办结
|
||||
task.setTaskItem(1).setTaskStatus(6);
|
||||
taskService.updateById(task);
|
||||
// 更新工单
|
||||
this.updateById(taskWorkOrder);
|
||||
// 插入工单暂停记录
|
||||
TaskWorkOrderRecord taskWorkOrderRecord = new TaskWorkOrderRecord();
|
||||
String finishTimeString = "提交工单办结申请,时间为:" + finishTime.format(DateTimeFormatter.ofPattern(DateUtils.YYYY_MM_DD_HH_MM_SS));
|
||||
// 读取员工信息
|
||||
taskWorkOrderRecord.setRecordStaffId(loginUserInfo.getString("id"))
|
||||
.setTaskWorkOrderId(bo.getId())
|
||||
.setRecordText(finishTimeString);
|
||||
// 插入记录
|
||||
SpringUtils.getBean(TaskWorkOrderRecordService.class).save(taskWorkOrderRecord);
|
||||
// 负责人手机号
|
||||
StaffService staffService = SpringUtils.getBean(StaffService.class);
|
||||
Set<String> staffIds = new HashSet<>();
|
||||
staffIds.add(task.getResponsibleStaffId());
|
||||
staffIds.add(task.getRecordStaffId());
|
||||
Map<String, StaffInfoVo> staffMap = staffService.listAs(QueryWrapper.create()
|
||||
.select(STAFF.ID, STAFF.NAME)
|
||||
.select(SYS_USER.PHONE_NUMBER.as(StaffInfoVo::getPhoneNumber))
|
||||
.from(STAFF)
|
||||
.leftJoin(SYS_USER)
|
||||
.on(SYS_USER.ID.eq(STAFF.USER_ID))
|
||||
.where(STAFF.ID.in(staffIds)),
|
||||
StaffInfoVo.class)
|
||||
.stream().collect(Collectors.toMap(StaffInfoVo::getId, item -> item));
|
||||
List<String> phoneList = new ArrayList<>();
|
||||
phoneList.add(staffMap.get(task.getResponsibleStaffId()).getPhoneNumber());
|
||||
// 记录人手机号
|
||||
phoneList.add(staffMap.get(task.getRecordStaffId()).getPhoneNumber());
|
||||
// 通知记录
|
||||
try {
|
||||
SpringUtils.getBean(WebHookSendHandler.class).webHookSendText(WebHookKeyConstant.ORDER_INFO_BOT, phoneList, task.getTaskContent() + "\n" + finishTimeString, false);
|
||||
} catch (IOException e) {
|
||||
throw new ServiceException("发送消息通知失败!");
|
||||
}
|
||||
// 删除工单完结超时任务
|
||||
try {
|
||||
SpringUtils.getBean(QuartzUtils.class).deleteJob(QuartzEnums.WORK_ORDER_OVERTIME_TASK.getName() + bo.getId(), QuartzEnums.WORK_ORDER_OVERTIME_TASK.getGroup());
|
||||
// 删除工单暂停恢复任务
|
||||
startOrRemoveWorkOrderPauseRecover(bo.getId(), false, null);
|
||||
// 删除工单完结超时任务
|
||||
workOrderFinishOverTimeRemindTask(bo.getId(), 2, null);
|
||||
} catch (SchedulerException e) {
|
||||
throw new ServiceException("删除工单完结超时任务失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 工单模块-工单提交-同意与拒绝强制办结
|
||||
* @author DB
|
||||
* @since 2024/2/21
|
||||
* @param bo 请求参数
|
||||
*/
|
||||
@Override
|
||||
public void agreeOrRejectEnforceFinish(AgreeOrRejectEnforceFinishBo bo) {
|
||||
TaskWorkOrder workOrder = this.getById(bo.getId());
|
||||
TaskService taskService = SpringUtils.getBean(TaskService.class);
|
||||
Task task = taskService.getById(workOrder.getTaskId());
|
||||
JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo();
|
||||
String finishString;
|
||||
//同意
|
||||
if (bo.getAgreeOrReject()){
|
||||
task.setTaskStatus(9);
|
||||
task.setTaskItem(3);
|
||||
taskService.updateById(task);
|
||||
workOrder.setFinishStaffId(loginUserInfo.getString("id"));
|
||||
workOrder.setFinishTime(workOrder.getEnforceFinishTime());
|
||||
this.updateById(workOrder);
|
||||
finishString = "\n工单办结申请通过,办结时间为:" + workOrder.getFinishTime().format(DateTimeFormatter.ofPattern(DateUtils.YYYY_MM_DD_HH_MM_SS));
|
||||
} else {
|
||||
//拒绝继续计时
|
||||
task.setTaskStatus(2);
|
||||
task.setTaskItem(0);
|
||||
taskService.updateById(task);
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
finishString = "\n工单办结申请未通过,工单到期时间为:" + now.plusMinutes(workOrder.getEnforceFinishSurplusTime().longValue()).format(DateTimeFormatter.ofPattern(DateUtils.YYYY_MM_DD_HH_MM_SS)) +
|
||||
"\n工单到期剩余时间为:" + workOrder.getEnforceFinishSurplusTime() + "分钟";
|
||||
//重新发起工单超时任务
|
||||
startOrUpdateWorkOrderOvertimeTask(workOrder.getId(), false, now, workOrder.getEnforceFinishSurplusTime());
|
||||
}
|
||||
// 插入工单暂停记录
|
||||
TaskWorkOrderRecord taskWorkOrderRecord = new TaskWorkOrderRecord();
|
||||
// 读取员工信息
|
||||
taskWorkOrderRecord.setRecordStaffId(loginUserInfo.getString("id"))
|
||||
.setTaskWorkOrderId(workOrder.getId())
|
||||
.setRecordText(finishString);
|
||||
// 插入记录
|
||||
SpringUtils.getBean(TaskWorkOrderRecordService.class).save(taskWorkOrderRecord);
|
||||
// 负责人手机号
|
||||
StaffService staffService = SpringUtils.getBean(StaffService.class);
|
||||
Set<String> staffIds = new HashSet<>();
|
||||
staffIds.add(task.getResponsibleStaffId());
|
||||
staffIds.add(task.getRecordStaffId());
|
||||
Map<String, StaffInfoVo> staffMap = staffService.listAs(QueryWrapper.create()
|
||||
.select(STAFF.ID, STAFF.NAME)
|
||||
.select(SYS_USER.PHONE_NUMBER.as(StaffInfoVo::getPhoneNumber))
|
||||
.from(STAFF)
|
||||
.leftJoin(SYS_USER)
|
||||
.on(SYS_USER.ID.eq(STAFF.USER_ID))
|
||||
.where(STAFF.ID.in(staffIds)),
|
||||
StaffInfoVo.class)
|
||||
.stream().collect(Collectors.toMap(StaffInfoVo::getId, item -> item));
|
||||
List<String> phoneList = new ArrayList<>();
|
||||
phoneList.add(staffMap.get(task.getResponsibleStaffId()).getPhoneNumber());
|
||||
// 记录人手机号
|
||||
phoneList.add(staffMap.get(task.getRecordStaffId()).getPhoneNumber());
|
||||
// 通知记录
|
||||
try {
|
||||
SpringUtils.getBean(WebHookSendHandler.class).webHookSendText(WebHookKeyConstant.ORDER_INFO_BOT, phoneList, task.getTaskContent() + "\n" + finishString, false);
|
||||
} catch (IOException e) {
|
||||
throw new ServiceException("发送消息通知失败!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,4 +136,29 @@ public class CluePageVo {
|
||||
@ApiModelProperty(value = "签约状态(0:待签约;1:已签约;2:警告线索)")
|
||||
private Integer clueStatus;
|
||||
|
||||
/**
|
||||
* 到期日期
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
|
||||
private LocalDate expireDate;
|
||||
|
||||
/**
|
||||
* 最后接收时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
@ApiModelProperty(value = "最后接收时间")
|
||||
private String lastReceiptTime;
|
||||
|
||||
/**
|
||||
* 最后接收员工id
|
||||
*/
|
||||
@ApiModelProperty(value = "最后接收员工id")
|
||||
private String lastReceiptStaffId;
|
||||
|
||||
/**
|
||||
* 最后接收员工姓名
|
||||
*/
|
||||
@ApiModelProperty(value = "最后接收员工姓名")
|
||||
private String lastReceiptStaffName;
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.cpop.oam.business.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
@ -7,6 +8,7 @@ import lombok.experimental.Accessors;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* @author DB
|
||||
@ -60,4 +62,17 @@ public class CluePutOffVo {
|
||||
*/
|
||||
@ApiModelProperty(value = "延期原因")
|
||||
private String putOffReason;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
@ApiModelProperty(value = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 延期附件
|
||||
*/
|
||||
@ApiModelProperty(value = "延期附件")
|
||||
private String putOffFileUrl;
|
||||
}
|
||||
|
||||
@ -30,6 +30,12 @@ public class SignGoalPageVo {
|
||||
@ApiModelProperty(value = "员工名")
|
||||
private String staffName;
|
||||
|
||||
/**
|
||||
* 员工Id
|
||||
*/
|
||||
@ApiModelProperty(value = "员工Id")
|
||||
private String staffId;
|
||||
|
||||
/**
|
||||
* 签约区域
|
||||
*/
|
||||
|
||||
@ -72,5 +72,5 @@ public class TaskWorkOrderPersonVo {
|
||||
* 工单状态
|
||||
*/
|
||||
@ApiModelProperty(value = "工单状态")
|
||||
private Integer workOrderStatus;
|
||||
private Integer taskStatus;
|
||||
}
|
||||
|
||||
@ -153,6 +153,12 @@ public class TaskWorkOrderReceiveDealPauseVo {
|
||||
@ApiModelProperty(value = "任务接收用时/min")
|
||||
private Integer receivingTime;
|
||||
|
||||
/**
|
||||
* 任务状态(-1:失败;0:待审核;1:待接受;2:进行中;3:待测试;5:暂停;7:接收超时;8:待部署;9:待归档;10:审核不通过)
|
||||
*/
|
||||
@ApiModelProperty(value = "任务状态(-1:失败;0:待审核;1:待接受;2:进行中;3:待测试;5:暂停;7:接收超时;8:待部署;9:待归档;10:审核不通过)")
|
||||
private Integer taskStatus;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -24,6 +24,11 @@
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>weixin-java-pay</artifactId>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/org.jdom/jdom2 -->
|
||||
<dependency>
|
||||
<groupId>org.jdom</groupId>
|
||||
<artifactId>jdom2</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@ -100,4 +100,9 @@ public class WxPayProperties {
|
||||
* 先学后付用户支付成功通知地址
|
||||
*/
|
||||
private String learnNowPayLaterServiceOrderNotifyUrl;
|
||||
|
||||
/**
|
||||
* 普通模式下的商户号
|
||||
*/
|
||||
private String easyLearnUnionPayNormalNotifyUrl;
|
||||
}
|
||||
|
||||
@ -5,6 +5,8 @@ import com.cpop.common.utils.ServletUtils;
|
||||
import com.cpop.common.utils.StringUtils;
|
||||
import com.cpop.core.base.exception.ServiceException;
|
||||
import com.cpop.core.utils.SecurityUtils;
|
||||
import com.cpop.core.utils.SpringUtils;
|
||||
import com.cpop.pay.framewok.config.wxPay.WxPayConfiguration;
|
||||
import com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader;
|
||||
import com.github.binarywang.wxpay.config.WxPayConfig;
|
||||
import com.github.binarywang.wxpay.service.WxPayService;
|
||||
@ -44,7 +46,7 @@ public class WxPayHandler {
|
||||
}
|
||||
String brandId = loginUserInfo.getString("brandId");
|
||||
Row brand = Db.selectOneByQuery("cp_sys_brand", QueryWrapper.create().where("id = ?", brandId));
|
||||
if (brand.isEmpty()) {
|
||||
if (brand.isEmpty() || StringUtils.isBlank(brand.getString("wxMchId"))) {
|
||||
throw new ServiceException("当前品牌暂未开通微信支付,请联系相关客服");
|
||||
}
|
||||
//检查是否开启分账
|
||||
@ -121,7 +123,7 @@ public class WxPayHandler {
|
||||
if (brand != null && StringUtils.isNotBlank(brand.getString("wxMchId"))){
|
||||
wxMchId = brand.getString("wxMchId");
|
||||
}else {
|
||||
wxMchId = "1661323640";
|
||||
wxMchId = null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -130,7 +132,7 @@ public class WxPayHandler {
|
||||
if (brand != null && StringUtils.isNotBlank(brand.getString("wxMchId"))){
|
||||
wxMchId = brand.getString("wxMchId");
|
||||
}else {
|
||||
wxMchId = "1661323640";
|
||||
wxMchId = null;
|
||||
}
|
||||
}
|
||||
return wxMchId;
|
||||
@ -152,4 +154,5 @@ public class WxPayHandler {
|
||||
log.info("微信支付分回调ID:{}",request.getHeader("Request-ID"));
|
||||
return signatureHeader;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,65 @@
|
||||
package com.cpop.pay.framewok.handler.wxPay;
|
||||
|
||||
import com.cpop.core.utils.SpringUtils;
|
||||
import com.cpop.pay.framewok.config.wxPay.WxPayConfiguration;
|
||||
import org.checkerframework.checker.units.qual.A;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Map;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* @author DB
|
||||
* @version 1.0.0
|
||||
* @since 2024-02-22 20:10
|
||||
*/
|
||||
@Component
|
||||
public class WxPayNormalHandler {
|
||||
|
||||
@Autowired
|
||||
private WxUtils wxUtils;
|
||||
|
||||
public <T> T createOrder(String orderId,String openId, BigDecimal price, String body, String ipAddress,String notifyUrl) throws IOException {
|
||||
SortedMap<String, Object> parameters = new TreeMap<String, Object>();
|
||||
parameters.put("appid", "wx20853d18c455e874");
|
||||
parameters.put("mch_id", "1618436087");
|
||||
parameters.put("openid", openId);
|
||||
// 默认 "WEB"
|
||||
parameters.put("device_info", "WEB");
|
||||
parameters.put("body", body);
|
||||
// 32 位随机字符串
|
||||
parameters.put("nonce_str", wxUtils.gen32RandomString());
|
||||
parameters.put("notify_url", notifyUrl);
|
||||
parameters.put("out_trade_no", orderId);
|
||||
parameters.put("total_fee", price.multiply(BigDecimal.valueOf(100)).intValue());
|
||||
// parameters.put("total_fee", 1); // 测试时,将支付金额设置为 1 分钱
|
||||
parameters.put("spbill_create_ip", ipAddress);
|
||||
parameters.put("trade_type", "JSAPI");
|
||||
// sign 必须在最后
|
||||
parameters.put("sign", wxUtils.createSign(parameters, "JamBox20220329174000000000000002"));
|
||||
// 执行 HTTP 请求,获取接收的字符串(一段 XML)
|
||||
String result = wxUtils.executeHttpPost("https://api.mch.weixin.qq.com/pay/unifiedorder", parameters);
|
||||
return wxUtils.createSign2(result, "JamBox20220329174000000000000002");
|
||||
}
|
||||
|
||||
public String fail() {
|
||||
return "<xml>\n" +
|
||||
" <return_code><![CDATA[FAIL]]></return_code>\n" +
|
||||
" <return_msg><![CDATA[]]></return_msg>\n" +
|
||||
"</xml>";
|
||||
}
|
||||
|
||||
public String success() {
|
||||
return "<xml>\n" +
|
||||
" <return_code><![CDATA[SUCCESS]]></return_code>\n" +
|
||||
" <return_msg><![CDATA[OK]]></return_msg>\n" +
|
||||
"</xml>";
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,283 @@
|
||||
package com.cpop.pay.framewok.handler.wxPay;
|
||||
|
||||
import com.cpop.common.utils.StringUtils;
|
||||
import com.cpop.core.base.exception.UtilException;
|
||||
import com.github.binarywang.wxpay.bean.order.WxPayAppOrderResult;
|
||||
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
|
||||
import com.github.binarywang.wxpay.constant.WxPayConstants;
|
||||
import com.github.binarywang.wxpay.util.SignUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.poi.ss.formula.functions.T;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.jdom2.Document;
|
||||
import org.jdom2.Element;
|
||||
import org.jdom2.JDOMException;
|
||||
import org.jdom2.input.SAXBuilder;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.*;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author DB
|
||||
* @version 1.0.0
|
||||
* @since 2024-02-22 20:13
|
||||
*/
|
||||
@Component
|
||||
public class WxUtils {
|
||||
|
||||
/**
|
||||
* 执行 POST 方法的 HTTP 请求
|
||||
*
|
||||
* @param url
|
||||
* @param parameters
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public String executeHttpPost(String url, SortedMap<String, Object> parameters) throws IOException {
|
||||
HttpClient client = HttpClients.createDefault();
|
||||
HttpPost request = new HttpPost(url);
|
||||
request.setHeader("Content-type", "application/xml");
|
||||
request.setHeader("Accept", "application/xml");
|
||||
request.setEntity(new StringEntity(transferMapToXml(parameters), "UTF-8"));
|
||||
HttpResponse response = client.execute(request);
|
||||
return readResponse(response);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 第一次签名
|
||||
*
|
||||
* @param parameters 数据为服务器生成,下单时必须的字段排序签名
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public String createSign(SortedMap<String, Object> parameters, String key) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
Set es = parameters.entrySet();//所有参与传参的参数按照accsii排序(升序)
|
||||
Iterator it = es.iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry entry = (Map.Entry) it.next();
|
||||
String k = (String) entry.getKey();
|
||||
Object v = entry.getValue();
|
||||
if (null != v && !"".equals(v)
|
||||
&& !"sign".equals(k) && !"key".equals(k)) {
|
||||
sb.append(k + "=" + v + "&");
|
||||
}
|
||||
}
|
||||
sb.append("key=" + key);
|
||||
return encodeMD5(sb.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 第二次签名
|
||||
*
|
||||
* @param result 数据为微信返回给服务器的数据(XML 的 String),再次签名后传回给客户端(APP)使用
|
||||
* @param key 密钥
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public <T> T createSign2(String result, String key) throws IOException {
|
||||
SortedMap<String, Object> map = new TreeMap<>(transferXmlToMap(result));
|
||||
if (StringUtils.equals(map.get("result_code").toString(),"FAIL")){
|
||||
throw new UtilException(map.get("err_code_des").toString());
|
||||
}
|
||||
//wxJava获取签名
|
||||
String signType = WxPayConstants.SignType.MD5;
|
||||
String appid = map.get("appid").toString();
|
||||
WxPayMpOrderResult payResult = WxPayMpOrderResult.builder()
|
||||
.appId(appid)
|
||||
.timeStamp(String.valueOf(System.currentTimeMillis() / 1000))
|
||||
.nonceStr(map.get("nonce_str").toString())
|
||||
.packageValue("prepay_id=" + map.get("prepay_id"))
|
||||
.signType(signType)
|
||||
.build();
|
||||
payResult.setPaySign(SignUtils.createSign(payResult, signType, key, null));
|
||||
return (T) payResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证签名是否正确
|
||||
*
|
||||
* @return boolean
|
||||
* @throws Exception
|
||||
*/
|
||||
public boolean checkSign(SortedMap<String, Object> parameters, String key) throws Exception {
|
||||
String signWx = parameters.get("sign").toString();
|
||||
if (signWx == null) return false;
|
||||
parameters.remove("sign"); // 需要去掉原 map 中包含的 sign 字段再进行签名
|
||||
String signMe = createSign(parameters, key);
|
||||
return signWx.equals(signMe);
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取 request body 内容作为字符串
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public String readRequest(HttpServletRequest request) throws IOException {
|
||||
InputStream inputStream;
|
||||
StringBuffer sb = new StringBuffer();
|
||||
inputStream = request.getInputStream();
|
||||
String str;
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
|
||||
while ((str = in.readLine()) != null) {
|
||||
sb.append(str);
|
||||
}
|
||||
in.close();
|
||||
inputStream.close();
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取 response body 内容为字符串
|
||||
*/
|
||||
public String readResponse(HttpResponse response) throws IOException {
|
||||
BufferedReader in = new BufferedReader(
|
||||
new InputStreamReader(response.getEntity().getContent()));
|
||||
String result = new String();
|
||||
String line;
|
||||
while ((line = in.readLine()) != null) {
|
||||
result += line;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 Map 转化为 XML
|
||||
*
|
||||
* @param map
|
||||
* @return
|
||||
*/
|
||||
public String transferMapToXml(SortedMap<String, Object> map) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append("<xml>");
|
||||
for (String key : map.keySet()) {
|
||||
sb.append("<").append(key).append(">")
|
||||
.append(map.get(key))
|
||||
.append("</").append(key).append(">");
|
||||
}
|
||||
return sb.append("</xml>").toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 XML 转化为 map
|
||||
*
|
||||
* @param strxml
|
||||
* @return
|
||||
* @throws JDOMException
|
||||
* @throws IOException
|
||||
*/
|
||||
public Map transferXmlToMap(String strxml) throws IOException {
|
||||
strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");
|
||||
if (null == strxml || "".equals(strxml)) {
|
||||
return null;
|
||||
}
|
||||
Map m = new HashMap();
|
||||
InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));
|
||||
SAXBuilder builder = new SAXBuilder();
|
||||
Document doc = null;
|
||||
try {
|
||||
doc = builder.build(in);
|
||||
} catch (JDOMException e) {
|
||||
throw new IOException(e.getMessage()); // 统一转化为 IO 异常输出
|
||||
}
|
||||
// 解析 DOM
|
||||
Element root = doc.getRootElement();
|
||||
List list = root.getChildren();
|
||||
Iterator it = list.iterator();
|
||||
while (it.hasNext()) {
|
||||
Element e = (Element) it.next();
|
||||
String k = e.getName();
|
||||
String v = "";
|
||||
List children = e.getChildren();
|
||||
if (children.isEmpty()) {
|
||||
v = e.getTextNormalize();
|
||||
} else {
|
||||
v = getChildrenText(children);
|
||||
}
|
||||
m.put(k, v);
|
||||
}
|
||||
//关闭流
|
||||
in.close();
|
||||
return m;
|
||||
}
|
||||
|
||||
// 辅助 transferXmlToMap 方法递归提取子节点数据
|
||||
private String getChildrenText(List<Element> children) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
if (!children.isEmpty()) {
|
||||
Iterator<Element> it = children.iterator();
|
||||
while (it.hasNext()) {
|
||||
Element e = (Element) it.next();
|
||||
String name = e.getName();
|
||||
String value = e.getTextNormalize();
|
||||
List<Element> list = e.getChildren();
|
||||
sb.append("<" + name + ">");
|
||||
if (!list.isEmpty()) {
|
||||
sb.append(getChildrenText(list));
|
||||
}
|
||||
sb.append(value);
|
||||
sb.append("</" + name + ">");
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 生成 32 位随机字符串,包含:数字、字母大小写
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String gen32RandomString() {
|
||||
char[] dict = {'1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
|
||||
StringBuffer sb = new StringBuffer();
|
||||
Random random = new Random();
|
||||
for (int i = 0; i < 32; i++) {
|
||||
sb.append(String.valueOf(dict[(int) (Math.random() * 36)]));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* MD5 签名
|
||||
*
|
||||
* @param str
|
||||
* @return 签名后的字符串信息
|
||||
*/
|
||||
public String encodeMD5(String str) {
|
||||
try {
|
||||
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
|
||||
byte[] inputByteArray = (str).getBytes();
|
||||
messageDigest.update(inputByteArray);
|
||||
byte[] resultByteArray = messageDigest.digest();
|
||||
return byteArrayToHex(resultByteArray);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助 encodeMD5 方法实现
|
||||
private String byteArrayToHex(byte[] byteArray) {
|
||||
char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
||||
char[] resultCharArray = new char[byteArray.length * 2];
|
||||
int index = 0;
|
||||
for (byte b : byteArray) {
|
||||
resultCharArray[index++] = hexDigits[b >>> 4 & 0xf];
|
||||
resultCharArray[index++] = hexDigits[b & 0xf];
|
||||
}
|
||||
// 字符数组组合成字符串返回
|
||||
return new String(resultCharArray);
|
||||
}
|
||||
}
|
||||
@ -66,6 +66,11 @@ public class StoreSign extends BaseEntity implements Serializable {
|
||||
*/
|
||||
private String runOffReason;
|
||||
|
||||
/**
|
||||
* 签约月份
|
||||
*/
|
||||
private String signMonth;
|
||||
|
||||
/**
|
||||
* 逻辑删除(0否1是)
|
||||
*/
|
||||
|
||||
7
pom.xml
7
pom.xml
@ -51,6 +51,7 @@
|
||||
<cos_api.version>5.6.155</cos_api.version>
|
||||
<spring-test.version>5.3.31</spring-test.version>
|
||||
<hutool.version>5.8.23</hutool.version>
|
||||
<jdom2.version>2.0.6.1</jdom2.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
@ -226,6 +227,12 @@
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>${hutool.version}</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/org.jdom/jdom2 -->
|
||||
<dependency>
|
||||
<groupId>org.jdom</groupId>
|
||||
<artifactId>jdom2</artifactId>
|
||||
<version>${jdom2.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user