diff --git a/backend/lpg-user/pom.xml b/backend/lpg-user/pom.xml
index c7cb5e5..c185be7 100644
--- a/backend/lpg-user/pom.xml
+++ b/backend/lpg-user/pom.xml
@@ -67,6 +67,37 @@
${parent.version}
+
+
+ com.github.binarywang
+ weixin-java-pay
+ 4.1.0
+
+
+
+ com.github.binarywang
+ weixin-java-common
+ 4.1.0
+
+
+
+ com.github.binarywang
+ weixin-java-miniapp
+ 4.1.0
+
+
+
+ com.github.binarywang
+ weixin-java-mp
+ 4.1.0
+
+
+
+ com.github.binarywang
+ weixin-java-open
+ 4.1.0
+
+
diff --git a/backend/lpg-user/src/main/java/com/hotent/lpg/user/controller/PaymentController.java b/backend/lpg-user/src/main/java/com/hotent/lpg/user/controller/PaymentController.java
new file mode 100644
index 0000000..b3d3140
--- /dev/null
+++ b/backend/lpg-user/src/main/java/com/hotent/lpg/user/controller/PaymentController.java
@@ -0,0 +1,41 @@
+package com.hotent.lpg.user.controller;
+
+import com.hotent.lpg.user.enums.PayTypeEnum;
+import com.hotent.lpg.user.manager.PaymentManage;
+import com.hotent.lpg.user.vo.ResultData;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping("/payment/v1/")
+@AllArgsConstructor
+@Validated
+@Slf4j
+public class PaymentController {
+ private final PaymentManage paymentManage;
+
+ /**
+ * 预支付
+ * @param ddid
+ * @return
+ */
+ @PostMapping("/{ddid}")
+ public ResultData pay(@PathVariable("ddid") String ddid) {
+ String payType = PayTypeEnum.WX.getName(); // 默认微信
+ return paymentManage.pay(ddid, payType);
+ }
+
+ /**
+ * 支付回调
+ * @return
+ */
+ @PostMapping("/notify-order")
+ public String notifyOrder(@RequestBody String xmlData) {
+ log.warn("支付回调:{}", xmlData);
+ String res = paymentManage.notifyOrder(xmlData);
+ log.warn("处理状态:{}", res);
+ return res;
+ }
+}
diff --git a/backend/lpg-user/src/main/java/com/hotent/lpg/user/enums/PayTypeEnum.java b/backend/lpg-user/src/main/java/com/hotent/lpg/user/enums/PayTypeEnum.java
new file mode 100644
index 0000000..62ef183
--- /dev/null
+++ b/backend/lpg-user/src/main/java/com/hotent/lpg/user/enums/PayTypeEnum.java
@@ -0,0 +1,11 @@
+package com.hotent.lpg.user.enums;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum PayTypeEnum {
+ WX("微信");
+
+ private String name;
+}
diff --git a/backend/lpg-user/src/main/java/com/hotent/lpg/user/enums/TradeTypeEnum.java b/backend/lpg-user/src/main/java/com/hotent/lpg/user/enums/TradeTypeEnum.java
new file mode 100644
index 0000000..a1c9f11
--- /dev/null
+++ b/backend/lpg-user/src/main/java/com/hotent/lpg/user/enums/TradeTypeEnum.java
@@ -0,0 +1,15 @@
+package com.hotent.lpg.user.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum TradeTypeEnum {
+ APP("APP"),
+ NATIVE("NATIVE"),
+ JSAPI("JSAPI"),
+ MWEB("MWEB");
+
+ private String code;
+}
diff --git a/backend/lpg-user/src/main/java/com/hotent/lpg/user/manager/PaymentManage.java b/backend/lpg-user/src/main/java/com/hotent/lpg/user/manager/PaymentManage.java
new file mode 100644
index 0000000..1ca6e56
--- /dev/null
+++ b/backend/lpg-user/src/main/java/com/hotent/lpg/user/manager/PaymentManage.java
@@ -0,0 +1,10 @@
+package com.hotent.lpg.user.manager;
+
+
+import com.hotent.lpg.user.vo.ResultData;
+
+public interface PaymentManage {
+ ResultData pay(String ddid, String payType);
+
+ String notifyOrder(String xmlData);
+}
diff --git a/backend/lpg-user/src/main/java/com/hotent/lpg/user/manager/impl/PaymentManageImpl.java b/backend/lpg-user/src/main/java/com/hotent/lpg/user/manager/impl/PaymentManageImpl.java
new file mode 100644
index 0000000..bc147ae
--- /dev/null
+++ b/backend/lpg-user/src/main/java/com/hotent/lpg/user/manager/impl/PaymentManageImpl.java
@@ -0,0 +1,138 @@
+package com.hotent.lpg.user.manager.impl;
+
+import cn.hutool.core.util.RandomUtil;
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
+import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
+import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
+import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.service.WxPayService;
+
+import com.hotent.base.util.BeanUtils;
+import com.hotent.lpg.common.model.WDd;
+import com.hotent.lpg.user.dao.DdDao;
+import com.hotent.lpg.user.enums.PayTypeEnum;
+import com.hotent.lpg.user.manager.PaymentManage;
+import com.hotent.lpg.user.util.LocalDateTimeUtils;
+import com.hotent.lpg.user.util.WxPayConfiguration;
+import com.hotent.lpg.user.vo.ResultData;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Service
+@Transactional
+@AllArgsConstructor
+@Slf4j
+public class PaymentManageImpl implements PaymentManage {
+ private final DdDao ddDao;
+
+ @Override
+ public ResultData pay(String ddid, String payType) {
+
+ WDd wDd = ddDao.selectById(ddid);
+ if (BeanUtils.isEmpty(wDd)) {
+ return ResultData.error("订单不存在");
+ }
+ if (payType.equals(PayTypeEnum.WX.getName())) {
+ wDd.setFZffs(PayTypeEnum.WX.getName());
+ return wxPay(wDd);
+ }
+ return ResultData.error("支付方式错误");
+ }
+
+
+ private ResultData wxPay(WDd wDd) {
+ try {
+ String tradeType = wDd.getFZffs();
+ if (StrUtil.isBlank(tradeType)) {
+ return ResultData.error("支付方式错误");
+ }
+
+ // 防止重新启动支付时报“商户订单号重复”,前面增加8位随机数,product_id最大32位
+ String outTradeNo = RandomUtil.randomString(8) + "_" + wDd.getId();
+ String body = wDd.getFDddh();
+ body = body.length() > 40 ? body.substring(0,39) : body;
+
+ WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest = new WxPayUnifiedOrderRequest();
+ wxPayUnifiedOrderRequest.setAppid(WxPayConfiguration.appId);
+ wxPayUnifiedOrderRequest.setOpenid(null);
+ wxPayUnifiedOrderRequest.setBody(body);
+ wxPayUnifiedOrderRequest.setOutTradeNo(outTradeNo);
+ wxPayUnifiedOrderRequest.setTotalFee(wDd.getFDdje().multiply(new BigDecimal(100)).intValue());
+ wxPayUnifiedOrderRequest.setTradeType(tradeType);
+
+ JSONObject scene_info = new JSONObject();
+ scene_info.put("id", "LPG");
+ scene_info.put("name", "燃气");
+ wxPayUnifiedOrderRequest.setSceneInfo(scene_info.toString());
+ wxPayUnifiedOrderRequest.setNotifyUrl("https://zaoyin.peony.cn/server/hzys/payment/v1/notify-order"); // 支付回调地址,开放不用登录
+ wxPayUnifiedOrderRequest.setSpbillCreateIp("127.0.0.1");
+
+ // trade_type=APP时
+ if("APP".equals(wxPayUnifiedOrderRequest.getTradeType())){
+
+ }
+ // trade_type=NATIVE时
+ if("NATIVE".equals(wxPayUnifiedOrderRequest.getTradeType())){
+ wxPayUnifiedOrderRequest.setProductId(wxPayUnifiedOrderRequest.getOutTradeNo());
+ }
+ if ("JSAPI".equals(wxPayUnifiedOrderRequest.getTradeType())) {
+
+ }
+ if ("MWEB".equals(wxPayUnifiedOrderRequest.getTradeType())) {
+
+ }
+ WxPayService wxPayService = WxPayConfiguration.getPayService();
+ ddDao.updateById(wDd);
+ return ResultData.success(wxPayService.createOrder(wxPayUnifiedOrderRequest));
+ } catch (WxPayException e) {
+ if("INVALID_REQUEST".equals(e.getErrCode())){
+ return ResultData.error("订单号重复,请重新下单");
+ }
+ e.printStackTrace();
+ return ResultData.error(e.getReturnMsg() + "" + e.getCustomErrorMsg() + "" + e.getErrCodeDes());
+ }
+ }
+
+
+ @Override
+ public String notifyOrder(String xmlData) {
+ WxPayService wxPayService = WxPayConfiguration.getPayService();
+ try {
+ WxPayOrderNotifyResult notifyResult = wxPayService.parseOrderNotifyResult(xmlData);
+ String ddid = notifyResult.getOutTradeNo().split("_")[1];
+ WDd wDd = ddDao.selectById(ddid);
+ if (null == wDd) {
+ return WxPayNotifyResponse.fail("订单不存在");
+ }
+ BigDecimal payPrice = wDd.getFDdje();
+ if (payPrice.multiply(new BigDecimal(100)).intValue() != notifyResult.getTotalFee()) {
+ return WxPayNotifyResponse.fail("付款金额与订单金额不等");
+ }
+
+ String timeEnd = notifyResult.getTimeEnd();
+ LocalDateTime paymentTime = LocalDateTimeUtils.parse(timeEnd);
+// wDdb.setfFksj(paymentTime);
+// wDdb.setfZfdh(notifyResult.getTransactionId());
+// wDdb.setfSffk("是");
+// wDdb.setfDdzt("已付款");
+// wDdb.setfPtddzt("待审批");
+// wDdbDao.updateById(wDdb);
+//
+// if (StrUtil.isNotBlank(wDdb.getfZpid())) {
+// WZp wZp = wZpDao.selectById(wDdb.getfZpid());
+// wZp.setfZt("定制中");
+// wZpDao.updateById(wZp);
+// }
+ return WxPayNotifyResponse.success("成功");
+ } catch (WxPayException e) {
+ return WxPayNotifyResponse.fail(e.getErrCodeDes());
+ }
+ }
+}
diff --git a/backend/lpg-user/src/main/java/com/hotent/lpg/user/util/LocalDateTimeUtils.java b/backend/lpg-user/src/main/java/com/hotent/lpg/user/util/LocalDateTimeUtils.java
new file mode 100644
index 0000000..78132da
--- /dev/null
+++ b/backend/lpg-user/src/main/java/com/hotent/lpg/user/util/LocalDateTimeUtils.java
@@ -0,0 +1,92 @@
+package com.hotent.lpg.user.util;
+
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.temporal.ChronoField;
+
+/**
+ * LocalDateTime时间工具
+ */
+public class LocalDateTimeUtils {
+
+ public static final String YYYY = "yyyy";
+ public static final String YYYYMM = "yyyyMM";
+ public static final String YYYYMMDD = "yyyyMMdd";
+ public static final String YYYYMMDDHH = "yyyyMMddHH";
+ public static final String YYYYMMDDHHMM = "yyyyMMddHHmm";
+ public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
+ public static final String YYYY_MM = "yyyy-MM";
+ public static final String YYYY_MM_DD = "yyyy-MM-dd";
+ public static final String YYYY_MM_DD_HH = "yyyy-MM-dd HH";
+ public static final String YYYY_MM_DD_HH_MM = "yyyy-MM-dd HH:mm";
+ public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
+
+ private static final String BASE_TIME_FORMAT = "[yyyyMMddHHmmss][yyyyMMddHHmm][yyyyMMddHH][yyyyMMdd][yyyyMM][yyyy][[-][/][.]MM][[-][/][.]dd][ ][HH][[:][.]mm][[:][.]ss][[:][.]SSS]";
+ /**
+ * 【推荐】解析常用时间字符串,支持,并不局限于以下形式:
+ * [yyyy][yyyy-MM][yyyy-MM-dd][yyyy-MM-dd HH][yyyy-MM-dd HH:mm][yyyy-MM-dd HH:mm:ss][yyyy-MM-dd HH:mm:ss:SSS]
+ * [yyyy][yyyy/MM][yyyy/MM/dd][yyyy/MM/dd HH][yyyy/MM/dd HH:mm][yyyy/MM/dd HH:mm:ss][yyyy/MM/dd HH:mm:ss:SSS]
+ * [yyyy][yyyy.MM][yyyy.MM.dd][yyyy.MM.dd HH][yyyy.MM.dd HH.mm][yyyy.MM.dd HH.mm.ss][yyyy.MM.dd HH.mm.ss.SSS]
+ * [yyyy][yyyyMM][yyyyMMdd][yyyyMMddHH][yyyyMMddHHmm][yyyyMMddHHmmss]
+ * [MM-dd]
+ * 不支持yyyyMMddHHmmssSSS,因为本身DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS")就不支持这个形式
+ *
+ * @param timeString
+ * @return
+ */
+ public static LocalDateTime parse(String timeString) {
+ return LocalDateTime.parse(timeString, getDateTimeFormatterByPattern(BASE_TIME_FORMAT));
+ }
+
+ /**
+ * 根据传进来的pattern返回LocalDateTime,自动补齐
+ *
+ * @param timeString
+ * @param pattern
+ * @return
+ */
+ public static LocalDateTime parseByPattern(String timeString, String pattern) {
+ return LocalDateTime.parse(timeString, getDateTimeFormatterByPattern(pattern));
+ }
+
+ private static DateTimeFormatter getDateTimeFormatterByPattern(String pattern) {
+ return new DateTimeFormatterBuilder()
+ .appendPattern(pattern)
+ .parseDefaulting(ChronoField.YEAR_OF_ERA, LocalDateTime.now().getYear())
+ .parseDefaulting(ChronoField.MONTH_OF_YEAR, LocalDateTime.now().getMonthValue())
+ .parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
+ .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
+ .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
+ .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
+ .parseDefaulting(ChronoField.NANO_OF_SECOND, 0)
+ .toFormatter();
+ }
+
+ /**
+ * 将timestamp转为LocalDateTime
+ * @param timestamp
+ * @return
+ */
+ public static LocalDateTime timestamToDatetime(long timestamp){
+ Instant instant = Instant.ofEpochMilli(timestamp);
+ return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
+ }
+
+ /**
+ * 将LocalDataTime转为timestamp
+ * @param ldt
+ * @return
+ */
+ public static long datatimeToTimestamp(LocalDateTime ldt){
+ ZoneId zone = ZoneId.systemDefault();
+ return ldt.atZone(zone).toInstant().toEpochMilli();
+ }
+
+ public static void main(String[] args) {
+ long timeStamp = 1382694957000l;
+ System.out.println(timestamToDatetime(timeStamp));
+ }
+}
diff --git a/backend/lpg-user/src/main/java/com/hotent/lpg/user/util/WxPayConfiguration.java b/backend/lpg-user/src/main/java/com/hotent/lpg/user/util/WxPayConfiguration.java
new file mode 100644
index 0000000..6c9f220
--- /dev/null
+++ b/backend/lpg-user/src/main/java/com/hotent/lpg/user/util/WxPayConfiguration.java
@@ -0,0 +1,63 @@
+package com.hotent.lpg.user.util;
+
+import com.github.binarywang.wxpay.config.WxPayConfig;
+import com.github.binarywang.wxpay.service.WxPayService;
+import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
+
+public class WxPayConfiguration {
+// public static final String appId = "wxf41ff374261f39cc"; // 该配置用的是景易游的微信支付信息
+ public static final String appId = "wxde6f31c15afb357d";
+
+ public static WxPayService getPayService() {
+ // 该配置用的是景易游的微信支付信息
+// WxPayConfig wxPayConfig = new WxPayConfig();
+// wxPayConfig.setAppId("wxf41ff374261f39cc");
+// wxPayConfig.setMchId("1634368190");
+// wxPayConfig.setMchKey("Peony8228Peony8228Peony8228Peony");
+//// wxPayConfig.setKeyPath("/mnt/install/joolun-file/cert/1/apiclient_cert8e55f27b-6d67-4b91-a16e-e9f6ef96ca5b11027923844080776299.p12");
+//// wxPayConfig.setPrivateKeyPath("/mnt/install/joolun-file/cert/1/apiclient_key571e2a52-a9f8-46c5-9d4d-ed4b08d0749c4331609001879503591.pem");
+//// wxPayConfig.setPrivateCertPath("/mnt/install/joolun-file/cert/1/apiclient_cert13b610c6-4005-4189-8a61-85fab73fa42017841178972810569411.pem");
+// wxPayConfig.setCertSerialNo("55ED43DE3CC79DD045B92577A8FB2E95AACE8BEF");
+// wxPayConfig.setApiV3Key("Peony8228Peony8228Peony8228Peony");
+// // 可以指定是否使用沙箱环境
+// wxPayConfig.setUseSandboxEnv(false);
+
+
+ /**
+ * 商户简称:
+ * 牡丹集团宁安智慧工程中心
+ * 企业名称:
+ * 北京牡丹电子集团有限责任公司宁安智慧工程中心
+ * 登录账号
+ * 1556251121 (本账号)
+ *
+ * 账号角色
+ * Administrator
+ * 创建时间
+ * 2019年9月19日 09:29:32
+ * 绑定微信号
+ * c*****21更换绑定
+ * 姓 名
+ * *际
+ * 联系手机
+ * 158******80
+ * 联系邮箱
+ * b*********n
+ */
+ WxPayConfig wxPayConfig = new WxPayConfig();
+ wxPayConfig.setAppId("wxde6f31c15afb357d"); // appId(应用id)(微信支付商户平台获取)
+ wxPayConfig.setMchId("1556251121"); // 商户号(微信支付商户平台获取)
+ // 这里的密钥应该使用APIv2密码,v3密钥此jar包不支持签名方式
+ wxPayConfig.setMchKey("Peony8228Peony8228Peony8228Peony"); // 商户密钥(APIv2密钥)(微信支付商户平台-》账户中心-》API安全中获取APIv3密钥)
+// wxPayConfig.setKeyPath("/mnt/install/joolun-file/cert/1/apiclient_cert8e55f27b-6d67-4b91-a16e-e9f6ef96ca5b11027923844080776299.p12");
+// wxPayConfig.setPrivateKeyPath("/mnt/install/joolun-file/cert/1/apiclient_key571e2a52-a9f8-46c5-9d4d-ed4b08d0749c4331609001879503591.pem");
+// wxPayConfig.setPrivateCertPath("/mnt/install/joolun-file/cert/1/apiclient_cert13b610c6-4005-4189-8a61-85fab73fa42017841178972810569411.pem");
+ wxPayConfig.setCertSerialNo("736846A3CE4CBAC36DD5E81EB08F89240E4A05E1"); // 商户证书序列号(微信支付商户平台-》账户中心-》API安全中申请API证书)
+ wxPayConfig.setApiV3Key("Peony8228Peony8228Peony8228Peony"); // 商户密钥(APIv2密钥)(微信支付商户平台-》账户中心-》API安全中获取APIv3密钥)
+ // 可以指定是否使用沙箱环境
+ wxPayConfig.setUseSandboxEnv(false);
+ WxPayService wxPayService = new WxPayServiceImpl();
+ wxPayService.setConfig(wxPayConfig);
+ return wxPayService;
+ }
+}
diff --git a/backend/lpg-user/src/main/java/com/hotent/lpg/user/vo/ResultData.java b/backend/lpg-user/src/main/java/com/hotent/lpg/user/vo/ResultData.java
new file mode 100644
index 0000000..93b14bb
--- /dev/null
+++ b/backend/lpg-user/src/main/java/com/hotent/lpg/user/vo/ResultData.java
@@ -0,0 +1,42 @@
+package com.hotent.lpg.user.vo;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.util.HashMap;
+
+/**
+ * @projectName: service
+ * @package: com.hotent.common
+ * @className: ResultData
+ * @author: HuangLang
+ * @description: 接口统一返回对象
+ * @date: 2021-12-15 13:40
+ */
+@Data
+@Accessors(chain = true)
+public class ResultData implements Serializable {
+
+ private String code ="200";
+ private String msg ="success";
+ private Object data =new HashMap<>();
+
+ public static ResultData error(Exception e){
+ return new ResultData().setCode("500").setMsg(e.getMessage());
+ }
+
+ public static ResultData error(String message){
+ return new ResultData().setCode("500").setMsg(message);
+ }
+
+ public static ResultData success(){
+ return new ResultData();
+ }
+
+ public static ResultData success(Object o){
+ return new ResultData().setData(o);
+ }
+
+
+}
--
libgit2 0.21.2