From 3e251b4c48249879b7ac65e63ceb9c403f90a519 Mon Sep 17 00:00:00 2001
From: akun <957746831@qq.com>
Date: Wed, 17 Apr 2024 11:29:35 +0800
Subject: [PATCH] =?UTF-8?q?=E8=AE=A2=E5=8D=95=E6=A8=A1=E5=9D=97=E8=B0=83?=
=?UTF-8?q?=E6=95=B4=E4=B8=8E=E5=8D=8E=E4=B8=BA=E6=94=AF=E4=BB=98=E5=88=9D?=
=?UTF-8?q?=E5=A7=8B=E5=8C=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
sf-admin/pom.xml | 7 +
.../system/UserMemberController.java | 113 +++++++++
sf-framework/pom.xml | 12 +
sf-order/pom.xml | 33 +++
.../order/controller/OrderInfoController.java | 7 +-
.../java/com/sf/order/domain/OrderInfo.java | 24 +-
.../sf/order/domain/dto/OrderCreateDto.java | 14 +-
.../sf/order/domain/req/OrderListReqVo.java | 2 +-
.../sf/order/domain/res/OrderListResVo.java | 32 ++-
.../com/sf/order/mapper/OrderInfoMapper.java | 2 +
.../sf/order/service/IOrderInfoService.java | 4 +-
.../service/impl/OrderInfoServiceImpl.java | 42 ++--
.../mapper/order/OrderInfoMapper.xml | 22 +-
sf-payment/pom.xml | 41 +++
.../payment/config/HuaweiPaymentConfig.java | 31 +++
.../controller/HuaweiPaymentController.java | 46 ++++
.../java/com/sf/payment/domain/AuthToken.java | 42 ++++
.../java/com/sf/payment/domain/AuthUser.java | 73 ++++++
.../payment/domain/HuaweiPaymentCallback.java | 35 +++
.../domain/HuaweiPurchasesVerifyDTO.java | 51 ++++
.../HuaweiPurchasesVerifyResponseDTO.java | 56 +++++
.../sf/payment/domain/InAppPurchaseData.java | 233 +++++++++++++++++
.../service/IHuaweiPaymentService.java | 14 ++
.../impl/HuaweiPaymentServiceImpl.java | 235 ++++++++++++++++++
.../java/com/sf/system/domain/UserMember.java | 110 ++++++++
.../sf/system/mapper/UserMemberMapper.java | 63 +++++
.../sf/system/service/IUserMemberService.java | 63 +++++
.../service/impl/UserMemberServiceImpl.java | 101 ++++++++
.../mapper/system/UserMemberMapper.xml | 89 +++++++
29 files changed, 1540 insertions(+), 57 deletions(-)
create mode 100644 sf-admin/src/main/java/com/sf/web/controller/system/UserMemberController.java
create mode 100644 sf-order/pom.xml
rename {sf-admin => sf-order}/src/main/java/com/sf/order/controller/OrderInfoController.java (91%)
rename {sf-admin => sf-order}/src/main/java/com/sf/order/domain/OrderInfo.java (92%)
rename {sf-admin => sf-order}/src/main/java/com/sf/order/domain/dto/OrderCreateDto.java (79%)
rename {sf-admin => sf-order}/src/main/java/com/sf/order/domain/req/OrderListReqVo.java (94%)
rename {sf-admin => sf-order}/src/main/java/com/sf/order/domain/res/OrderListResVo.java (53%)
rename {sf-admin => sf-order}/src/main/java/com/sf/order/mapper/OrderInfoMapper.java (96%)
rename {sf-admin => sf-order}/src/main/java/com/sf/order/service/IOrderInfoService.java (93%)
rename {sf-admin => sf-order}/src/main/java/com/sf/order/service/impl/OrderInfoServiceImpl.java (79%)
rename {sf-admin => sf-order}/src/main/resources/mapper/order/OrderInfoMapper.xml (92%)
create mode 100644 sf-payment/pom.xml
create mode 100644 sf-payment/src/main/java/com/sf/payment/config/HuaweiPaymentConfig.java
create mode 100644 sf-payment/src/main/java/com/sf/payment/controller/HuaweiPaymentController.java
create mode 100644 sf-payment/src/main/java/com/sf/payment/domain/AuthToken.java
create mode 100644 sf-payment/src/main/java/com/sf/payment/domain/AuthUser.java
create mode 100644 sf-payment/src/main/java/com/sf/payment/domain/HuaweiPaymentCallback.java
create mode 100644 sf-payment/src/main/java/com/sf/payment/domain/HuaweiPurchasesVerifyDTO.java
create mode 100644 sf-payment/src/main/java/com/sf/payment/domain/HuaweiPurchasesVerifyResponseDTO.java
create mode 100644 sf-payment/src/main/java/com/sf/payment/domain/InAppPurchaseData.java
create mode 100644 sf-payment/src/main/java/com/sf/payment/service/IHuaweiPaymentService.java
create mode 100644 sf-payment/src/main/java/com/sf/payment/service/impl/HuaweiPaymentServiceImpl.java
create mode 100644 sf-system/src/main/java/com/sf/system/domain/UserMember.java
create mode 100644 sf-system/src/main/java/com/sf/system/mapper/UserMemberMapper.java
create mode 100644 sf-system/src/main/java/com/sf/system/service/IUserMemberService.java
create mode 100644 sf-system/src/main/java/com/sf/system/service/impl/UserMemberServiceImpl.java
create mode 100644 sf-system/src/main/resources/mapper/system/UserMemberMapper.xml
diff --git a/sf-admin/pom.xml b/sf-admin/pom.xml
index 3603c72..49f0926 100644
--- a/sf-admin/pom.xml
+++ b/sf-admin/pom.xml
@@ -66,6 +66,13 @@
sf-oauth
+
+ com.smarterFramework
+ sf-order
+
+
+
+
diff --git a/sf-admin/src/main/java/com/sf/web/controller/system/UserMemberController.java b/sf-admin/src/main/java/com/sf/web/controller/system/UserMemberController.java
new file mode 100644
index 0000000..8454cf7
--- /dev/null
+++ b/sf-admin/src/main/java/com/sf/web/controller/system/UserMemberController.java
@@ -0,0 +1,113 @@
+package com.sf.web.controller.system;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.sf.common.annotation.Log;
+import com.sf.common.core.controller.BaseController;
+import com.sf.common.core.domain.AjaxResult;
+import com.sf.common.enums.BusinessType;
+import com.sf.system.domain.UserMember;
+import com.sf.system.service.IUserMemberService;
+import com.sf.common.utils.poi.ExcelUtil;
+import com.sf.common.core.page.TableDataInfo;
+
+/**
+ * 会员Controller
+ *
+ * @author ztzh
+ * @date 2024-04-16
+ */
+@RestController
+@RequestMapping("/system/member")
+public class UserMemberController extends BaseController
+{
+ @Autowired
+ private IUserMemberService userMemberService;
+
+ /**
+ * 查询会员列表
+ */
+ @PreAuthorize("@ss.hasPermi('system:member:list')")
+ @GetMapping("/list")
+ public TableDataInfo list(UserMember userMember)
+ {
+ startPage();
+ List list = userMemberService.selectUserMemberList(userMember);
+ return getDataTable(list);
+ }
+
+ /**
+ * 导出会员列表
+ */
+ @PreAuthorize("@ss.hasPermi('system:member:export')")
+ @Log(title = "会员", businessType = BusinessType.EXPORT)
+ @PostMapping("/export")
+ public void export(HttpServletResponse response, UserMember userMember)
+ {
+ List list = userMemberService.selectUserMemberList(userMember);
+ ExcelUtil util = new ExcelUtil(UserMember.class);
+ util.exportExcel(response, list, "会员数据");
+ }
+
+ /**
+ * 获取会员详细信息
+ */
+ @PreAuthorize("@ss.hasPermi('system:member:query')")
+ @GetMapping(value = "/{id}")
+ public AjaxResult getInfo(@PathVariable("id") Long id)
+ {
+ return success(userMemberService.selectUserMemberById(id));
+ }
+
+ /**
+ * 获取会员详细信息,通过用户id
+ */
+ @GetMapping(value = "/byUser")
+ public AjaxResult getInfoByUser(Long userId)
+ {
+ return success(userMemberService.selectUserMemberByUserId(userId));
+ }
+
+ /**
+ * 新增会员
+ */
+ @PreAuthorize("@ss.hasPermi('system:member:add')")
+ @Log(title = "会员", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@RequestBody UserMember userMember)
+ {
+ return toAjax(userMemberService.insertUserMember(userMember));
+ }
+
+ /**
+ * 修改会员
+ */
+ @PreAuthorize("@ss.hasPermi('system:member:edit')")
+ @Log(title = "会员", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@RequestBody UserMember userMember)
+ {
+ return toAjax(userMemberService.updateUserMember(userMember));
+ }
+
+ /**
+ * 删除会员
+ */
+ @PreAuthorize("@ss.hasPermi('system:member:remove')")
+ @Log(title = "会员", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public AjaxResult remove(@PathVariable Long[] ids)
+ {
+ return toAjax(userMemberService.deleteUserMemberByIds(ids));
+ }
+}
diff --git a/sf-framework/pom.xml b/sf-framework/pom.xml
index df42e74..480011e 100644
--- a/sf-framework/pom.xml
+++ b/sf-framework/pom.xml
@@ -72,6 +72,18 @@
com.smarterFramework
sf-common
+
+
+ io.springfox
+ springfox-boot-starter
+
+
+
+
+ io.swagger
+ swagger-models
+ 1.6.2
+
\ No newline at end of file
diff --git a/sf-order/pom.xml b/sf-order/pom.xml
new file mode 100644
index 0000000..d95e016
--- /dev/null
+++ b/sf-order/pom.xml
@@ -0,0 +1,33 @@
+
+
+
+ smarterFramework
+ com.smarterFramework
+ 1.0.0
+
+ 4.0.0
+
+ sf-order
+
+
+ 订单模块
+
+
+
+
+
+
+ com.smarterFramework
+ sf-common
+
+
+ com.smarterFramework
+ sf-framework
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sf-admin/src/main/java/com/sf/order/controller/OrderInfoController.java b/sf-order/src/main/java/com/sf/order/controller/OrderInfoController.java
similarity index 91%
rename from sf-admin/src/main/java/com/sf/order/controller/OrderInfoController.java
rename to sf-order/src/main/java/com/sf/order/controller/OrderInfoController.java
index d887548..21f3db2 100644
--- a/sf-admin/src/main/java/com/sf/order/controller/OrderInfoController.java
+++ b/sf-order/src/main/java/com/sf/order/controller/OrderInfoController.java
@@ -13,7 +13,6 @@ import com.sf.order.domain.dto.OrderCreateDto;
import com.sf.order.domain.req.OrderListReqVo;
import com.sf.order.domain.res.OrderListResVo;
import com.sf.order.service.IOrderInfoService;
-import io.swagger.v3.oas.annotations.Operation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@@ -39,10 +38,7 @@ public class OrderInfoController extends BaseController {
@GetMapping("/list")
public TableDataInfo list(OrderListReqVo vo) {
startPage();
- SysUser user = SecurityUtils.getLoginUser().getUser();
- vo.setUserId(user.getUserId());
List list = orderInfoService.queryList(vo);
- logger.info("prderList"+list);
return getDataTable(list);
}
@@ -72,7 +68,7 @@ public class OrderInfoController extends BaseController {
@Log(title = "创建订单基础信息", businessType = BusinessType.INSERT)
@PostMapping(value = "/createOrder")
public AjaxResult createOrder(@RequestBody OrderCreateDto orderCreateDto) {
- return toAjax(orderInfoService.createOrder(orderCreateDto));
+ return AjaxResult.success(orderInfoService.createOrder(orderCreateDto));
}
/**
@@ -87,7 +83,6 @@ public class OrderInfoController extends BaseController {
/**
* 支付订单
*/
- @Operation(summary = "支付订单")
@PostMapping(value = "/pay/{orderId}")
private String orderPay(@PathVariable(value = "orderId") Long orderId) {
orderInfoService.orderPay(orderId);
diff --git a/sf-admin/src/main/java/com/sf/order/domain/OrderInfo.java b/sf-order/src/main/java/com/sf/order/domain/OrderInfo.java
similarity index 92%
rename from sf-admin/src/main/java/com/sf/order/domain/OrderInfo.java
rename to sf-order/src/main/java/com/sf/order/domain/OrderInfo.java
index 6e165a8..6785f83 100644
--- a/sf-admin/src/main/java/com/sf/order/domain/OrderInfo.java
+++ b/sf-order/src/main/java/com/sf/order/domain/OrderInfo.java
@@ -26,16 +26,12 @@ public class OrderInfo extends BaseEntity {
* 订单编号
*/
@Excel(name = "订单编号")
- private Long orderNo;
+ private String orderNo;
/**
- * 订单状态:
- * 0:待支付
- * 1:已付款
- * 2:支付超时系统结束
- * 3:已完成
+ * 订单状态: 0:待支付 1:已付款待发货 2:配送中 3:待取货 4:支付超时系统结束 5:客户自主取消 6:已完成
*/
- @Excel(name = "订单状态: 0:待支付 1:已付款 2:支付超时系统结束 3:已完成 ")
+ @Excel(name = "订单状态: 0:待支付 1:已付款待发货 2:配送中 3:待取货 4:支付超时系统结束 5:客户自主取消 6:已完成 ")
private Long orderStatus;
/**
@@ -105,8 +101,8 @@ public class OrderInfo extends BaseEntity {
/**
* 支付时间
*/
- @JsonFormat(pattern = "yyyy-MM-dd")
- @Excel(name = "支付时间", width = 30, dateFormat = "yyyy-MM-dd")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @Excel(name = "支付时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date payTime;
/**
@@ -145,7 +141,7 @@ public class OrderInfo extends BaseEntity {
* 平台外部订单号
*/
@Excel(name = "平台外部订单号")
- private Long outOrderNo;
+ private String outOrderNo;
/**
* 平台支付返回值
@@ -167,11 +163,11 @@ public class OrderInfo extends BaseEntity {
return id;
}
- public void setOrderNo(Long orderNo) {
+ public void setOrderNo(String orderNo) {
this.orderNo = orderNo;
}
- public Long getOrderNo() {
+ public String getOrderNo() {
return orderNo;
}
@@ -311,11 +307,11 @@ public class OrderInfo extends BaseEntity {
return orderType;
}
- public void setOutOrderNo(Long outOrderNo) {
+ public void setOutOrderNo(String outOrderNo) {
this.outOrderNo = outOrderNo;
}
- public Long getOutOrderNo() {
+ public String getOutOrderNo() {
return outOrderNo;
}
diff --git a/sf-admin/src/main/java/com/sf/order/domain/dto/OrderCreateDto.java b/sf-order/src/main/java/com/sf/order/domain/dto/OrderCreateDto.java
similarity index 79%
rename from sf-admin/src/main/java/com/sf/order/domain/dto/OrderCreateDto.java
rename to sf-order/src/main/java/com/sf/order/domain/dto/OrderCreateDto.java
index 0359751..4ec904a 100644
--- a/sf-admin/src/main/java/com/sf/order/domain/dto/OrderCreateDto.java
+++ b/sf-order/src/main/java/com/sf/order/domain/dto/OrderCreateDto.java
@@ -1,5 +1,6 @@
package com.sf.order.domain.dto;
+import com.sf.common.annotation.Excel;
import io.swagger.v3.oas.annotations.media.Schema;
import javax.validation.constraints.NotNull;
@@ -15,12 +16,13 @@ public class OrderCreateDto {
@NotNull(message = "商品id不能为空")
private Long goodsId;
+ @Schema(description = "平台外部订单号")
+ private String outOrderNo;
+
@Schema(description = "数量")
- @NotNull(message = "数量不能唯恐")
private Long count;
@Schema(description = "金额")
- @NotNull(message = "金额不能为空")
private Long amount;
@Schema(description = "用户id")
@@ -56,4 +58,12 @@ public class OrderCreateDto {
public void setUserId(Long userId) {
this.userId = userId;
}
+
+ public String getOutOrderNo() {
+ return outOrderNo;
+ }
+
+ public void setOutOrderNo(String outOrderNo) {
+ this.outOrderNo = outOrderNo;
+ }
}
diff --git a/sf-admin/src/main/java/com/sf/order/domain/req/OrderListReqVo.java b/sf-order/src/main/java/com/sf/order/domain/req/OrderListReqVo.java
similarity index 94%
rename from sf-admin/src/main/java/com/sf/order/domain/req/OrderListReqVo.java
rename to sf-order/src/main/java/com/sf/order/domain/req/OrderListReqVo.java
index c0e0d17..11d3832 100644
--- a/sf-admin/src/main/java/com/sf/order/domain/req/OrderListReqVo.java
+++ b/sf-order/src/main/java/com/sf/order/domain/req/OrderListReqVo.java
@@ -14,7 +14,7 @@ public class OrderListReqVo extends BaseEntity {
private Long userId;
/**
- * 订单类型
+ * 订单状态
*/
private Long orderStatus;
diff --git a/sf-admin/src/main/java/com/sf/order/domain/res/OrderListResVo.java b/sf-order/src/main/java/com/sf/order/domain/res/OrderListResVo.java
similarity index 53%
rename from sf-admin/src/main/java/com/sf/order/domain/res/OrderListResVo.java
rename to sf-order/src/main/java/com/sf/order/domain/res/OrderListResVo.java
index 1c7a63d..6bea013 100644
--- a/sf-admin/src/main/java/com/sf/order/domain/res/OrderListResVo.java
+++ b/sf-order/src/main/java/com/sf/order/domain/res/OrderListResVo.java
@@ -1,8 +1,12 @@
package com.sf.order.domain.res;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.sf.common.annotation.Excel;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
+import java.util.Date;
+
/**
* 活动信息详情
*
@@ -21,11 +25,7 @@ public class OrderListResVo {
private String orderNo;
/**
- * 订单状态:
- * 0:待支付
- * 1:已付款
- * 2:支付超时系统结束
- * 3:已完成
+ * 订单状态: 0:待支付 1:已付款待发货 2:配送中 3:待取货 4:支付超时系统结束 5:客户自主取消 6:已完成
*/
private Long orderStatus;
@@ -34,6 +34,18 @@ public class OrderListResVo {
*/
private Long orderAmt;
+ /**
+ * 支付时间
+ */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date payTime;
+
+ /**
+ * 订阅订单取消时间
+ */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date subscriptionCancellationTime;
+
/**
* 商品标题
*/
@@ -43,13 +55,21 @@ public class OrderListResVo {
*/
private String productPicture;
+ /**
+ * 商品描述
+ */
+ private String productDesc;
+
+
/**
* 商品规格
*/
private String goodsSpec;
+
/**
* 商品数量
*/
- private Integer goodsCount = 1;
+ private Integer goodsCount;
+
}
diff --git a/sf-admin/src/main/java/com/sf/order/mapper/OrderInfoMapper.java b/sf-order/src/main/java/com/sf/order/mapper/OrderInfoMapper.java
similarity index 96%
rename from sf-admin/src/main/java/com/sf/order/mapper/OrderInfoMapper.java
rename to sf-order/src/main/java/com/sf/order/mapper/OrderInfoMapper.java
index dfb2950..342981a 100644
--- a/sf-admin/src/main/java/com/sf/order/mapper/OrderInfoMapper.java
+++ b/sf-order/src/main/java/com/sf/order/mapper/OrderInfoMapper.java
@@ -64,4 +64,6 @@ public interface OrderInfoMapper {
* @return 结果
*/
public int deleteOrderInfoByIds(Long[] ids);
+
+ OrderInfo selectOrderInfoByOrderNo(String orderNo);
}
diff --git a/sf-admin/src/main/java/com/sf/order/service/IOrderInfoService.java b/sf-order/src/main/java/com/sf/order/service/IOrderInfoService.java
similarity index 93%
rename from sf-admin/src/main/java/com/sf/order/service/IOrderInfoService.java
rename to sf-order/src/main/java/com/sf/order/service/IOrderInfoService.java
index 26210aa..16d34ef 100644
--- a/sf-admin/src/main/java/com/sf/order/service/IOrderInfoService.java
+++ b/sf-order/src/main/java/com/sf/order/service/IOrderInfoService.java
@@ -43,7 +43,7 @@ public interface IOrderInfoService
* @param orderInfo 订单基础信息
* @return 结果
*/
- public int createOrder(OrderCreateDto orderInfo);
+ public Long createOrder(OrderCreateDto orderInfo);
/**
* 修改订单基础信息
@@ -70,4 +70,6 @@ public interface IOrderInfoService
public int deleteOrderInfoById(Long id);
void orderPay(Long orderId);
+
+ OrderInfo selectOrderInfoByOrderNo(String orderNo);
}
diff --git a/sf-admin/src/main/java/com/sf/order/service/impl/OrderInfoServiceImpl.java b/sf-order/src/main/java/com/sf/order/service/impl/OrderInfoServiceImpl.java
similarity index 79%
rename from sf-admin/src/main/java/com/sf/order/service/impl/OrderInfoServiceImpl.java
rename to sf-order/src/main/java/com/sf/order/service/impl/OrderInfoServiceImpl.java
index 5e3edda..24a723a 100644
--- a/sf-admin/src/main/java/com/sf/order/service/impl/OrderInfoServiceImpl.java
+++ b/sf-order/src/main/java/com/sf/order/service/impl/OrderInfoServiceImpl.java
@@ -21,8 +21,7 @@ import java.util.List;
* @date 2024-04-09
*/
@Service
-public class OrderInfoServiceImpl implements IOrderInfoService
-{
+public class OrderInfoServiceImpl implements IOrderInfoService {
@Resource
private OrderInfoMapper orderInfoMapper;
@Resource
@@ -35,8 +34,7 @@ public class OrderInfoServiceImpl implements IOrderInfoService
* @return 订单基础信息
*/
@Override
- public OrderInfo selectOrderInfoById(Long id)
- {
+ public OrderInfo selectOrderInfoById(Long id) {
return orderInfoMapper.selectOrderInfoById(id);
}
@@ -47,12 +45,11 @@ public class OrderInfoServiceImpl implements IOrderInfoService
* @return 订单基础信息
*/
@Override
- public List selectOrderInfoList(OrderInfo orderInfo)
- {
+ public List selectOrderInfoList(OrderInfo orderInfo) {
return orderInfoMapper.selectOrderInfoList(orderInfo);
}
- public List queryList(OrderListReqVo vo)
- {
+
+ public List queryList(OrderListReqVo vo) {
return orderInfoMapper.queryList(vo);
}
@@ -63,11 +60,10 @@ public class OrderInfoServiceImpl implements IOrderInfoService
* @return 结果
*/
@Override
- public int createOrder(OrderCreateDto orderCreateDto)
- {
+ public Long createOrder(OrderCreateDto orderCreateDto) {
OrderInfo orderInfo = new OrderInfo();
- orderInfo.setOrderNo(snowflakeIdWorker.nextId());
- orderInfo.setPayType(0L);
+ orderInfo.setOrderNo(snowflakeIdWorker.nextId() + "");
+ orderInfo.setPayType(1L);
orderInfo.setReceiveType(0L);
orderInfo.setOrderStatus(0L);
orderInfo.setCreateUserId(orderCreateDto.getUserId());
@@ -77,7 +73,9 @@ public class OrderInfoServiceImpl implements IOrderInfoService
orderInfo.setPayAmt(orderCreateDto.getAmount());
orderInfo.setCreateTime(DateUtils.getNowDate());
orderInfo.setUpdateTime(DateUtils.getNowDate());
- return orderInfoMapper.insertOrderInfo(orderInfo);
+ orderInfo.setOutOrderNo(orderCreateDto.getOutOrderNo());
+ orderInfoMapper.insertOrderInfo(orderInfo);
+ return snowflakeIdWorker.nextId();
}
/**
@@ -87,11 +85,11 @@ public class OrderInfoServiceImpl implements IOrderInfoService
* @return 结果
*/
@Override
- public int updateOrderInfo(OrderInfo orderInfo)
- {
+ public int updateOrderInfo(OrderInfo orderInfo) {
orderInfo.setUpdateTime(DateUtils.getNowDate());
return orderInfoMapper.updateOrderInfo(orderInfo);
}
+
@Override
public void orderPay(Long orderId) {
OrderInfo updateOrder = this.selectOrderInfoById(orderId);
@@ -104,11 +102,17 @@ public class OrderInfoServiceImpl implements IOrderInfoService
updateOrder.setOrderStatus(1L);
updateOrder.setPayTime(DateUtils.getNowDate());
// 修改订单状态
- if (1>this.updateOrderInfo(updateOrder)) {
+ if (1 > this.updateOrderInfo(updateOrder)) {
throw new ServiceException("支付异常,请联系管理员!");
}
}
+ @Override
+ public OrderInfo selectOrderInfoByOrderNo(String orderNo) {
+
+ return orderInfoMapper.selectOrderInfoByOrderNo(orderNo);
+ }
+
/**
* 批量删除订单基础信息
*
@@ -116,8 +120,7 @@ public class OrderInfoServiceImpl implements IOrderInfoService
* @return 结果
*/
@Override
- public int deleteOrderInfoByIds(Long[] ids)
- {
+ public int deleteOrderInfoByIds(Long[] ids) {
return orderInfoMapper.deleteOrderInfoByIds(ids);
}
@@ -128,8 +131,7 @@ public class OrderInfoServiceImpl implements IOrderInfoService
* @return 结果
*/
@Override
- public int deleteOrderInfoById(Long id)
- {
+ public int deleteOrderInfoById(Long id) {
return orderInfoMapper.deleteOrderInfoById(id);
}
diff --git a/sf-admin/src/main/resources/mapper/order/OrderInfoMapper.xml b/sf-order/src/main/resources/mapper/order/OrderInfoMapper.xml
similarity index 92%
rename from sf-admin/src/main/resources/mapper/order/OrderInfoMapper.xml
rename to sf-order/src/main/resources/mapper/order/OrderInfoMapper.xml
index 207b139..51117d1 100644
--- a/sf-admin/src/main/resources/mapper/order/OrderInfoMapper.xml
+++ b/sf-order/src/main/resources/mapper/order/OrderInfoMapper.xml
@@ -35,18 +35,21 @@
+
+
+
- select id, order_no, order_status, pay_type, pay_channel, order_amt, freight_amt, pay_amt, really_amt, receive_type, goods_id, business_id, receive_addr_id, create_time, pay_time, create_user_id, update_user_id, is_delete, update_time, track_no, order_type, out_order_no, pay_data, reduction_amout from ORDER_INFO
+ select id, order_no, order_status, pay_type, pay_channel, order_amt, freight_amt, pay_amt, really_amt, receive_type, goods_id, business_id, receive_addr_id, create_time, pay_time, create_user_id, update_user_id, is_delete, update_time, track_no, order_type, out_order_no, pay_data, reduction_amout from Order_info
- SELECT a.order_no,a.order_status,a.order_amt,b.product_title,b.product_picture,b.product_desc,b.goods_spec
- FROM ORDER_INFO a LEFT JOIN GOODS_MESSAGES b ON a.goods_id = b.id
+ SELECT a.id,a.order_no,a.order_status,a.order_amt,a.pay_time,a.count as goods_count,a.subscription_cancellation_time,b.product_title,b.product_picture,b.product_desc,b.goods_spec
+ FROM Order_info a LEFT JOIN GOODS_MESSAGES b ON a.goods_id = b.id
+
+
- insert into ORDER_INFO
+ insert into Order_info
id,
order_no,
@@ -146,7 +154,7 @@
- update ORDER_INFO
+ update Order_info
order_no = #{orderNo},
order_status = #{orderStatus},
@@ -176,11 +184,11 @@
- delete from ORDER_INFO where id = #{id}
+ delete from Order_info where id = #{id}
- delete from ORDER_INFO where id in
+ delete from Order_info where id in
#{id}
diff --git a/sf-payment/pom.xml b/sf-payment/pom.xml
new file mode 100644
index 0000000..b8bc13d
--- /dev/null
+++ b/sf-payment/pom.xml
@@ -0,0 +1,41 @@
+
+
+
+ smarterFramework
+ com.smarterFramework
+ 1.0.0
+
+ 4.0.0
+
+ sf-payment
+
+
+ 支付模块
+
+
+
+
+
+
+ com.smarterFramework
+ sf-common
+
+
+ com.smarterFramework
+ sf-framework
+
+
+ com.smarterFramework
+ sf-order
+
+
+ org.bouncycastle
+ bcprov-jdk18on
+ 1.73
+
+
+
+
+
\ No newline at end of file
diff --git a/sf-payment/src/main/java/com/sf/payment/config/HuaweiPaymentConfig.java b/sf-payment/src/main/java/com/sf/payment/config/HuaweiPaymentConfig.java
new file mode 100644
index 0000000..e52acb7
--- /dev/null
+++ b/sf-payment/src/main/java/com/sf/payment/config/HuaweiPaymentConfig.java
@@ -0,0 +1,31 @@
+package com.sf.payment.config;
+
+import lombok.Data;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+
+
+/**
+ * 功能描述:
+ *
+ * @author a_kun
+ * @date 2024/4/17 9:23
+ */
+@Data
+@Configuration
+public class HuaweiPaymentConfig {
+
+ /**
+ * 客户端id:对应各平台的appKey
+ */
+ @Value("${huawei.payment.clientId:110693217}")
+ private String clientId;
+
+ /**
+ * 客户端Secret:对应各平台的appSecret
+ */
+ @Value("${huawei.payment.clientSecret:1410c01bc71c7ba587175ae79e500137c70945acc1416a38127cf98a09a6f8ba}")
+ private String clientSecret;
+
+
+}
diff --git a/sf-payment/src/main/java/com/sf/payment/controller/HuaweiPaymentController.java b/sf-payment/src/main/java/com/sf/payment/controller/HuaweiPaymentController.java
new file mode 100644
index 0000000..baa770d
--- /dev/null
+++ b/sf-payment/src/main/java/com/sf/payment/controller/HuaweiPaymentController.java
@@ -0,0 +1,46 @@
+package com.sf.payment.controller;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.sf.common.core.domain.AjaxResult;
+import com.sf.payment.domain.HuaweiPaymentCallback;
+import com.sf.payment.domain.HuaweiPurchasesVerifyDTO;
+import com.sf.payment.service.IHuaweiPaymentService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * @author zoukun
+ */
+@Slf4j
+@RestController
+@RequestMapping("/payment")
+public class HuaweiPaymentController {
+
+ @Autowired
+ private IHuaweiPaymentService huaweiPaymentService;
+
+
+ /**
+ * 华为支付回调地址
+ */
+ @RequestMapping("/callback/huawei")
+ public AjaxResult callback(@RequestBody HuaweiPaymentCallback callback) {
+ log.info("进入callback: params:" + JSONObject.toJSONString(callback));
+ AjaxResult ajax = AjaxResult.success();
+ return ajax;
+ }
+
+
+ /**
+ * 华为购买验证
+ */
+ @RequestMapping("/huawei/purchases/verify")
+ public AjaxResult purchasesVerify(@Validated @RequestBody HuaweiPurchasesVerifyDTO verifyDTO) {
+ log.info("进入/huawei/purchases/tokens/verify: params:" + JSONObject.toJSONString(verifyDTO));
+ huaweiPaymentService.purchasesVerify(verifyDTO);
+ return AjaxResult.success();
+ }
+
+}
diff --git a/sf-payment/src/main/java/com/sf/payment/domain/AuthToken.java b/sf-payment/src/main/java/com/sf/payment/domain/AuthToken.java
new file mode 100644
index 0000000..20bd856
--- /dev/null
+++ b/sf-payment/src/main/java/com/sf/payment/domain/AuthToken.java
@@ -0,0 +1,42 @@
+package com.sf.payment.domain;
+
+import lombok.*;
+
+import java.io.Serializable;
+
+/**
+ * 授权所需的token
+ *
+ * @author zoukun
+ */
+@Getter
+@Setter
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class AuthToken implements Serializable {
+ private String accessToken;
+ private int expireIn;
+ private String refreshToken;
+ private int refreshTokenExpireIn;
+ private String uid;
+ private String openId;
+ private String accessCode;
+ private String unionId;
+
+ /**
+ * 华为返回 生成的Access Token中包含的scope。
+ */
+ private String scope;
+
+ /**
+ * 华为返回 固定返回Bearer,标识返回Access Token的类型
+ */
+ private String tokenType;
+
+ /**
+ * 华为返回 返回JWT格式数据,包含用户基本帐号、用户邮箱等信息。
+ * 参照https://developer.huawei.com/consumer/cn/doc/HMSCore-References/account-verify-id-token_hms_reference-0000001050050577#section3142132691914
+ */
+ private String idToken;
+}
diff --git a/sf-payment/src/main/java/com/sf/payment/domain/AuthUser.java b/sf-payment/src/main/java/com/sf/payment/domain/AuthUser.java
new file mode 100644
index 0000000..03eaa4b
--- /dev/null
+++ b/sf-payment/src/main/java/com/sf/payment/domain/AuthUser.java
@@ -0,0 +1,73 @@
+package com.sf.payment.domain;
+
+import com.alibaba.fastjson2.JSONObject;
+import lombok.*;
+
+import java.io.Serializable;
+
+/**
+ * 授权成功后的用户信息,根据授权平台的不同,获取的数据完整性也不同
+ *
+ * @author zoukun
+ */
+@Getter
+@Setter
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class AuthUser implements Serializable {
+ /**
+ * 用户第三方系统的唯一id。
+ */
+ private String uuid;
+ /**
+ * 用户名
+ */
+ private String username;
+ /**
+ * 用户昵称
+ */
+ private String nickname;
+ /**
+ * 用户头像
+ */
+ private String avatar;
+ /**
+ * 用户网址
+ */
+ private String blog;
+ /**
+ * 所在公司
+ */
+ private String company;
+ /**
+ * 位置
+ */
+ private String location;
+ /**
+ * 用户邮箱
+ */
+ private String email;
+ /**
+ * 用户手机号
+ */
+ private String mobileNumber;
+ /**
+ * 用户备注(各平台中的用户个人介绍)
+ */
+ private String remark;
+ /**
+ * 用户来源
+ */
+ private String source;
+ /**
+ * 用户授权的token信息
+ */
+ private AuthToken token;
+ /**
+ * 第三方平台返回的原始用户信息
+ */
+ private JSONObject rawUserInfo;
+
+
+}
diff --git a/sf-payment/src/main/java/com/sf/payment/domain/HuaweiPaymentCallback.java b/sf-payment/src/main/java/com/sf/payment/domain/HuaweiPaymentCallback.java
new file mode 100644
index 0000000..b7e46d2
--- /dev/null
+++ b/sf-payment/src/main/java/com/sf/payment/domain/HuaweiPaymentCallback.java
@@ -0,0 +1,35 @@
+package com.sf.payment.domain;
+
+import lombok.*;
+
+import java.io.Serializable;
+
+/**
+ * 授权回调时的参数类
+ *
+ * @author zk
+ */
+@Getter
+@Setter
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class HuaweiPaymentCallback implements Serializable {
+
+ /**
+ * 访问AuthorizeUrl后回调时带的参数code
+ */
+ private String code;
+
+ /**
+ * 客户端id:对应各平台的appKey
+ */
+ private String clientId;
+
+ /**
+ * 客户端Secret:对应各平台的appSecret
+ */
+ private String clientSecret;
+
+
+}
diff --git a/sf-payment/src/main/java/com/sf/payment/domain/HuaweiPurchasesVerifyDTO.java b/sf-payment/src/main/java/com/sf/payment/domain/HuaweiPurchasesVerifyDTO.java
new file mode 100644
index 0000000..563f879
--- /dev/null
+++ b/sf-payment/src/main/java/com/sf/payment/domain/HuaweiPurchasesVerifyDTO.java
@@ -0,0 +1,51 @@
+package com.sf.payment.domain;
+
+import apijson.NotNull;
+import lombok.*;
+
+import javax.validation.constraints.NotBlank;
+import java.io.Serializable;
+
+/**
+ * 华为验证购买tokenDTO
+ *
+ * @author zk
+ */
+@Getter
+@Setter
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class HuaweiPurchasesVerifyDTO implements Serializable {
+
+
+
+ /**
+ * 商品类别,取值包括:
+ *
+ * 0:消耗型商品
+ * 1:非消耗型商品
+ * 2:订阅型商品
+ */
+ @NotNull
+ private Integer kind;
+
+ /**
+ * 待下发商品的购买Token,发起购买和查询待消费商品信息时均会返回purchaseToken参数。
+ */
+ @NotBlank(message = "待下发商品的购买Token不能为空")
+ private String purchaseToken;
+
+ /**
+ * 待下发商品ID。商品ID来源于您在AppGallery Connect中配置商品信息时设置的商品ID。
+ */
+ @NotBlank(message = "待下发商品ID不能为空")
+ private String productId;
+
+ /**
+ * 订单号
+ */
+ @NotBlank(message = "订单号不能为空")
+ private String orderNo;
+
+}
diff --git a/sf-payment/src/main/java/com/sf/payment/domain/HuaweiPurchasesVerifyResponseDTO.java b/sf-payment/src/main/java/com/sf/payment/domain/HuaweiPurchasesVerifyResponseDTO.java
new file mode 100644
index 0000000..c684a59
--- /dev/null
+++ b/sf-payment/src/main/java/com/sf/payment/domain/HuaweiPurchasesVerifyResponseDTO.java
@@ -0,0 +1,56 @@
+package com.sf.payment.domain;
+
+import apijson.NotNull;
+import lombok.*;
+
+import javax.validation.constraints.NotBlank;
+import java.io.Serializable;
+
+/**
+ * 华为验证购买tokenD返回
+ *
+ * @author zk
+ */
+@Getter
+@Setter
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class HuaweiPurchasesVerifyResponseDTO implements Serializable {
+
+ /**
+ * 返回码。
+ *
+ * 0:成功。
+ * 其他:失败,具体请参见错误码。
+ */
+ private String responseCode;
+
+ /**
+ * 响应描述。
+ */
+ private String responseMessage;
+
+ /**
+ *
+ * 包含购买数据的JSON字符串,具体请参见表InappPurchaseDetails。
+ *
+ * 该字段原样参与签名。
+ */
+ private String purchaseTokenData;
+
+ /**
+ * purchaseTokenData基于应用RSA IAP私钥的签名信息,签名算法为signatureAlgorithm。
+ * 应用请参见对返回结果验签使用IAP公钥对PurchaseTokenData的JSON字符串进行验签。
+ */
+ private String dataSignature;
+
+ /**
+ *
+ * 签名算法。
+ */
+ @NotBlank(message = "待下发商品ID不能为空")
+ private String signatureAlgorithm;
+
+
+}
diff --git a/sf-payment/src/main/java/com/sf/payment/domain/InAppPurchaseData.java b/sf-payment/src/main/java/com/sf/payment/domain/InAppPurchaseData.java
new file mode 100644
index 0000000..05f7e97
--- /dev/null
+++ b/sf-payment/src/main/java/com/sf/payment/domain/InAppPurchaseData.java
@@ -0,0 +1,233 @@
+package com.sf.payment.domain;
+
+import lombok.Data;
+
+/**
+ * 功能描述:
+ *
+ * @author a_kun
+ * @date 2024/4/16 15:29
+ */
+@Data
+public class InAppPurchaseData {
+
+ /**
+ * 应用ID。
+ */
+ private Long applicationId;
+
+ /**
+ * 消耗型商品或者非消耗型商品:固定为false。
+ *
+ * 订阅型商品:
+ *
+ * true:订阅处于活动状态并且将在下一个结算日期自动续订。
+ * false:用户已经取消订阅。 用户可以在下一个结算日期之前访问订阅内容,并且在该日期后将无法访问,除非重新启用自动续订。 如果提供了宽限期,只要宽限期未过,此值就会对所有订阅保持设置为true。 下一次结算日期每天都会自动延长,直至宽限期结束,或者用户更改付款方式。
+ */
+ private Boolean autoRenewing;
+
+ /**
+ * 订单ID,唯一标识一笔需要收费的收据,由华为应用内支付服务器在创建订单以及订阅型商品续费时生成。
+ *
+ * 每一笔新的收据都会使用不同的orderId。
+ */
+ private String orderId;
+
+ /**
+ * 商品类别,取值包括:
+ *
+ * 0:消耗型商品
+ * 1:非消耗型商品
+ * 2:订阅型商品
+ */
+ private Integer kind;
+
+ /**
+ * 商品ID。每种商品必须有唯一的ID,由应用在PMS中维护,或者应用发起购买时传入。
+ * 说明
+ * 为避免资金损失,您在对支付结果验签成功后,必须对其进行校验。
+ */
+ private String productId;
+
+ /**
+ * 商品名称。
+ */
+ private String productName;
+
+ /**
+ * 商品购买时间,UTC时间戳,以毫秒为单位。
+ */
+ private Long purchaseTime;
+
+ /**
+ * 订单交易状态。
+ *
+ * -1:初始化
+ * 0:已购买
+ * 1:已取消
+ * 2:已撤销或已退款
+ * 3:待处理
+ */
+ private Integer purchaseState;
+
+ /**
+ *
+ * 商户侧保留信息,由您在调用支付接口时传入。
+ */
+ private String developerPayload;
+
+ /**
+ *消耗状态,仅一次性商品存在,取值包括:
+ *
+ * 0:未消耗
+ * 1:已消耗
+ */
+ private Integer consumptionState;
+
+ /**
+ *确认状态,取值包括:
+ *
+ * 0 :未确认
+ * 1:已确认
+ * 没有值表示不需要确认
+ */
+ private Integer confirmed;
+
+ /**
+ * 用于唯一标识商品和用户对应关系的购买令牌,在支付完成时由华为应用内支付服务器生成。
+ * 说明
+ * 该字段是唯一标识商品和用户对应关系的,在订阅型商品正常续订时不会改变。
+ * 当前92位,后续存在扩展可能,如要进行存储,建议您预留128位的长度。
+ * 如要进行存储,为保证安全,建议加密存储。
+ */
+ private String purchaseToken;
+
+ /**
+ * 用定价货币的币种,请参见ISO 4217标准。
+ * 说明
+ * 为避免资金损失,您在对支付结果验签成功后,必须对其进行校验。
+ */
+ private String currency;
+
+ /**
+ * 商品实际价格*100以后的值。商品实际价格精确到小数点后2位,例如此参数值为501,则表示商品实际价格为5.01。
+ */
+ private Long price;
+
+ /**
+ * 支付方式,取值请参见payType说明。
+ */
+ private String payType;
+
+ /**
+ * 交易单号,用户支付成功后生成。
+ */
+ private String payOrderId;
+
+ // 以下参数只在订阅场景返回
+
+
+ /**
+ * 上次续期收款的订单ID,由支付服务器在续期扣费时生成。首次购买订阅型商品时的lastOrderId与orderId数值相同。
+ */
+ private String lastOrderId;
+
+ /**
+ * 订阅型商品所属的订阅组ID。
+ */
+ private String productGroup;
+
+ /**
+ * 原购买的时间,即本订阅型商品首次成功收费的时间,UTC时间戳,以毫秒为单位。。
+ */
+ private Long oriPurchaseTime;
+
+ /**
+ * 订阅ID。
+ * 说明
+ * subscriptionId是用户与商品之间的一一对应关系,在订阅型商品正常续订时不会改变。
+ */
+ private String subscriptionId;
+
+ /**
+ * 原订阅ID。有值表示当前订阅是从其他商品切换来的,该值可以关联切换前的商品订阅信息
+ */
+ private String oriSubscriptionId;
+
+ /**
+ * 购买数量。
+ */
+ private Integer quantity;
+
+ /**
+ * 已经付费订阅的天数,免费试用和促销期周期除外。。
+ */
+ private Long daysLasted;
+
+ /**
+ * 成功标准续期(没有设置促销的续期)的期数,为0或者不存在表示还没有成功续期。
+ */
+ private Long numOfPeriods;
+
+ /**
+ * 成功促销续期期数。
+ */
+ private Long numOfDiscount;
+
+ /**
+ * 订阅型商品过期时间,UTC时间戳,以毫秒为单位。
+ *
+ * 对于一个成功收费的自动续订收据,该时间表示续期日期或者超期日期。如果商品最近的收据的该时间是一个过去的时间,则订阅已经过期。
+ */
+ private Long expirationDate;
+
+ /**
+ * 对于已经过期的订阅,表示过期原因,取值包括:
+ *
+ * 1:用户取消
+ * 2:商品不可用
+ * 3:用户签约信息异常
+ * 4:Billing错误
+ * 5:用户未同意涨价
+ * 6:未知错误
+ * 同时有多个异常时,优先级为:1 > 2 > 3…
+ */
+ private Integer expirationIntent;
+
+ /**
+ * 订阅撤销时间,UTC时间戳,以毫秒为单位,发生退款且服务立即不可用。在顾客投诉,通过客服撤销订阅,或者顾客升级、跨级到同组其他商品并且立即生效场景下,需要撤销原有订阅的上次收据时有值。
+ * 说明
+ * 已经撤销的收据等同于没有完成购买。
+ */
+ private Long cancelTime;
+
+ /**
+ * 取消原因。
+ *
+ * 3: 应用调用IAP接口取消
+ * 2:顾客升级、跨级等。
+ * 1:顾客因为在App内遇到了问题而取消了订阅。
+ * 0:其他原因取消,比如顾客错误地订阅了商品。
+ * 说明
+ * 如果为空且cancelTime有值,表示是升级等操作导致的取消。
+ */
+ private Integer cancelReason;
+
+ /**
+ * 续期状态。
+ *
+ * 1:当前周期到期时自动续期
+ * 0:用户停止了续期
+ * 仅针对自动续期订阅,对有效和过期的订阅均有效,并不代表顾客的订阅状态。通常,取值为0时,应用可以给顾客提供其他的订阅选项,
+ * 例如推荐一个同组更低级别的商品。该值为0通常代表着顾客主动取消了该订阅。
+ */
+ private Integer renewStatus;
+
+ /**
+ * 用户取消订阅的时间,UTC时间戳,以毫秒为单位。在该时间进行了订阅续期停止的设定,商品在有效期内仍然有效,但后续的续期会终止,无退款。
+ */
+ private Integer cancellationTime;
+
+
+
+}
diff --git a/sf-payment/src/main/java/com/sf/payment/service/IHuaweiPaymentService.java b/sf-payment/src/main/java/com/sf/payment/service/IHuaweiPaymentService.java
new file mode 100644
index 0000000..1383be3
--- /dev/null
+++ b/sf-payment/src/main/java/com/sf/payment/service/IHuaweiPaymentService.java
@@ -0,0 +1,14 @@
+package com.sf.payment.service;
+
+
+import com.sf.payment.domain.HuaweiPurchasesVerifyDTO;
+
+/**
+ * 功能描述:
+ *
+ * @author a_kun
+ * @date 2024/4/12 10:21
+ */
+public interface IHuaweiPaymentService {
+ void purchasesVerify(HuaweiPurchasesVerifyDTO verifyDTO);
+}
diff --git a/sf-payment/src/main/java/com/sf/payment/service/impl/HuaweiPaymentServiceImpl.java b/sf-payment/src/main/java/com/sf/payment/service/impl/HuaweiPaymentServiceImpl.java
new file mode 100644
index 0000000..2cf3347
--- /dev/null
+++ b/sf-payment/src/main/java/com/sf/payment/service/impl/HuaweiPaymentServiceImpl.java
@@ -0,0 +1,235 @@
+package com.sf.payment.service.impl;
+
+import cn.hutool.core.date.DateField;
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.HttpUtil;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.sf.common.utils.SecurityUtils;
+import com.sf.order.domain.OrderInfo;
+import com.sf.order.service.IOrderInfoService;
+import com.sf.payment.config.HuaweiPaymentConfig;
+import com.sf.payment.domain.HuaweiPurchasesVerifyDTO;
+import com.sf.payment.domain.HuaweiPurchasesVerifyResponseDTO;
+import com.sf.payment.domain.InAppPurchaseData;
+import com.sf.payment.service.IHuaweiPaymentService;
+import com.sf.system.domain.UserMember;
+import com.sf.system.service.IUserMemberService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.codec.binary.Base64;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.Assert;
+
+import java.nio.charset.StandardCharsets;
+import java.security.KeyFactory;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.spec.X509EncodedKeySpec;
+import java.text.MessageFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * 功能描述:
+ *
+ * @author a_kun
+ * @date 2024/4/12 10:21
+ */
+@Slf4j
+@Service
+public class HuaweiPaymentServiceImpl implements IHuaweiPaymentService {
+
+ // token url to get the authorization
+ private static final String TOKEN_URL = "https://oauth-login.cloud.huawei.com/oauth2/v3/token";
+ private static final String VERIFY_TOKEN_URL = "https://orders-drcn.iap.cloud.huawei.com.cn/applications/purchases/tokens/verify";
+
+ private static final String PUBLIC_KEY = "PUBLIC_KEY";
+
+ @Autowired
+ private IOrderInfoService orderInfoService;
+
+ @Autowired
+ private IUserMemberService userMemberService;
+
+ @Autowired
+ private HuaweiPaymentConfig huaweiPaymentConfig;
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void purchasesVerify(HuaweiPurchasesVerifyDTO verifyDTO) {
+ // construct the Authorization in Header
+ Map headers = buildAuthorization(getAppAT(huaweiPaymentConfig.getClientId(), huaweiPaymentConfig.getClientSecret()));
+
+ // pack the request body
+ Map bodyMap = new HashMap<>();
+ bodyMap.put("purchaseToken", verifyDTO.getPurchaseToken());
+ bodyMap.put("productId", verifyDTO.getProductId());
+
+ String response = HttpUtil.createPost(VERIFY_TOKEN_URL)
+ .addHeaders(headers)
+ .body(JSON.toJSONString(bodyMap))
+ .execute().body();
+ HuaweiPurchasesVerifyResponseDTO huaweiPurchasesVerifyResponseDTO = JSON.parseObject(response, HuaweiPurchasesVerifyResponseDTO.class);
+ InAppPurchaseData inAppPurchaseData = JSON.parseObject(huaweiPurchasesVerifyResponseDTO.getPurchaseTokenData(), InAppPurchaseData.class);
+ // 获取服务订单
+ OrderInfo orderInfo = orderInfoService.selectOrderInfoByOrderNo(verifyDTO.getOrderNo());
+ // 校验订单
+ boolean checkSuccessOrder = checkSuccessOrder(huaweiPurchasesVerifyResponseDTO.getPurchaseTokenData()
+ , huaweiPurchasesVerifyResponseDTO.getDataSignature()
+ , PUBLIC_KEY
+ , huaweiPurchasesVerifyResponseDTO.getSignatureAlgorithm()
+ , orderInfo);
+
+ Assert.isTrue(checkSuccessOrder, "订单校验失败,请重试");
+ Assert.isTrue(inAppPurchaseData.getPurchaseState()==0, "订单未完成购买");
+ DateTime payTime = DateUtil.date(inAppPurchaseData.getPurchaseTime());
+ UserMember userMember = userMemberService.selectUserMemberByUserId(orderInfo.getCreateUserId());
+ if (userMember == null) {
+ // 添加会员信息
+ boolean isSubscription = verifyDTO.getKind() == 2;
+ userMember = new UserMember();
+ userMember.setMemberLevel(isSubscription ? 1 : 2);
+ userMember.setSubscriptionStatus(isSubscription ? 1 : 0);
+ userMember.setUserId(orderInfo.getCreateUserId());
+ userMember.setIntegration(0L);
+ DateTime expirationTime = DateUtil.offset(payTime, DateField.MONTH, 1);
+ userMember.setExpirationTime(expirationTime);
+ userMember.setCreateTime(new Date());
+ userMember.setUpdateTime(new Date());
+ userMemberService.insertUserMember(userMember);
+ } else {
+ // 更新
+ DateTime expirationTime = DateUtil.offset(userMember.getExpirationTime(), DateField.MONTH, 1);
+ userMember.setExpirationTime(expirationTime);
+ userMember.setUpdateTime(new Date());
+ userMemberService.updateUserMember(userMember);
+ }
+ // 更新订单状态
+ orderInfo.setPayTime(payTime);
+ orderInfo.setOrderStatus(3L);
+ orderInfo.setPayChannel(2L);
+ orderInfo.setPayAmt(orderInfo.getOrderAmt());
+ orderInfo.setReallyAmt(orderInfo.getOrderAmt());
+ orderInfo.setOrderStatus(3L);
+ orderInfo.setPayData(huaweiPurchasesVerifyResponseDTO.getPurchaseTokenData());
+ orderInfoService.updateOrderInfo(orderInfo);
+ }
+
+ /**
+ * Gets App Level AccessToken.
+ */
+ public static String getAppAT(String clientId, String clientSecret) {
+ // fetch accessToken
+ Map form = new HashMap<>(8);
+ form.put("grant_type", "client_credentials");
+ form.put("client_secret", clientSecret);
+ form.put("client_id", clientId);
+ String atResponse = HttpUtil.post(TOKEN_URL, form);
+ log.info("getAppAT Response : {}", atResponse);
+ JSONObject parseObject = JSON.parseObject(atResponse);
+ return parseObject.getString("access_token");
+ }
+
+ /**
+ * Build Authorization in Header
+ *
+ * @param appAt appAt
+ * @return headers
+ */
+ public static Map buildAuthorization(String appAt) {
+ String oriString = MessageFormat.format("APPAT:{0}", appAt);
+ String authorization =
+ MessageFormat.format("Basic {0}", Base64.encodeBase64String(oriString.getBytes(StandardCharsets.UTF_8)));
+ Map headers = new HashMap<>();
+ headers.put("Authorization", authorization);
+ headers.put("Content-Type", "application/json; charset=UTF-8");
+ return headers;
+ }
+
+ /**
+ * 校验签名信息,校验InAppPurchaseData中的productId、price、currency等信息的一致性
+ *
+ * @param content 结果字符串
+ * @param sign 签名字符串
+ * @param publicKey IAP公钥
+ * @return 是否校验通过
+ */
+ public static boolean checkSuccessOrder(String content, String sign, String publicKey, String signatureAlgorithm, OrderInfo orderInfo) {
+ // 校验签名信息
+ boolean checkRes = checkSign(content, sign, publicKey, StrUtil.blankToDefault(signatureAlgorithm, "SHA256WithRSA"));
+ if (checkRes) {
+ // 校验InAppPurchaseData中的productId、price、currency等信息的一致性
+ checkRes = checkProductIdAndPriceAndCurrency(content, orderInfo);
+ }
+ return checkRes;
+ }
+
+ /**
+ * 校验InAppPurchaseData中的productId、price、currency等信息的一致性
+ *
+ * @param content 结果字符串
+ * @param yourOrderInfo 您的订单信息,包括productId、price、currency
+ * @return 是否校验通过
+ */
+ public static boolean checkProductIdAndPriceAndCurrency(String content, OrderInfo yourOrderInfo) {
+ InAppPurchaseData inAppPurchaseData = JSON.parseObject(content, InAppPurchaseData.class);
+ // 校验InAppPurchaseData中的productId、price、currency等信息的一致性
+ return inAppPurchaseData.getProductId().equals(yourOrderInfo.getGoodsId())
+ && inAppPurchaseData.getPrice().equals(yourOrderInfo.getOrderAmt());
+ }
+
+ /**
+ * 校验签名信息
+ *
+ * @param content 结果字符串
+ * @param sign 签名字符串
+ * @param publicKey IAP公钥
+ * @param signatureAlgorithm 签名算法字段,可从接口返回数据中获取,例如:OwnedPurchasesResult.getSignatureAlgorithm()
+ * @return 是否校验通过
+ */
+ public static boolean checkSign(String content, String sign, String publicKey, String signatureAlgorithm) {
+ if (sign == null) {
+ return false;
+ }
+ if (publicKey == null) {
+ return false;
+ }
+
+ // 当signatureAlgorithm为空时使用默认签名算法
+ if (signatureAlgorithm == null || signatureAlgorithm.length() == 0) {
+ signatureAlgorithm = "SHA256WithRSA";
+ System.out.println("doCheck, algorithm: SHA256WithRSA");
+ }
+ try {
+ Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
+ // 生成"RSA"的KeyFactory对象
+ KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+ byte[] decodedKey = Base64.decodeBase64(publicKey);
+ // 生成公钥
+ PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(decodedKey));
+ java.security.Signature signature = null;
+ // 根据SHA256WithRSA算法获取签名对象实例
+ signature = java.security.Signature.getInstance(signatureAlgorithm);
+ // 初始化验证签名的公钥
+ signature.initVerify(pubKey);
+ // 把原始报文更新到签名对象中
+ signature.update(content.getBytes(StandardCharsets.UTF_8));
+ // 将sign解码
+ byte[] bsign = Base64.decodeBase64(sign);
+ // 进行验签
+ return signature.verify(bsign);
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return false;
+ }
+
+}
diff --git a/sf-system/src/main/java/com/sf/system/domain/UserMember.java b/sf-system/src/main/java/com/sf/system/domain/UserMember.java
new file mode 100644
index 0000000..e298567
--- /dev/null
+++ b/sf-system/src/main/java/com/sf/system/domain/UserMember.java
@@ -0,0 +1,110 @@
+package com.sf.system.domain;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.sf.common.annotation.Excel;
+import com.sf.common.core.domain.BaseEntity;
+
+/**
+ * 会员对象 User_member
+ *
+ * @author ztzh
+ * @date 2024-04-16
+ */
+public class UserMember extends BaseEntity
+{
+ private static final long serialVersionUID = 1L;
+
+ /** $column.columnComment */
+ private Long id;
+
+ /** 用户会员等级(0普通会员 1订阅会员 2月度会员) */
+ @Excel(name = "用户会员等级", readConverterExp = "0=普通会员,1=订阅会员,2=月度会员")
+ private Integer memberLevel;
+
+ /** 会员等级为订阅会员时的订阅状态,未订阅就是取消了(0未订阅 1已订阅) */
+ @Excel(name = "会员等级为订阅会员时的订阅状态,未订阅就是取消了", readConverterExp = "0=未订阅,1=已订阅")
+ private Integer subscriptionStatus;
+
+ /** 关联的用户id */
+ @Excel(name = "关联的用户id")
+ private Long userId;
+
+ /** 积分 */
+ @Excel(name = "积分")
+ private Long integration;
+
+ /** 过期时间 */
+ private Date expirationTime;
+
+ public void setId(Long id)
+ {
+ this.id = id;
+ }
+
+ public Long getId()
+ {
+ return id;
+ }
+ public void setMemberLevel(Integer memberLevel)
+ {
+ this.memberLevel = memberLevel;
+ }
+
+ public Integer getMemberLevel()
+ {
+ return memberLevel;
+ }
+ public void setSubscriptionStatus(Integer subscriptionStatus)
+ {
+ this.subscriptionStatus = subscriptionStatus;
+ }
+
+ public Integer getSubscriptionStatus()
+ {
+ return subscriptionStatus;
+ }
+ public void setUserId(Long userId)
+ {
+ this.userId = userId;
+ }
+
+ public Long getUserId()
+ {
+ return userId;
+ }
+ public void setIntegration(Long integration)
+ {
+ this.integration = integration;
+ }
+
+ public Long getIntegration()
+ {
+ return integration;
+ }
+ public void setExpirationTime(Date expirationTime)
+ {
+ this.expirationTime = expirationTime;
+ }
+
+ public Date getExpirationTime()
+ {
+ return expirationTime;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+ .append("id", getId())
+ .append("memberLevel", getMemberLevel())
+ .append("subscriptionStatus", getSubscriptionStatus())
+ .append("userId", getUserId())
+ .append("createTime", getCreateTime())
+ .append("updateTime", getUpdateTime())
+ .append("integration", getIntegration())
+ .append("expirationTime", getExpirationTime())
+ .toString();
+ }
+}
diff --git a/sf-system/src/main/java/com/sf/system/mapper/UserMemberMapper.java b/sf-system/src/main/java/com/sf/system/mapper/UserMemberMapper.java
new file mode 100644
index 0000000..f5ad663
--- /dev/null
+++ b/sf-system/src/main/java/com/sf/system/mapper/UserMemberMapper.java
@@ -0,0 +1,63 @@
+package com.sf.system.mapper;
+
+import java.util.List;
+import com.sf.system.domain.UserMember;
+
+/**
+ * 会员Mapper接口
+ *
+ * @author ztzh
+ * @date 2024-04-16
+ */
+public interface UserMemberMapper
+{
+ /**
+ * 查询会员
+ *
+ * @param id 会员主键
+ * @return 会员
+ */
+ public UserMember selectUserMemberById(Long id);
+
+ /**
+ * 查询会员列表
+ *
+ * @param userMember 会员
+ * @return 会员集合
+ */
+ public List selectUserMemberList(UserMember userMember);
+
+ /**
+ * 新增会员
+ *
+ * @param userMember 会员
+ * @return 结果
+ */
+ public int insertUserMember(UserMember userMember);
+
+ /**
+ * 修改会员
+ *
+ * @param userMember 会员
+ * @return 结果
+ */
+ public int updateUserMember(UserMember userMember);
+
+ /**
+ * 删除会员
+ *
+ * @param id 会员主键
+ * @return 结果
+ */
+ public int deleteUserMemberById(Long id);
+
+ /**
+ * 批量删除会员
+ *
+ * @param ids 需要删除的数据主键集合
+ * @return 结果
+ */
+ public int deleteUserMemberByIds(Long[] ids);
+
+ UserMember selectUserMemberByUserId(Long userId);
+}
diff --git a/sf-system/src/main/java/com/sf/system/service/IUserMemberService.java b/sf-system/src/main/java/com/sf/system/service/IUserMemberService.java
new file mode 100644
index 0000000..8e40f1a
--- /dev/null
+++ b/sf-system/src/main/java/com/sf/system/service/IUserMemberService.java
@@ -0,0 +1,63 @@
+package com.sf.system.service;
+
+import java.util.List;
+import com.sf.system.domain.UserMember;
+
+/**
+ * 会员Service接口
+ *
+ * @author ztzh
+ * @date 2024-04-16
+ */
+public interface IUserMemberService
+{
+ /**
+ * 查询会员
+ *
+ * @param id 会员主键
+ * @return 会员
+ */
+ public UserMember selectUserMemberById(Long id);
+
+ /**
+ * 查询会员列表
+ *
+ * @param userMember 会员
+ * @return 会员集合
+ */
+ public List selectUserMemberList(UserMember userMember);
+
+ /**
+ * 新增会员
+ *
+ * @param userMember 会员
+ * @return 结果
+ */
+ public int insertUserMember(UserMember userMember);
+
+ /**
+ * 修改会员
+ *
+ * @param userMember 会员
+ * @return 结果
+ */
+ public int updateUserMember(UserMember userMember);
+
+ /**
+ * 批量删除会员
+ *
+ * @param ids 需要删除的会员主键集合
+ * @return 结果
+ */
+ public int deleteUserMemberByIds(Long[] ids);
+
+ /**
+ * 删除会员信息
+ *
+ * @param id 会员主键
+ * @return 结果
+ */
+ public int deleteUserMemberById(Long id);
+
+ UserMember selectUserMemberByUserId(Long userId);
+}
diff --git a/sf-system/src/main/java/com/sf/system/service/impl/UserMemberServiceImpl.java b/sf-system/src/main/java/com/sf/system/service/impl/UserMemberServiceImpl.java
new file mode 100644
index 0000000..6c2890c
--- /dev/null
+++ b/sf-system/src/main/java/com/sf/system/service/impl/UserMemberServiceImpl.java
@@ -0,0 +1,101 @@
+package com.sf.system.service.impl;
+
+import java.util.List;
+import com.sf.common.utils.DateUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.sf.system.mapper.UserMemberMapper;
+import com.sf.system.domain.UserMember;
+import com.sf.system.service.IUserMemberService;
+
+/**
+ * 会员Service业务层处理
+ *
+ * @author ztzh
+ * @date 2024-04-16
+ */
+@Service
+public class UserMemberServiceImpl implements IUserMemberService
+{
+ @Autowired
+ private UserMemberMapper userMemberMapper;
+
+ /**
+ * 查询会员
+ *
+ * @param id 会员主键
+ * @return 会员
+ */
+ @Override
+ public UserMember selectUserMemberById(Long id)
+ {
+ return userMemberMapper.selectUserMemberById(id);
+ }
+
+ /**
+ * 查询会员列表
+ *
+ * @param userMember 会员
+ * @return 会员
+ */
+ @Override
+ public List selectUserMemberList(UserMember userMember)
+ {
+ return userMemberMapper.selectUserMemberList(userMember);
+ }
+
+ /**
+ * 新增会员
+ *
+ * @param userMember 会员
+ * @return 结果
+ */
+ @Override
+ public int insertUserMember(UserMember userMember)
+ {
+ userMember.setCreateTime(DateUtils.getNowDate());
+ return userMemberMapper.insertUserMember(userMember);
+ }
+
+ /**
+ * 修改会员
+ *
+ * @param userMember 会员
+ * @return 结果
+ */
+ @Override
+ public int updateUserMember(UserMember userMember)
+ {
+ userMember.setUpdateTime(DateUtils.getNowDate());
+ return userMemberMapper.updateUserMember(userMember);
+ }
+
+ /**
+ * 批量删除会员
+ *
+ * @param ids 需要删除的会员主键
+ * @return 结果
+ */
+ @Override
+ public int deleteUserMemberByIds(Long[] ids)
+ {
+ return userMemberMapper.deleteUserMemberByIds(ids);
+ }
+
+ /**
+ * 删除会员信息
+ *
+ * @param id 会员主键
+ * @return 结果
+ */
+ @Override
+ public int deleteUserMemberById(Long id)
+ {
+ return userMemberMapper.deleteUserMemberById(id);
+ }
+
+ @Override
+ public UserMember selectUserMemberByUserId(Long userId) {
+ return userMemberMapper.selectUserMemberByUserId(userId);
+ }
+}
diff --git a/sf-system/src/main/resources/mapper/system/UserMemberMapper.xml b/sf-system/src/main/resources/mapper/system/UserMemberMapper.xml
new file mode 100644
index 0000000..3c8a8a0
--- /dev/null
+++ b/sf-system/src/main/resources/mapper/system/UserMemberMapper.xml
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select id, member_level, subscription_status, user_id, create_time, update_time, integration, expiration_time from User_member
+
+
+
+
+
+
+
+
+
+ insert into User_member
+
+ member_level,
+ subscription_status,
+ user_id,
+ create_time,
+ update_time,
+ integration,
+ expiration_time,
+
+
+ #{memberLevel},
+ #{subscriptionStatus},
+ #{userId},
+ #{createTime},
+ #{updateTime},
+ #{integration},
+ #{expirationTime},
+
+
+
+
+ update User_member
+
+ member_level = #{memberLevel},
+ subscription_status = #{subscriptionStatus},
+ user_id = #{userId},
+ create_time = #{createTime},
+ update_time = #{updateTime},
+ integration = #{integration},
+ expiration_time = #{expirationTime},
+
+ where id = #{id}
+
+
+
+ delete from User_member where id = #{id}
+
+
+
+ delete from User_member where id in
+
+ #{id}
+
+
+
\ No newline at end of file