记得上下班打卡 | git大法好,push需谨慎

Commit fd0e404d authored by 姜秀龙's avatar 姜秀龙

Merge remote-tracking branch 'origin/dev-1.6-shouqianba' into dev-1.6-shouqianba

parents 9d6fdcc2 ca0f6dcc
......@@ -54,6 +54,7 @@ CREATE TABLE `goblin_sqb_order` (
`sqb_order_sn` VARCHAR(64) COMMENT '收钱吧订单号',
`sqb_order_signature` VARCHAR(256) COMMENT '收钱吧订单签名',
`sqb_acquiring_sn` VARCHAR(64) COMMENT '收钱吧收单号',
`sqb_acquiring_sign` VARCHAR(255) DEFAULT '' COMMENT '收钱吧收单密钥',
`sqb_checkout_items_id` VARCHAR(64) COMMENT '结算明细ID',
`coupon_sn` VARCHAR(64) COMMENT '券码编号',
`coupon_qr_code` VARCHAR(512) COMMENT '核销二维码',
......
......@@ -27,6 +27,12 @@
<artifactId>liquidnet-service-dragon-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.liquidnet</groupId>
<artifactId>liquidnet-common-third-sqb</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
......@@ -446,4 +446,10 @@ public class GoblinRedisConst {
*/
public static final String SQB_ORDER_LOCK = PREFIX.concat("sqb:order:lock:");
/**
* 收钱吧 用户订单列表
*/
public static final String SQB_GOBLIN_ORDER_LIST = PREFIX.concat("sqb:order:id:list:");//用户订单id列表 key:$uid
}
package com.liquidnet.service.goblin.dto.manage;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@ApiModel(value = "GoblinSqbOrderParam")
@Data
public class GoblinSqbOrderParam {
@ApiModelProperty(required = true, value = "apuId")
@NotBlank(message = "商品不能为空")
private String spuId;
@ApiModelProperty(required = true, value = "skuId")
@NotBlank(message = "商品规格不能为空")
private String skuId;
@ApiModelProperty(required = true, value = "购买数量")
@NotNull(message = "购买数量不能为空")
private Integer quantity;
@ApiModelProperty(required = true, value = "关联演出ID")
@NotBlank(message = "关联演出ID不能为空")
private String performancesId;
}
package com.liquidnet.service.goblin.dto.manage;
import com.liquidnet.common.third.sqb.param.response.data.MallProductsQueryData;
import com.liquidnet.commons.lang.constant.LnsRegex;
import com.liquidnet.commons.lang.util.CollectionUtil;
import com.liquidnet.commons.lang.util.DateUtil;
import com.liquidnet.commons.lang.util.IDGenerator;
import com.liquidnet.service.goblin.dto.GoblinGoodsSpecDto;
import com.liquidnet.service.goblin.dto.vo.*;
import com.liquidnet.service.goblin.param.shouqianba.response.data.MallProductsQueryData;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
......@@ -152,7 +151,6 @@ public class GoblinStoreMgtGoodsSqbAddParam implements Serializable {
}
/**
* 编辑SPU参数整理
*
......
......@@ -78,7 +78,7 @@ public class GoblinOrderSkuVo implements Serializable, Cloneable {
* ---------------------------- 以下为券类商品-代金券属性 ----------------------------
*/
@ApiModelProperty(value = "商品类型[0-常规|1-数字藏品|2-券类商品]")
@ApiModelProperty(value = "商品类型[0-常规|1-数字藏品|2-券类商品] 33-收钱吧商品")
private Integer skuType;
@ApiModelProperty(value = "是否实名[0-否|1-是,表示该商品需要实名关联],这里默认0")
private Integer isTrueName;
......
package com.liquidnet.service.goblin.dto.vo;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import java.io.Serializable;
@Data
@ApiModel(value = "用户端-查询券码-VO")
public class GoblinSqbCouponVo implements Serializable {
private static final long serialVersionUID = 1L;
private String couponSn;
......
package com.liquidnet.service.goblin.dto.vo;
import lombok.Data;
import java.io.Serializable;
@Data
......@@ -16,13 +17,17 @@ public class GoblinSqbOrderVo implements Serializable {
private String sqbOrderSn;
private String sqbOrderSignature;
private String sqbAcquiringSn;
private String sqbAcquiringSign;
private String sqbCheckoutItemsId;
private String couponSn;
private String couponQrCode;
private String couponExpireTime;
private Integer status; // 0-待支付 1-已支付 2-已核销 3-已退款 4-退款中 9-失败
private Integer couponUsedStatus; // 0-未核销 1-已核销
private String refundReason;
private String createdAt;
private String updatedAt;
// 扩展属性
private Integer couponUsedStatus; // 0-未核销 1-已核销
}
package com.liquidnet.service.goblin.dto.vo;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.liquidnet.service.goblin.param.shouqianba.response.data.MallProductsQueryData;
import com.liquidnet.common.third.sqb.param.response.data.MallProductsQueryData;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
......
package com.liquidnet.service.goblin.param.shouqianba.callback;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "CallbackParams", description = "收钱吧微信小店订单推送请求体")
public class CallbackParams {
@ApiModelProperty(value = "推送事件ID,全局唯一", example = "2024013000594610646")
private Long eventId;
@ApiModelProperty(value = "推送时间戳,当前时间毫秒值", example = "1706679507593")
private Long timestamp;
@ApiModelProperty(value = "随机字串,用于签名", example = "j9xd5kc7ixcryy7at5rrrv24xty783th")
private String nonce;
@ApiModelProperty(value = "订单数据 JSON字符串 (详见 SqbOrderContentDTO)")
private String content;
@ApiModelProperty(value = "报文签名", example = "bryyeKJ6opUothNTz1s3+F98LOl2Teji6T4XcEAejxdt...")
private String signature;
}
package com.liquidnet.service.goblin.param.shouqianba.request;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
@Data
@ApiModel(value = "券码状态同步")
public class CouponStatusSyncRequest {
@ApiModelProperty(required = true, value = "应用ID(聚合收单唯一ID,需申请)")
private String appid;
@ApiModelProperty(required = true, value = "券号")
private List<String> voucherNos;
@ApiModelProperty(required = true, value = "用户ID(自定义,核销用户id)")
private String redeemMerchantId;
@ApiModelProperty(required = true, value = "外部单号(${AppCode}+id,AppCode需要分配)")
private String redeemExternalOrderSn;
@ApiModelProperty(required = true, value = "来源(固定值:EXTERN)")
private String redeemSource;
@ApiModelProperty(required = true, value = "核销终端号(自定义)")
private String clientSn;
@ApiModelProperty(required = true, value = "券使用状态(0未核销,1已核销)")
private Byte status;
}
package com.liquidnet.service.goblin.param.shouqianba.request;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
/**
* 收钱吧商品同步单项参数
*/
@Data
public class GoblinSqbGoodsSyncParam implements Serializable {
private static final long serialVersionUID = 1L;
@NotBlank(message = "收钱吧商品 ID 不能为空")
@ApiModelProperty(value = "收钱吧商品 ID (对应 spuId)", required = true)
private String sqbProductId;
@ApiModelProperty(value = "收钱吧商品编码 (非必填)")
private String sqbProductSn;
@NotBlank(message = "商城编号不能为空")
@ApiModelProperty(value = "收钱吧商城编号", required = true)
private String mallSn;
@NotBlank(message = "商城签名不能为空")
@ApiModelProperty(value = "收钱吧商城签名", required = true)
private String mallSignature;
}
package com.liquidnet.service.goblin.service;
import com.liquidnet.service.goblin.param.shouqianba.callback.CallbackParams;
import com.liquidnet.service.goblin.param.shouqianba.request.*;
import com.liquidnet.service.goblin.param.shouqianba.response.data.*;
import java.util.List;
import java.util.Map;
/**
* 收钱吧对接接口定义
*
* @author liquidnet
* @since 2026-03-16
*/
public interface IGoblinShouQianBaService {
/**
* 创建结算明细
* <p>
* 对接收钱吧「创建结算明细」接口,向收钱吧上传订单结算数据。
* </p>
*
* @param request 创建结算明细请求参数
* @return 收钱吧响应结果;调用失败时返回 null
*/
SettlementCreateData createSettlement(SettlementCreateRequest request);
/**
*
* @param mallSn 商城ID
* @param signature 商城密钥
* @param userId 正在用户ID
* @param checkoutItems 商品
* @return
*/
SettlementCreateData createSettlement(String mallSn, String signature, String userId, List<SettlementCreateRequest.CheckoutItem> checkoutItems);
/**
* 创建订单
*
* @param request
* @return
*/
OrderCreateData createOrder(OrderCreateRequest request);
/**
*
* @param mallSn 商城ID
* @param signature 商城密钥
* @param checkoutItemsId 创建结算明细 返回的 结算项ID
* @param userId 正在用户ID
* @param requestId 请求ID
* @param subject 标题
* @return
*/
OrderCreateData createOrder(String mallSn, String signature, String checkoutItemsId, String userId, String requestId, String subject);
/**
* 创建收单
* 如果上一步创建收单失败 可以使用这个接口重新创建收单
*
* @return
*/
AcquiringCreateData createAcquiring(AcquiringCreateRequest request);
/**
* 查询收银台
*
* @param request
* @return
*/
CashierQueryData queryCashier(CashierQueryRequest request);
/**
* 查询收银台
* @param acquiringSn 收单号
* @param acquiringSignature 收单密钥
* @param userId 正在用户ID
* @return
*/
CashierQueryData queryCashier(String acquiringSn, String acquiringSignature, String userId);
/**
* 创建微信预支付订单
*
* @param request
* @return
*/
CreateWechatPrepayOrderData createWechatPrepayOrder(CreateWechatPrepayOrderRequest request);
/**
* 创建微信预支付订单
*
* @param acquiringSn 收单号
* @param signature 收单签名
* @param userId 正在用户ID
* @param amount 支付金额
* @param requestSn 支付请求号
* @param payTool 支付工具代码
* @param channelExt 通道扩展参数
* @param selectedSignature 支付工具签名
* @param seq 序列号 上一步seq(查询收银台)
* @return
*/
CreateWechatPrepayOrderData createWechatPrepayOrder(String acquiringSn,
String signature,
String userId,
String amount,
String requestSn,
CashierQueryData.PayTool payTool,
Map<String, Object> channelExt,
String selectedSignature,
String seq);
/**
* 查询券码
*
* @param request
* @return
*/
CouponQueryData queryCoupon(CouponQueryRequest request);
/**
* 查询券码
* @param sn 订单ID
* @param signature 订单密码
* @return
*/
CouponQueryData queryCoupon(String sn, String signature);
/**
* 券码状态同步
*
* @param request
* @return
*/
boolean syncCouponStatus(CouponStatusSyncRequest request);
/**
* 券码状态同步
* @param redeemMerchantId 用户ID(自定义,核销用户id)
* @param voucherNos 券号
* @param redeemExternalOrderSn 外部单号(${AppCode}+id,AppCode需要分配)
* @param clientSn 核销终端号(自定义)
* @param status 券使用状态(0未核销,1已核销)
* @return
*/
boolean syncCouponStatus(String redeemMerchantId,
List<String> voucherNos,
String redeemExternalOrderSn,
String clientSn,
Byte status);
/**
* 券退款
*
* @param request
* @return
*/
CouponRefundData refundCoupon(CouponRefundRequest request);
/**
* @param sn 单号(前置操作后拿到)
* @param signature 密码(前置操作后拿到)
* @param applyAmount 金额
* @param type 退款类型(1商品 2金额)
* @param item
* @param refundReason 退款原因
* @param requestId 退款请求id(${AppCode}+id)
* @return
*/
CouponRefundData refundCoupon(String sn,
String signature,
Long applyAmount,
Byte type,
List<CouponRefundRequest.RefundItem> item,
String refundReason,
String requestId);
/**
* 商城列表接口
*
* @param request
* @return
*/
List<MallListQueryData> queryMallList(MallListQueryRequest request);
/**
*
* @param endCursor 结束游标 上一页的结束游标(首次查询传 null)
* @param count 查询数量 每页返回的最大订单数
* @return
*/
List<MallListQueryData> queryMallList(String endCursor, Integer count);
/**
* 商城商品接口
*
* @param request
* @return
*/
List<MallProductsQueryData> queryMallProducts(MallProductsQueryRequest request);
/**
* 商城商品接口
* @param mallSn 商城ID
* @param signature 商城密码
* @return
*/
List<MallProductsQueryData> queryMallProducts(String mallSn, String signature);
/**
* 验签
* @param callbackParams
* @return
*/
boolean verifySignature(CallbackParams callbackParams);
}
package com.liquidnet.service.goblin.service;
import com.liquidnet.common.third.sqb.param.callback.CouponCallbackContent;
import com.liquidnet.common.third.sqb.param.callback.OrderCallbackContent;
import com.liquidnet.common.third.sqb.param.callback.RefundCallbackContent;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.goblin.dto.vo.GoblinSqbCouponVo;
import com.liquidnet.service.goblin.dto.manage.GoblinSqbOrderParam;
import com.liquidnet.service.goblin.dto.vo.GoblinSqbOrderCreateVo;
import com.liquidnet.service.goblin.dto.vo.GoblinSqbOrderDetailVo;
import com.liquidnet.service.goblin.param.shouqianba.callback.CouponCallbackContent;
import com.liquidnet.service.goblin.param.shouqianba.callback.OrderCallbackContent;
import com.liquidnet.service.goblin.param.shouqianba.callback.RefundCallbackContent;
import java.util.List;
/**
* 收钱吧订单服务接口
......@@ -19,50 +16,31 @@ public interface IGoblinSqbOrderService {
* 创建收钱吧订单
*
* @param userId 用户ID(从 token 获取)
* @param spuId 商品 SPU ID
* @param skuId 商品 SKU ID
* @param quantity 购买数量
* @param performancesId 关联演出 ID
* @param orderParam
* @return 订单创建结果(orderId、acquiringSn、paymentVoucher)
*/
ResponseDto<GoblinSqbOrderCreateVo> createOrder(String userId, String spuId, String skuId,
Integer quantity, String performancesId);
ResponseDto<GoblinSqbOrderCreateVo> createOrder(String userId, GoblinSqbOrderParam orderParam);
/**
* 查询支付状态
*
* @param userId 用户ID
* @param orderId 本地订单ID
* @return 支付状态(0-待支付 1-已支付 9-失败)
*/
ResponseDto<Integer> queryPayStatus(String userId, String orderId);
/**
* 获取核销二维码(券码
* 再次付款(待支付状态下重新拉起微信支付
*
* @param userId 用户ID
* @param orderId 本地订单ID
* @return 券码信息(couponSn、couponQrCode、couponExpireTime
* @return 新的 paymentVoucher(复用原 orderId
*/
ResponseDto<GoblinSqbCouponVo> queryCoupon(String userId, String orderId);
ResponseDto<GoblinSqbOrderCreateVo> repay(String userId, String orderId);
/**
* 申请退款
*
* @param userId 用户ID
* @param orderId 本地订单ID
* @return 退款结果
*/
ResponseDto<Boolean> refund(String userId, String orderId);
/**
* 主动同步核销状态
* 查询支付状态
*
* @param userId 用户ID
* @param orderId 本地订单ID
* @return 同步结果
* @return 支付状态(0-待支付 1-已支付 9-失败)
*/
ResponseDto<Boolean> syncCouponStatus(String userId, String orderId);
ResponseDto<Integer> queryPayStatus(String userId, String orderId);
/**
* 支付成功回调(收钱吧主动推送)
......@@ -85,37 +63,4 @@ public interface IGoblinSqbOrderService {
*/
ResponseDto<String> handleCouponCallback(CouponCallbackContent callbackContent);
/**
* 演出结束自动退款(定时任务调用)
*
* @param performancesId 演出ID
* @return 处理结果摘要(成功/失败笔数)
*/
ResponseDto<String> autoRefundByPerformance(String performancesId);
/**
* 查询用户收钱吧订单列表
*
* @param userId 用户ID
* @return 收钱吧订单列表(仅 skuType=33 的订单,按下单时间倒序)
*/
ResponseDto<List<GoblinSqbOrderDetailVo>> getOrderList(String userId);
/**
* 查询收钱吧订单详情
*
* @param userId 用户ID
* @param orderId 本地订单ID
* @return 订单详情(基础信息 + 收钱吧扩展信息)
*/
ResponseDto<GoblinSqbOrderDetailVo> getOrderDetail(String userId, String orderId);
/**
* 再次付款(待支付状态下重新拉起微信支付)
*
* @param userId 用户ID
* @param orderId 本地订单ID
* @return 新的 paymentVoucher(复用原 orderId)
*/
ResponseDto<GoblinSqbOrderCreateVo> repay(String userId, String orderId);
}
package com.liquidnet.service.goblin.service;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.goblin.dto.vo.GoblinSqbCouponVo;
import com.liquidnet.service.goblin.dto.vo.GoblinSqbOrderDetailVo;
import java.util.List;
public interface IGoblinSqbService {
/**
* 获取核销二维码(券码)
*
* @param userId 用户ID
* @param orderId 本地订单ID
* @return 券码信息(couponSn、couponQrCode、couponExpireTime)
*/
ResponseDto<GoblinSqbCouponVo> queryCoupon(String userId, String orderId);
/**
* 申请退款
*
* @param userId 用户ID
* @param orderId 本地订单ID
* @return 退款结果
*/
ResponseDto<Boolean> refund(String userId, String orderId);
/**
* 主动同步核销状态
*
* @param userId 用户ID
* @param orderId 本地订单ID
* @return 同步结果
*/
ResponseDto<Boolean> syncCouponStatus(String userId, String orderId);
/**
* 演出结束自动退款(定时任务调用)
* TODO
* @param performancesId 演出ID
* @return 处理结果摘要(成功/失败笔数)
*/
ResponseDto<String> autoRefundByPerformance(String performancesId);
/**
* 查询用户收钱吧订单列表
*
* @param userId 用户ID
* @return 收钱吧订单列表(仅 skuType=33 的订单,按下单时间倒序)
*/
ResponseDto<List<GoblinSqbOrderDetailVo>> getOrderList(String userId);
/**
* 查询收钱吧订单详情
*
* @param userId 用户ID
* @param orderId 本地订单ID
* @return 订单详情(基础信息 + 收钱吧扩展信息)
*/
ResponseDto<GoblinSqbOrderDetailVo> getOrderDetail(String userId, String orderId);
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.liquidnet</groupId>
<artifactId>liquidnet-common-third</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>liquidnet-common-third-sqb</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.liquidnet</groupId>
<artifactId>liquidnet-common-base</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package com.liquidnet.service.goblin.service.impl;
package com.liquidnet.common.third.sqb.biz;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.liquidnet.commons.lang.util.MD5Utils;
import com.liquidnet.service.goblin.config.properties.ShouqianbaProperties;
import com.liquidnet.service.goblin.param.shouqianba.callback.CallbackParams;
import com.liquidnet.service.goblin.param.shouqianba.request.*;
import com.liquidnet.service.goblin.param.shouqianba.response.*;
import com.liquidnet.service.goblin.param.shouqianba.response.data.*;
import com.liquidnet.service.goblin.service.IGoblinShouQianBaService;
import com.liquidnet.common.third.sqb.config.SqbConfig;
import com.liquidnet.common.third.sqb.param.callback.CallbackParams;
import com.liquidnet.common.third.sqb.param.request.*;
import com.liquidnet.common.third.sqb.param.response.*;
import com.liquidnet.common.third.sqb.param.response.data.*;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.stereotype.Service;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
......@@ -31,23 +31,22 @@ import java.util.List;
import java.util.Map;
/**
* 收钱吧对接实现
* 收钱吧对接公共工具
*
* @author liquidnet
* @since 2026-03-16
*/
@Slf4j
@Service
public class GoblinShouQianBaServiceImpl implements IGoblinShouQianBaService {
@Component
public class SqbBiz {
private final ShouqianbaProperties shouqianbaProperties;
@Getter
private final SqbConfig sqbConfig;
private final CommonRequest.Seller cachedSeller;
public GoblinShouQianBaServiceImpl(ShouqianbaProperties properties) {
this.shouqianbaProperties = properties;
if (this.shouqianbaProperties == null) {
throw new IllegalArgumentException("找不到应用配置");
public SqbBiz(SqbConfig properties) {
this.sqbConfig = properties;
if (this.sqbConfig == null) {
throw new IllegalArgumentException("找不到收钱吧应用配置");
}
// 商户信息来自配置,整个生命周期内不变,提前构建并缓存
this.cachedSeller = new CommonRequest.Seller();
......@@ -59,7 +58,6 @@ public class GoblinShouQianBaServiceImpl implements IGoblinShouQianBaService {
private static final ObjectMapper objectMapper;
private static final RestTemplate restTemplate;
static {
// 1. 初始化 RestTemplate 并强制设置 String 转换器为 UTF-8
restTemplate = new RestTemplate();
......@@ -77,15 +75,12 @@ public class GoblinShouQianBaServiceImpl implements IGoblinShouQianBaService {
* @param request 创建结算明细请求参数
* @return 收钱吧响应结果;调用失败时返回 null
*/
@Override
public SettlementCreateData createSettlement(SettlementCreateRequest request) {
return executeShouQianBaRequest("/optimus/core/mall/createCheckoutItems", "创建结算明细", request, SettlementCreateResponse.class);
}
@Override
public SettlementCreateData createSettlement(String mallSn, String signature, String userId, List<SettlementCreateRequest.CheckoutItem> checkoutItems) {
SettlementCreateRequest request = new SettlementCreateRequest();
request.setAppid(shouqianbaProperties.getAppId());
request.setAppid(sqbConfig.getAppId());
request.setMallID(buildMall(mallSn, signature));
request.setSeller(cachedSeller);
request.setBuyer(buildBuyer(userId));
......@@ -93,34 +88,15 @@ public class GoblinShouQianBaServiceImpl implements IGoblinShouQianBaService {
return createSettlement(request);
}
private CommonRequest.Mall buildMall(String mallSn, String signature) {
CommonRequest.Mall mall = new CommonRequest.Mall();
mall.setMallSn(mallSn);
mall.setSignature(signature);
return mall;
}
private CommonRequest.Buyer buildBuyer(String userId) {
CommonRequest.Buyer buyer = new CommonRequest.Buyer();
buyer.setBuyerId(userId);
return buyer;
}
/**
* 创建订单
*
* @param request
* @return
*/
@Override
public OrderCreateData createOrder(OrderCreateRequest request) {
return executeShouQianBaRequest("/optimus/core/order/placeOrder", "创建订单", request, OrderCreateResponse.class);
}
@Override
public OrderCreateData createOrder(String mallSn, String signature, String checkoutItemsId, String userId, String requestId, String subject) {
OrderCreateRequest orderCreateRequest = new OrderCreateRequest();
orderCreateRequest.setAppid(shouqianbaProperties.getAppId());
orderCreateRequest.setAppid(sqbConfig.getAppId());
orderCreateRequest.setMallID(buildMall(mallSn, signature));
orderCreateRequest.setSeller(cachedSeller);
orderCreateRequest.setCheckoutItemsId(checkoutItemsId);
......@@ -132,33 +108,23 @@ public class GoblinShouQianBaServiceImpl implements IGoblinShouQianBaService {
/**
* 创建收单
* 如果上一步创建收单失败 可以使用这个接口重新创建收单
*
* @return
*/
@Override
public AcquiringCreateData createAcquiring(AcquiringCreateRequest request) {
return executeShouQianBaRequest("/optimus/core/order/createAcquiring", "创建收单环节", request, AcquiringCreateResponse.class);
}
/**
* 查询收银台
*
* @param request
* @return
*/
@Override
public CashierQueryData queryCashier(CashierQueryRequest request) {
return executeShouQianBaRequest("/optimus/core/cashier/queryCashierPage", "查询收银台", request, CashierQueryResponse.class);
}
@Override
public CashierQueryData queryCashier(String acquiringSn, String acquiringSignature, String userId) {
CashierQueryRequest.PaymentEnv paymentEnv = new CashierQueryRequest.PaymentEnv();
paymentEnv.setClient("wechat");
CashierQueryRequest cashierQueryRequest = new CashierQueryRequest();
cashierQueryRequest.setAppid(shouqianbaProperties.getAppId());
cashierQueryRequest.setAppid(sqbConfig.getAppId());
cashierQueryRequest.setSeller(cachedSeller);
cashierQueryRequest.setPaymentMode(4);
cashierQueryRequest.setPaymentEnv(paymentEnv);
......@@ -170,16 +136,10 @@ public class GoblinShouQianBaServiceImpl implements IGoblinShouQianBaService {
/**
* 创建微信预支付订单
*
* @param request
* @return
*/
@Override
public CreateWechatPrepayOrderData createWechatPrepayOrder(CreateWechatPrepayOrderRequest request) {
return executeShouQianBaRequest("/optimus/core/cashier/proxyPreCreatedPay", "创建微信预支付订单", request, CreateWechatPrepayOrderResponse.class);
}
@Override
public CreateWechatPrepayOrderData createWechatPrepayOrder(String acquiringSn,
String signature,
String userId,
......@@ -190,7 +150,7 @@ public class GoblinShouQianBaServiceImpl implements IGoblinShouQianBaService {
String selectedSignature,
String seq) {
CreateWechatPrepayOrderRequest orderRequest = new CreateWechatPrepayOrderRequest();
orderRequest.setAppid(shouqianbaProperties.getAppId());
orderRequest.setAppid(sqbConfig.getAppId());
orderRequest.setSeller(cachedSeller);
orderRequest.setAcquiringSn(acquiringSn);
orderRequest.setSignature(signature);
......@@ -200,39 +160,16 @@ public class GoblinShouQianBaServiceImpl implements IGoblinShouQianBaService {
return createWechatPrepayOrder(orderRequest);
}
private List<CreateWechatPrepayOrderRequest.UsingPayTool> buildUsingPayTools(String requestSn,
CashierQueryData.PayTool payTool,
Map<String, Object> channelExt,
String amount,
String userId) {
CreateWechatPrepayOrderRequest.UsingPayTool tool = new CreateWechatPrepayOrderRequest.UsingPayTool();
tool.setId(payTool.getId());
tool.setPayTool(Integer.valueOf(payTool.getCode()));
tool.setPayMode(4); // TODO 需要确认
tool.setAmount(amount);
tool.setIdentity(userId);
tool.setAmountComposition(payTool.getAmountComposition());
tool.setRequestSn(requestSn);
tool.setChannelExt(channelExt);
return Collections.singletonList(tool);
}
/**
* 查询券码
*
* @param request
* @return
*/
@Override
public CouponQueryData queryCoupon(CouponQueryRequest request) {
return executeShouQianBaRequest("/optimus/core/voucher/queryOrderVoucherList", "查询优惠券", request, CouponQueryResponse.class);
}
@Override
public CouponQueryData queryCoupon(String sn, String signature) {
CouponQueryRequest couponQueryRequest = new CouponQueryRequest();
couponQueryRequest.setAppid(shouqianbaProperties.getAppId());
couponQueryRequest.setAppid(sqbConfig.getAppId());
couponQueryRequest.setSeller(cachedSeller);
couponQueryRequest.setOrderID(new CommonRequest.OrderInfo(sn, signature));
return queryCoupon(couponQueryRequest);
......@@ -240,20 +177,14 @@ public class GoblinShouQianBaServiceImpl implements IGoblinShouQianBaService {
/**
* 券码状态同步
*
* @param request
* @return
*/
@Override
public boolean syncCouponStatus(CouponStatusSyncRequest request) {
CouponStatusSyncResponse response = executeRequestAndGetResponse("/optimus/core/voucher/modifyOrderVoucherList", "同步优惠券状态", request, CouponStatusSyncResponse.class);
return response != null && Boolean.TRUE.equals(response.getSuccess());
}
@Override
public boolean syncCouponStatus(String redeemMerchantId, List<String> voucherNos, String redeemExternalOrderSn, String clientSn, Byte status) {
CouponStatusSyncRequest couponStatusSyncRequest = new CouponStatusSyncRequest();
couponStatusSyncRequest.setAppid(shouqianbaProperties.getAppId());
couponStatusSyncRequest.setAppid(sqbConfig.getAppId());
couponStatusSyncRequest.setVoucherNos(voucherNos);
couponStatusSyncRequest.setRedeemSource("EXTERN");
couponStatusSyncRequest.setRedeemExternalOrderSn(redeemExternalOrderSn);
......@@ -265,16 +196,10 @@ public class GoblinShouQianBaServiceImpl implements IGoblinShouQianBaService {
/**
* 券退款
*
* @param request
* @return
*/
@Override
public CouponRefundData refundCoupon(CouponRefundRequest request) {
return executeShouQianBaRequest("/optimus/core/aftersale/applyRefund", "退款优惠券", request, CouponRefundResponse.class);
}
@Override
public CouponRefundData refundCoupon(String sn,
String signature,
Long applyAmount,
......@@ -283,7 +208,7 @@ public class GoblinShouQianBaServiceImpl implements IGoblinShouQianBaService {
String refundReason,
String requestId) {
CouponRefundRequest couponRefundRequest = new CouponRefundRequest();
couponRefundRequest.setAppid(shouqianbaProperties.getAppId());
couponRefundRequest.setAppid(sqbConfig.getAppId());
couponRefundRequest.setSeller(cachedSeller);
couponRefundRequest.setOrderID(new CommonRequest.OrderInfo(sn, signature));
couponRefundRequest.setRefundInfo(new CouponRefundRequest.RefundInfo(applyAmount, type, item, refundReason));
......@@ -294,18 +219,11 @@ public class GoblinShouQianBaServiceImpl implements IGoblinShouQianBaService {
/**
* 商城列表接口
*
* @param request
* @return
*/
@Override
public List<MallListQueryData> queryMallList(MallListQueryRequest request) {
return executeShouQianBaRequest("/optimus/core/open/mall/queryMallList", "查询门店列表", request, MallListQueryResponse.class);
}
@Override
public List<MallListQueryData> queryMallList(String endCursor, Integer count) {
MallListQueryRequest.Filter filter = new MallListQueryRequest.Filter();
filter.setSeller(cachedSeller);
......@@ -319,7 +237,7 @@ public class GoblinShouQianBaServiceImpl implements IGoblinShouQianBaService {
sort.setSort("DESC");
MallListQueryRequest mallListQueryRequest = new MallListQueryRequest();
mallListQueryRequest.setAppid(shouqianbaProperties.getAppId());
mallListQueryRequest.setAppid(sqbConfig.getAppId());
mallListQueryRequest.setFilter(filter);
mallListQueryRequest.setCursor(cursor);
mallListQueryRequest.setSort(sort);
......@@ -328,19 +246,13 @@ public class GoblinShouQianBaServiceImpl implements IGoblinShouQianBaService {
/**
* 商城商品接口
*
* @param request
* @return
*/
@Override
public List<MallProductsQueryData> queryMallProducts(MallProductsQueryRequest request) {
return executeShouQianBaRequest("/optimus/core/open/mall/queryMallProducts", "查询门店商品", request, MallProductsQueryResponse.class);
}
@Override
public List<MallProductsQueryData> queryMallProducts(String mallSn, String signature) {
MallProductsQueryRequest request = new MallProductsQueryRequest();
request.setAppid(shouqianbaProperties.getAppId());
request.setAppid(sqbConfig.getAppId());
request.setSeller(cachedSeller);
request.setMallID(new CommonRequest.Mall(mallSn, signature));
return queryMallProducts(request);
......@@ -351,7 +263,7 @@ public class GoblinShouQianBaServiceImpl implements IGoblinShouQianBaService {
*/
private <T extends BaseResponse<?>> T executeRequestAndGetResponse(
String apiPath, String businessName, Object request, Class<T> responseClass) {
final String url = shouqianbaProperties.getBaseApi() + apiPath;
final String url = sqbConfig.getBaseApi() + apiPath;
log.info("[收钱吧] {}, 请求URL: {}, 请求参数: {}", businessName, url, request);
try {
......@@ -368,7 +280,6 @@ public class GoblinShouQianBaServiceImpl implements IGoblinShouQianBaService {
headers.add("X-env-flag", "41508");
// 4. 发送请求
// 注意:传入的是 String jsonBody,接收的也是 String.class,确保不被二次处理
HttpEntity<String> entity = new HttpEntity<>(requestBody, headers);
ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
......@@ -403,33 +314,61 @@ public class GoblinShouQianBaServiceImpl implements IGoblinShouQianBaService {
private String getSign(String bodyJsonStr) {
try {
// 签名算法: sign = MD5( CONCAT( body + appkey ) )
String rawStr = bodyJsonStr + shouqianbaProperties.getAppKey();
String rawStr = bodyJsonStr + sqbConfig.getAppKey();
String sign = MD5Utils.md5(rawStr);
// 签名首部: Authorization: appid + " " + sign
return shouqianbaProperties.getAppId() + " " + sign;
return sqbConfig.getAppId() + " " + sign;
} catch (Exception e) {
log.error("[收钱吧] 生成签名发生异常", e);
return "";
}
}
private CommonRequest.Mall buildMall(String mallSn, String signature) {
CommonRequest.Mall mall = new CommonRequest.Mall();
mall.setMallSn(mallSn);
mall.setSignature(signature);
return mall;
}
private CommonRequest.Buyer buildBuyer(String userId) {
CommonRequest.Buyer buyer = new CommonRequest.Buyer();
buyer.setBuyerId(userId);
return buyer;
}
private List<CreateWechatPrepayOrderRequest.UsingPayTool> buildUsingPayTools(String requestSn,
CashierQueryData.PayTool payTool,
Map<String, Object> channelExt,
String amount,
String userId) {
CreateWechatPrepayOrderRequest.UsingPayTool tool = new CreateWechatPrepayOrderRequest.UsingPayTool();
tool.setId(payTool.getId());
tool.setPayTool(Integer.valueOf(payTool.getCode()));
tool.setPayMode(4); // TODO 需要确认
tool.setAmount(amount);
tool.setIdentity(userId);
tool.setAmountComposition(payTool.getAmountComposition());
tool.setRequestSn(requestSn);
tool.setChannelExt(channelExt);
return Collections.singletonList(tool);
}
/**
* 收钱吧回调推送验签
*
* @param callbackParams@return 验签是否通过
*/
public boolean verifySignature(CallbackParams callbackParams) {
// 签名原串 = eventId + timestamp + nonce + content
String plaintext = callbackParams.getEventId() + callbackParams.getTimestamp() + callbackParams.getNonce() + callbackParams.getContent();
return verifySignatureSHA256WithRSA(plaintext, callbackParams.getSignature(), shouqianbaProperties.getPublicKey());
return verifySignatureSHA256WithRSA(plaintext, callbackParams.getSignature(), sqbConfig.getPublicKey());
}
public boolean verifySignatureSHA256WithRSA(String plaintext, String inputSignature, String pubKey) {
private boolean verifySignatureSHA256WithRSA(String plaintext, String inputSignature, String pubKey) {
return verifySignatureSHA256WithRSA(plaintext.getBytes(StandardCharsets.UTF_8), inputSignature, pubKey);
}
public boolean verifySignatureSHA256WithRSA(byte[] plaintextByte, String inputSignature, String pubKey) {
private boolean verifySignatureSHA256WithRSA(byte[] plaintextByte, String inputSignature, String pubKey) {
try {
X509EncodedKeySpec bobPubKeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(pubKey));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
......
package com.liquidnet.service.goblin.config.properties;
package com.liquidnet.common.third.sqb.config;
import lombok.Getter;
import lombok.Setter;
......@@ -9,7 +9,7 @@ import org.springframework.stereotype.Component;
@Component
@Setter
@Getter
public class ShouqianbaProperties {
public class SqbConfig {
private String appId;
......
package com.liquidnet.common.third.sqb.param.callback;
import lombok.Data;
@Data
/**
* CallbackParams
*/
public class CallbackParams {
/** 推送事件ID,全局唯一 */
private Long eventId;
/** 推送时间戳,当前时间毫秒值 */
private Long timestamp;
/** 随机字串,用于签名 */
private String nonce;
/** 订单数据 JSON字符串 (详见 SqbOrderContentDTO) */
private String content;
/** 报文签名 */
private String signature;
}
package com.liquidnet.service.goblin.param.shouqianba.callback;
package com.liquidnet.common.third.sqb.param.callback;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
@Data
@ApiModel(value = "SqbVoucherStatusDTO", description = "收钱吧券状态推送内容详情")
/**
* SqbVoucherStatusDTO
*/
public class CouponCallbackContent {
@ApiModelProperty(value = "订单Sn")
/** 订单Sn */
private String orderSn;
@ApiModelProperty(value = "商城Sn")
/** 商城Sn */
private String mallSn;
@ApiModelProperty(value = "商户Sn")
/** 商户Sn */
private String merchantSn;
@ApiModelProperty(value = "门店id")
/** 门店id */
private String storeId;
@ApiModelProperty(value = "券列表信息")
/** 券列表信息 */
private List<VoucherItem> voucherList;
@Data
@ApiModel("VoucherItem")
/**
* VoucherItem
*/
public static class VoucherItem {
@ApiModelProperty(value = "券号")
/** 券号 */
private String voucherNo;
@ApiModelProperty(value = "类型")
/** 类型 */
private String type;
@ApiModelProperty(value = "券状态 (0未核销, 1已核销, 2未核销退款, 3已核销退款中, 4未核销退款完成, 5已核销退款完成, 6已失效)")
/** 券状态 (0未核销, 1已核销, 2未核销退款, 3已核销退款中, 4未核销退款完成, 5已核销退款完成, 6已失效) */
private Byte targetState;
@ApiModelProperty(value = "券原状态")
/** 券原状态 */
private Byte sourceState;
@ApiModelProperty(value = "券名称")
/** 券名称 */
private String voucherName;
@ApiModelProperty(value = "操作时间 (yyyy-MM-dd HH:mm:ss)")
/** 操作时间 (yyyy-MM-dd HH:mm:ss) */
private String operationTime;
@ApiModelProperty(value = "券对应的商品信息")
/** 券对应的商品信息 */
private VoucherProductInfo item;
@ApiModelProperty(value = "券二维码地址")
/** 券二维码地址 */
private String qrCodeUrl;
@ApiModelProperty(value = "券二维码内容")
/** 券二维码内容 */
private String qrCodeContent;
@ApiModelProperty(value = "原金额 (单位:分)")
/** 原金额 (单位:分) */
private Long oriAmount;
@ApiModelProperty(value = "实收金额 (单位:分)")
/** 实收金额 (单位:分) */
private Long receivedAmount;
@ApiModelProperty(value = "核销信息 (已核销会有这部分)")
/** 核销信息 (已核销会有这部分) */
private RedeemInfo redeemInfo;
}
@Data
@ApiModel("VoucherProductInfo")
/**
* VoucherProductInfo
*/
public static class VoucherProductInfo {
@ApiModelProperty(value = "spuId")
/** spuId */
private Long spuId;
@ApiModelProperty(value = "skuId")
/** skuId */
private Long skuId;
@ApiModelProperty(value = "商品标题")
/** 商品标题 */
private String title;
@ApiModelProperty(value = "商品图片地址")
/** 商品图片地址 */
private String img;
}
@Data
@ApiModel("RedeemInfo")
/**
* RedeemInfo
*/
public static class RedeemInfo {
@ApiModelProperty(value = "操作来源 (如: EXTERN)")
/** 操作来源 (如: EXTERN) */
private String redeemSource;
@ApiModelProperty(value = "操作appId")
/** 操作appId */
private String redeemAppId;
@ApiModelProperty(value = "客户端编码")
/** 客户端编码 */
private String redeemClientSn;
@ApiModelProperty(value = "外部编码 (appId + 请求号)")
/** 外部编码 (appId + 请求号) */
private String redeemExternalOrderSn;
@ApiModelProperty(value = "操作商户 (userId)")
/** 操作商户 (userId) */
private String operatorMerchantId;
}
......
package com.liquidnet.service.goblin.param.shouqianba.callback;
package com.liquidnet.common.third.sqb.param.callback;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
@Data
@ApiModel(value = "OrderCallbackContent", description = "收钱吧订单推送 Content 具体数据")
/**
* OrderCallbackContent
*/
public class OrderCallbackContent {
@ApiModelProperty(value = "订单号", example = "71655367906162")
/** 订单号 */
private String orderSn;
@ApiModelProperty(value = "支付流水号列表", example = "[\"7894259297368060\"]")
/** 支付流水号列表 */
private List<String> payTsnList;
@ApiModelProperty(value = "终端号", example = "2101056320290541156")
/** 终端号 */
private String terminalSn;
@ApiModelProperty(value = "门店号", example = "21590000000630325")
/** 门店号 */
private String storeSn;
@ApiModelProperty(value = "商城名称", example = "智能商城0206-17:35")
/** 商城名称 */
private String mallName;
@ApiModelProperty(value = "订单金额", example = "2")
/** 订单金额 */
private BigDecimal orderAmount;
@ApiModelProperty(value = "创建时间", example = "2024-02-20 10:46:32")
/** 创建时间 */
private String createdAt;
@ApiModelProperty(value = "订单状态码 0:已创建 10:已支付 35:已完成 40:已取消", example = "35")
/** 订单状态码 0:已创建 10:已支付 35:已完成 40:已取消 */
private Integer orderStateCode;
@ApiModelProperty(value = "商品明细列表")
/** 商品明细列表 */
private List<Item> items;
@ApiModelProperty(value = "收集的信息 JSON字符串", example = "[{\"type\":\"text\",\"form\":\"basic\",\"fieldName\":\"姓名\",\"content\":\"\"}]")
/** 收集的信息 JSON字符串 */
private String collectedInfo;
@ApiModelProperty(value = "预订单编码")
/** 预订单编码 */
private List<String> preOrderSns;
@ApiModelProperty(value = "订单签名")
/** 订单签名 */
private String orderSignature;
@ApiModelProperty(value = "支付的代客下单数据")
/** 支付的代客下单数据 */
private List<PreOrder> preOrderList;
@Data
@ApiModel(value = "商品明细")
/**
* 商品明细
*/
public static class Item {
@ApiModelProperty(value = "商品标题")
/** 商品标题 */
private String title;
@ApiModelProperty(value = "规格描述")
/** 规格描述 */
private String skuDesc;
@ApiModelProperty(value = "数量")
/** 数量 */
private String quantity;
@ApiModelProperty(value = "单位")
/** 单位 */
private String unit;
}
@Data
@ApiModel(value = "采集数据")
/**
* 采集数据
*/
public static class CollectedInfo {
@ApiModelProperty(value = "控件类型")
/** 控件类型 */
private String type;
@ApiModelProperty(value = "控件格式")
/** 控件格式 */
private String form;
@ApiModelProperty(value = "字段名")
/** 字段名 */
private String fieldName;
@ApiModelProperty(value = "采集数据内容")
/** 采集数据内容 */
private String content;
}
@Data
@ApiModel(value = "支付的代客下单数据")
/**
* 支付的代客下单数据
*/
public static class PreOrder {
@ApiModelProperty(value = "预订单id")
/** 预订单id */
private String preOrderId;
@ApiModelProperty(value = "预订单编号")
/** 预订单编号 */
private String preOrderSn;
@ApiModelProperty(value = "请求号")
/** 请求号 */
private String requestId;
}
......
package com.liquidnet.service.goblin.param.shouqianba.callback;
package com.liquidnet.common.third.sqb.param.callback;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
@Data
@ApiModel(value = "SqbRefundContentDTO", description = "收钱吧退款推送内容详情")
/**
* SqbRefundContentDTO
*/
public class RefundCallbackContent {
@ApiModelProperty(value = "售后单号 (全局唯一)", example = "71582143744560")
/** 售后单号 (全局唯一) */
private String ticketSn;
@ApiModelProperty(value = "订单号", example = "2101056320290513285")
/** 订单号 */
private String orderSn;
@ApiModelProperty(value = "原状态")
/** 原状态 */
private Integer sourceState;
@ApiModelProperty(value = "目标状态 (20:完成, 15:退款完成, 0:创建, 10:退款中, 30:取消退款)", example = "15")
/** 目标状态 (20:完成, 15:退款完成, 0:创建, 10:退款中, 30:取消退款) */
private Integer targetState;
@ApiModelProperty(value = "下单金额 (单位:分)", example = "100")
/** 下单金额 (单位:分) */
private Long amount;
@ApiModelProperty(value = "申请金额 (单位:分)", example = "100")
/** 申请金额 (单位:分) */
private Long applyAmount;
@ApiModelProperty(value = "请求号")
/** 请求号 */
private String requestId;
@ApiModelProperty(value = "来源 (如: EXTERN)")
/** 来源 (如: EXTERN) */
private String requestSource;
@ApiModelProperty(value = "退款的商品信息")
/** 退款的商品信息 */
private SqbRefundItemContainer item;
@Data
@ApiModel("SqbRefundItemContainer")
/**
* SqbRefundItemContainer
*/
public static class SqbRefundItemContainer {
@ApiModelProperty(value = "退款类型 (1:商品, 2:金额)")
/** 退款类型 (1:商品, 2:金额) */
private Byte type;
@ApiModelProperty(value = "商品明细列表")
/** 商品明细列表 */
private List<SqbRefundItemDetail> items;
}
@Data
@ApiModel("SqbRefundItemDetail")
/**
* SqbRefundItemDetail
*/
public static class SqbRefundItemDetail {
@ApiModelProperty(value = "spu id")
/** spu id */
private String spuId;
@ApiModelProperty(value = "sku id")
/** sku id */
private String skuId;
@ApiModelProperty(value = "标题")
/** 标题 */
private String title;
@ApiModelProperty(value = "数量")
/** 数量 */
private String quantity;
@ApiModelProperty(value = "退款类型 (0:正常商品, 1:自定义商品)")
/** 退款类型 (0:正常商品, 1:自定义商品) */
private Byte type;
}
}
package com.liquidnet.service.goblin.param.shouqianba.request;
package com.liquidnet.common.third.sqb.param.request;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 创建收单请求
*/
@Data
@ApiModel(value = "创建收单请求")
public class AcquiringCreateRequest {
@ApiModelProperty(required = true, value = "应用id", example = "202507xxxxxxx")
/**
* 应用id
*/
private String appid;
@ApiModelProperty(required = true, value = "卖家信息")
/**
* 卖家信息
*/
private CommonRequest.Seller seller;
@ApiModelProperty(required = true, value = "卖家信息")
/**
* 卖家信息
*/
private Order orderID;
/**
* 订单信息
*/
@Data
@ApiModel(value = "订单信息")
public static class Order {
@ApiModelProperty(required = true, value = "订单ID")
/**
* 订单ID
*/
private String sn;
@ApiModelProperty(required = true, value = "订单密码")
/**
* 订单密码
*/
private String signature;
}
......
package com.liquidnet.service.goblin.param.shouqianba.request;
package com.liquidnet.common.third.sqb.param.request;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 收银台查询请求
*/
@Data
@ApiModel(value = "收银台查询请求")
public class CashierQueryRequest {
@ApiModelProperty(required = true, value = "应用id", example = "202507xxxxxxx")
/** 应用id */
private String appid;
@ApiModelProperty(required = true, value = "商户信息")
/** 商户信息 */
private CommonRequest.Seller seller;
@ApiModelProperty(required = true, value = "支付模式代码", example = "4")
/** 支付模式代码 */
private Integer paymentMode;
@ApiModelProperty(required = true, value = "支付环境")
/** 支付环境 */
private PaymentEnv paymentEnv;
@ApiModelProperty(required = false, value = "付款人信息")
/** 付款人信息 */
private CommonRequest.Payer payer;
@ApiModelProperty(required = true, value = "收单信息")
/** 收单信息 */
private CommonRequest.Acquiring acquiringInfo;
@Data
@ApiModel(value = "支付环境信息")
/**
* 支付环境信息
*/
public static class PaymentEnv {
@ApiModelProperty(required = false, value = "ip地址 最大40位")
/** ip地址 最大40位 */
private String ip;
@ApiModelProperty(required = true, value = "支付客户端 最大32位", example = "wechat")
/** 支付客户端 最大32位 */
private String client;
@ApiModelProperty(required = false, value = "设备号 最大64位")
/** 设备号 最大64位 */
private String device;
@ApiModelProperty(required = false, value = "版本号", example = "1.4")
/** 版本号 */
private String version;
}
......
package com.liquidnet.service.goblin.param.shouqianba.request;
package com.liquidnet.common.third.sqb.param.request;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
......@@ -12,97 +10,141 @@ import java.util.List;
@Data
public class CommonRequest {
/**
* 商城信息
*/
@Data
@ApiModel(value = "商城信息")
@JsonIgnoreProperties(ignoreUnknown = true)
@AllArgsConstructor
@NoArgsConstructor
public static class Mall{
public static class Mall {
@ApiModelProperty(required = true, value = "商城ID")
/**
* 商城ID
*/
private String mallSn;
@ApiModelProperty(required = true, value = "商城密码")
/**
* 商城密码
*/
private String signature;
}
/**
* 卖家信息/商户信息
*/
@Data
@ApiModel(value = "卖家信息/商户信息")
@JsonIgnoreProperties(ignoreUnknown = true)
@AllArgsConstructor
@NoArgsConstructor
public static class Seller {
@ApiModelProperty(required = true, value = "商户ID")
/**
* 商户ID
*/
private String merchantId;
@ApiModelProperty(required = true, value = "商户userID")
/**
* 商户userID
*/
private String merchantUserId;
@ApiModelProperty(required = true, value = "角色 固定值(super_admin)")
/**
* 角色 固定值(super_admin)
*/
private String role;
}
/**
* 买家信息
*/
@Data
@ApiModel("买家信息")
@AllArgsConstructor
@NoArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public static class Buyer{
@ApiModelProperty(required = true, value = "买家ID(用户唯一标识)")
public static class Buyer {
/**
* 买家ID(用户唯一标识)
*/
private String buyerId;
}
/**
* 付款人信息
*/
@Data
@ApiModel("付款人信息")
@AllArgsConstructor
@NoArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public static class Payer{
@ApiModelProperty(required = true, value = "付款人ID")
public static class Payer {
/**
* 付款人ID
*/
private String userId;
}
@ApiModel(value = "收单信息")
/**
* 收单信息
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
@AllArgsConstructor
@NoArgsConstructor
public static class Acquiring{
@ApiModelProperty(value = "收单号")
public static class Acquiring {
/**
* 收单号
*/
private String acquiringSn;
@ApiModelProperty(value = "收单密钥")
/**
* 收单密钥
*/
private String signature;
}
/**
* 金额构成信息
*/
@Data
@ApiModel(value = "金额构成信息")
@JsonIgnoreProperties(ignoreUnknown = true)
public static class AmountComposition {
@ApiModelProperty(required = true, value = "金额构成项列表")
/**
* 金额构成项列表
*/
private List<CompositionItem> compositionItems;
}
/**
* 金额构成项详情
*/
@Data
@ApiModel(value = "金额构成项详情")
@JsonIgnoreProperties(ignoreUnknown = true)
public static class CompositionItem {
@ApiModelProperty(required = true, value = "构成项类目")
/**
* 构成项类目
*/
private String category;
@ApiModelProperty(required = true, value = "构成项金额")
/**
* 构成项金额
*/
private Long amount;
}
/**
* 订单信息
*/
@Data
@ApiModel(value = "订单信息")
@AllArgsConstructor
@NoArgsConstructor
public static class OrderInfo {
@ApiModelProperty(required = true, value = "订单ID")
/**
* 订单ID
*/
private String sn;
@ApiModelProperty(required = true, value = "订单密码")
/**
* 订单密码
*/
private String signature;
}
......
package com.liquidnet.service.goblin.param.shouqianba.request;
package com.liquidnet.common.third.sqb.param.request;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 查询券码请求
*/
@Data
@ApiModel(value = "查询券码请求")
public class CouponQueryRequest {
@ApiModelProperty(required = true, value = "应用id", example = "202507xxxxxxx")
/** 应用id */
private String appid;
@ApiModelProperty(required = true, value = "订单信息")
/** 订单信息 */
private CommonRequest.OrderInfo orderID;
@ApiModelProperty(required = true, value = "卖家信息", example = "4")
/** 卖家信息 */
private CommonRequest.Seller seller;
......
package com.liquidnet.service.goblin.param.shouqianba.request;
package com.liquidnet.common.third.sqb.param.request;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* 券退款请求参数
*/
@Data
@ApiModel(value = "券退款请求参数")
public class CouponRefundRequest {
@ApiModelProperty(required = true, value = "应用ID(收钱吧分配的应用id)")
/** 应用ID(收钱吧分配的应用id) */
private String appid;
@ApiModelProperty(required = true, value = "卖家信息")
/** 卖家信息 */
private CommonRequest.Seller seller;
@ApiModelProperty(required = true, value = "订单信息")
/** 订单信息 */
private CommonRequest.OrderInfo orderID;
@ApiModelProperty(required = true, value = "申请退款信息不能为空")
/** 申请退款信息不能为空 */
private RefundInfo refundInfo;
@ApiModelProperty(required = false, value = "退款请求id(${AppCode}+id)")
/** 退款请求id(${AppCode}+id) */
private String requestId;
@ApiModelProperty(required = true, value = "退款来源(固定值:EXTERN)")
/** 退款来源(固定值:EXTERN) */
private String requestSource;
@Data
@ApiModel(value = "退款信息")
/**
* 退款信息
*/
@AllArgsConstructor
@NoArgsConstructor
public static class RefundInfo {
@ApiModelProperty(required = true, value = "金额")
/** 金额 */
private Long applyAmount;
@ApiModelProperty(required = true, value = "退款类型(1商品 2金额)")
/** 退款类型(1商品 2金额) */
private Byte type;
@ApiModelProperty(required = false, value = "退款明细(商品必填)")
/** 退款明细(商品必填) */
private List<RefundItem> items;
@ApiModelProperty(required = true, value = "退款原因")
/** 退款原因 */
private String refundReason;
}
@Data
@ApiModel(value = "退款明细商品")
/**
* 退款明细商品
*/
public static class RefundItem {
@ApiModelProperty(required = true, value = "spu")
/** spu */
private String spuId;
@ApiModelProperty(required = true, value = "sku")
/** sku */
private String skuId;
@ApiModelProperty(required = true, value = "标题")
/** 标题 */
private String title;
@ApiModelProperty(required = true, value = "商品图片")
/** 商品图片 */
private String img;
@ApiModelProperty(required = true, value = "数量")
/** 数量 */
private String quantity;
@ApiModelProperty(required = false, value = "退款类型(0正常商品 1自定义商品)")
/** 退款类型(0正常商品 1自定义商品) */
private Byte type;
}
......
package com.liquidnet.common.third.sqb.param.request;
import lombok.Data;
import java.util.List;
/**
* 券码状态同步
*/
@Data
public class CouponStatusSyncRequest {
/** 应用ID(聚合收单唯一ID,需申请) */
private String appid;
/** 券号 */
private List<String> voucherNos;
/** 用户ID(自定义,核销用户id) */
private String redeemMerchantId;
/** 外部单号(${AppCode}+id,AppCode需要分配) */
private String redeemExternalOrderSn;
/** 来源(固定值:EXTERN) */
private String redeemSource;
/** 核销终端号(自定义) */
private String clientSn;
/** 券使用状态(0未核销,1已核销) */
private Byte status;
}
package com.liquidnet.service.goblin.param.shouqianba.request;
package com.liquidnet.common.third.sqb.param.request;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
import java.util.Map;
/**
* 创建微信预支付订单请求
*/
@Data
@ApiModel(value = "创建微信预支付订单请求")
public class CreateWechatPrepayOrderRequest {
@ApiModelProperty(required = true, value = "应用id", example = "202507xxxxxxx")
/** 应用id */
private String appid;
@ApiModelProperty(required = true, value = "商户信息")
/** 商户信息 */
private CommonRequest.Seller seller;
@ApiModelProperty(required = true, value = "收单号")
/** 收单号 */
private String acquiringSn;
@ApiModelProperty(required = true, value = "收单签名")
/** 收单签名 */
private String signature;
@ApiModelProperty(required = true, value = "支付工具")
/** 支付工具 */
private List<UsingPayTool> usingPayTools;
@ApiModelProperty(required = false, value = "支付环境")
/** 支付环境 */
private PaymentEnv paymentEnv;
@ApiModelProperty(required = true, value = "支付工具签名", notes = "上一步签名")
/** 支付工具签名 */
private String selectedSignature;
@ApiModelProperty(required = true, value = "序列号", notes = "上一步seq")
/** 序列号 */
private String seq;
@Data
@ApiModel(value = "支付工具使用详情")
/**
* 支付工具使用详情
*/
public static class UsingPayTool {
@ApiModelProperty(required = true, value = "支付工具ID")
/** 支付工具ID */
private Long id;
@ApiModelProperty(required = true, value = "支付工具代码")
/** 支付工具代码 */
private Integer payTool;
@ApiModelProperty(required = true, value = "支付模式", example = "4")
/** 支付模式 */
private Integer payMode;
@ApiModelProperty(required = true, value = "支付金额")
/** 支付金额 */
private String amount;
@ApiModelProperty(required = true, value = "金额构成")
/** 金额构成 */
private CommonRequest.AmountComposition amountComposition;
@ApiModelProperty(required = true, value = "用户身份信息", example = "wzwl")
/** 用户身份信息 */
private String identity;
@ApiModelProperty(required = true, value = "支付请求号", notes = "不超过40位")
/** 支付请求号 */
private String requestSn;
@ApiModelProperty(required = true, value = "通道扩展参数", example = "{\"sub_appid\":\"wx36e68952a6\"}")
/** 通道扩展参数 */
private Map<String, Object> channelExt;
}
@Data
@ApiModel(value = "支付环境信息")
/**
* 支付环境信息
*/
public static class PaymentEnv {
@ApiModelProperty(required = false, value = "付款终端ip")
/** 付款终端ip */
private String clientIp;
@ApiModelProperty(required = false, value = "付款经纬度")
/** 付款经纬度 */
private ClientPoi clientPoi;
@ApiModelProperty(required = false, value = "支付入口")
/** 支付入口 */
private String paymentEntry;
}
@Data
@ApiModel(value = "地理位置信息")
/**
* 地理位置信息
*/
public static class ClientPoi {
@ApiModelProperty(required = false, value = "经度信息")
/** 经度信息 */
private String longitude;
@ApiModelProperty(required = false, value = "纬度信息")
/** 纬度信息 */
private String latitude;
}
......
package com.liquidnet.service.goblin.param.shouqianba.request;
package com.liquidnet.common.third.sqb.param.request;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
@ApiModel(value = "商城列表接口")
/**
* 商城列表接口
*/
@Data
public class MallListQueryRequest implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "应用ID", example = "2025912312")
/** 应用ID */
private String appid;
@ApiModelProperty(value = "过滤条件")
/** 过滤条件 */
private Filter filter;
@ApiModelProperty(value = "分页游标")
/** 分页游标 */
private Cursor cursor;
@ApiModelProperty(value = "排序条件")
/** 排序条件 */
private Sort sort;
@Data
@ApiModel("查询过滤条件")
/**
* 查询过滤条件
*/
public static class Filter {
@ApiModelProperty(value = "商户信息")
/** 商户信息 */
private CommonRequest.Seller seller;
@ApiModelProperty(value = "商城行业筛选")
/** 商城行业筛选 */
private List<String> industryCodes;
@ApiModelProperty(value = "商城状态筛选")
/** 商城状态筛选 */
private List<Byte> states;
@ApiModelProperty(value = "商城状态筛选")
/** 商城状态筛选 */
private Byte state;
@ApiModelProperty(value = "创建时间起始")
/** 创建时间起始 */
private String beginDateTime;
@ApiModelProperty(value = "创建时间截止")
/** 创建时间截止 */
private String endDateTime;
}
@Data
@ApiModel("排序规则")
/**
* 排序规则
*/
public static class Sort {
@ApiModelProperty(value = "排序方式: DESC/ASC")
/** 排序方式: DESC/ASC */
private String sort;
@ApiModelProperty(value = "排序字段")
/** 排序字段 */
private String sortField;
}
@Data
@ApiModel("分页游标")
/**
* 分页游标
*/
public static class Cursor {
@ApiModelProperty(value = "游标字段 分页依据的字段(固定为id)")
/** 游标字段 分页依据的字段(固定为id) */
private String cursorField;
@ApiModelProperty(value = "结束游标 上一页的结束游标(首次查询传 null)")
/** 结束游标 上一页的结束游标(首次查询传 null) */
private String endCursor;
@ApiModelProperty(value = "查询数量 每页返回的最大订单数")
/** 查询数量 每页返回的最大订单数 */
private Integer count;
}
}
package com.liquidnet.service.goblin.param.shouqianba.request;
package com.liquidnet.common.third.sqb.param.request;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 商城列表查询响应数据
*/
@Data
@ApiModel(value = "商城商品查询请求参数")
public class MallProductsQueryRequest {
@ApiModelProperty(value = "应用ID", required = true)
/** 应用ID */
private String appid;
@ApiModelProperty(value = "商户信息", required = true)
/** 商户信息 */
private CommonRequest.Seller seller;
@ApiModelProperty(value = "商城标识", required = true)
/** 商城标识 */
private CommonRequest.Mall mallID;
}
package com.liquidnet.service.goblin.param.shouqianba.request;
package com.liquidnet.common.third.sqb.param.request;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
......@@ -14,31 +12,30 @@ import java.util.List;
* @author liquidnet
* @since 2026-03-16
*/
@ApiModel(value = "创建订单")
@Data
public class OrderCreateRequest implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(required = true, value = "应用ID(聚合收单唯一ID,需申请)")
/** 应用ID(聚合收单唯一ID,需申请) */
private String appid;
@ApiModelProperty(required = true, value = "商城信息")
/** 商城信息 */
private CommonRequest.Mall mallID;
@ApiModelProperty(required = true, value = "商户信息")
/** 商户信息 */
private CommonRequest.Seller seller;
@ApiModelProperty(required = true, value = "结算项ID")
/** 结算项ID */
private String checkoutItemsId;
@ApiModelProperty(required = true, value = "买家信息")
/** 买家信息 */
private CommonRequest.Buyer buyer;
@ApiModelProperty(required = true, value = "请求ID 不超过40位")
/** 请求ID 不超过40位 */
private String requestId;
@ApiModelProperty(required = true, value = "标题 不超过32")
/** 标题 不超过32 */
private String subject;
}
package com.liquidnet.service.goblin.param.shouqianba.request;
package com.liquidnet.common.third.sqb.param.request;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
......@@ -13,54 +11,55 @@ import java.util.List;
* @author liquidnet
* @since 2026-03-16
*/
@ApiModel(value = "创建结算明细请求参数")
@Data
public class SettlementCreateRequest implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(required = true, value = "应用ID(聚合收单唯一ID,需申请)")
/** 应用ID(聚合收单唯一ID,需申请) */
private String appid;
@ApiModelProperty(required = true, value = "商城信息")
/** 商城信息 */
private CommonRequest.Mall mallID;
@ApiModelProperty(required = true, value = "商户信息")
/** 商户信息 */
private CommonRequest.Seller seller;
@ApiModelProperty(required = true, value = "买家信息")
/** 买家信息 */
private CommonRequest.Buyer buyer;
@ApiModelProperty(required = false, value = "结算明细组(结算条目列表)")
/** 结算明细组(结算条目列表) */
private List<CheckoutItem> checkoutItems;
@ApiModelProperty(required = false, value = "结算总金额(单位:分)")
/** 结算总金额(单位:分) */
private Long amount;
@Data
@ApiModel(value = "结算明细条目")
/**
* 结算明细条目
*/
public static class CheckoutItem{
@ApiModelProperty(required = true, value = "商品识别号(商品唯一标识,如 spuId)")
/** 商品识别号(商品唯一标识,如 spuId) */
private String spuId;
@ApiModelProperty(required = true, value = "规格识别号(SKU唯一标识,如 skuId)")
/** 规格识别号(SKU唯一标识,如 skuId) */
private String skuId;
@ApiModelProperty(required = true, value = "单价(单位:分)")
/** 单价(单位:分) */
private Long price;
@ApiModelProperty(required = true, value = "购买数量")
/** 购买数量 */
private String quantity;
@ApiModelProperty(required = true, value = "商品类型(0 正常商品 1 自定义商品)")
/** 商品类型(0 正常商品 1 自定义商品) */
private Byte type;
@ApiModelProperty(required = true, value = "商品标题")
/** 商品标题 */
private String title;
@ApiModelProperty(required = true, value = "商品图片链接")
/** 商品图片链接 */
private String image;
}
}
package com.liquidnet.service.goblin.param.shouqianba.response;
package com.liquidnet.common.third.sqb.param.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.liquidnet.service.goblin.param.shouqianba.response.data.AcquiringCreateData;
import io.swagger.annotations.ApiModel;
import com.liquidnet.common.third.sqb.param.response.data.AcquiringCreateData;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 创建收单响应参数
*/
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "创建收单响应参数")
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class AcquiringCreateResponse extends BaseResponse<AcquiringCreateData> {
......
package com.liquidnet.service.goblin.param.shouqianba.response;
package com.liquidnet.common.third.sqb.param.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 收钱吧基础响应参数
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
@ApiModel(value = "收钱吧基础响应参数")
public class BaseResponse<T> {
@ApiModelProperty(value = "是否成功(true-成功,false-失败)")
/** 是否成功(true-成功,false-失败) */
private Boolean success;
@ApiModelProperty(value = "业务码(200-成功,4001等-失败码)")
/** 业务码(200-成功,4001等-失败码) */
private String code;
@ApiModelProperty(value = "失败信息(success为false时返回失败原因描述)")
/** 失败信息(success为false时返回失败原因描述) */
private String msg;
@ApiModelProperty(value = "data")
/** data */
private T data;
}
package com.liquidnet.service.goblin.param.shouqianba.response;
package com.liquidnet.common.third.sqb.param.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.liquidnet.service.goblin.param.shouqianba.response.data.CashierQueryData;
import io.swagger.annotations.ApiModel;
import com.liquidnet.common.third.sqb.param.response.data.CashierQueryData;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 自助收银查询响应
*/
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "自助收银查询响应")
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class CashierQueryResponse extends BaseResponse<CashierQueryData>{
......
package com.liquidnet.service.goblin.param.shouqianba.response;
package com.liquidnet.common.third.sqb.param.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.liquidnet.service.goblin.param.shouqianba.response.data.CouponQueryData;
import io.swagger.annotations.ApiModel;
import com.liquidnet.common.third.sqb.param.response.data.CouponQueryData;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 券详情查询响应
*/
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "券详情查询响应")
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class CouponQueryResponse extends BaseResponse<CouponQueryData>{
......
package com.liquidnet.service.goblin.param.shouqianba.response;
package com.liquidnet.common.third.sqb.param.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.liquidnet.service.goblin.param.shouqianba.response.data.CouponRefundData;
import io.swagger.annotations.ApiModel;
import com.liquidnet.common.third.sqb.param.response.data.CouponRefundData;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 券退款响应
*/
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "券退款响应")
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class CouponRefundResponse extends BaseResponse<CouponRefundData>{
......
package com.liquidnet.service.goblin.param.shouqianba.response;
package com.liquidnet.common.third.sqb.param.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 券状态变更响应
*/
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "券状态变更响应")
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class CouponStatusSyncResponse extends BaseResponse<String>{
......
package com.liquidnet.service.goblin.param.shouqianba.response;
package com.liquidnet.common.third.sqb.param.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.liquidnet.service.goblin.param.shouqianba.response.data.CreateWechatPrepayOrderData;
import io.swagger.annotations.ApiModel;
import com.liquidnet.common.third.sqb.param.response.data.CreateWechatPrepayOrderData;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 创建微信预支付订单响应
*/
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "创建微信预支付订单响应")
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class CreateWechatPrepayOrderResponse extends BaseResponse<CreateWechatPrepayOrderData>{
......
package com.liquidnet.service.goblin.param.shouqianba.response;
package com.liquidnet.common.third.sqb.param.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.liquidnet.service.goblin.param.shouqianba.response.data.MallListQueryData;
import io.swagger.annotations.ApiModel;
import com.liquidnet.common.third.sqb.param.response.data.MallListQueryData;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
/**
* 商城列表查询响应参数
*/
@EqualsAndHashCode(callSuper = true)
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
@ApiModel(value = "商城列表查询响应参数")
public class MallListQueryResponse extends BaseResponse<List<MallListQueryData>> {
}
package com.liquidnet.service.goblin.param.shouqianba.response;
package com.liquidnet.common.third.sqb.param.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.liquidnet.service.goblin.param.shouqianba.response.data.MallProductsQueryData;
import io.swagger.annotations.ApiModel;
import com.liquidnet.common.third.sqb.param.response.data.MallProductsQueryData;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
/**
* 商城商品接口响应
*/
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "商城商品接口响应")
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class MallProductsQueryResponse extends BaseResponse<List<MallProductsQueryData>>{
......
package com.liquidnet.service.goblin.param.shouqianba.response;
package com.liquidnet.common.third.sqb.param.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.liquidnet.service.goblin.param.shouqianba.response.data.OrderCreateData;
import io.swagger.annotations.ApiModel;
import com.liquidnet.common.third.sqb.param.response.data.OrderCreateData;
import lombok.Data;
import lombok.EqualsAndHashCode;
......@@ -13,7 +13,6 @@ import lombok.EqualsAndHashCode;
* @since 2026-03-16
*/
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "创建订单响应参数")
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class OrderCreateResponse extends BaseResponse<OrderCreateData>{
......
package com.liquidnet.service.goblin.param.shouqianba.response;
package com.liquidnet.common.third.sqb.param.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.liquidnet.service.goblin.param.shouqianba.response.data.SettlementCreateData;
import io.swagger.annotations.ApiModel;
import com.liquidnet.common.third.sqb.param.response.data.SettlementCreateData;
import lombok.Data;
import lombok.EqualsAndHashCode;
......@@ -13,7 +13,6 @@ import lombok.EqualsAndHashCode;
* @since 2026-03-16
*/
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "创建结算明细响应参数")
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class SettlementCreateResponse extends BaseResponse<SettlementCreateData> {
......
package com.liquidnet.service.goblin.param.shouqianba.response.data;
package com.liquidnet.common.third.sqb.param.response.data;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.liquidnet.service.goblin.param.shouqianba.request.CommonRequest;
import io.swagger.annotations.ApiModel;
import com.liquidnet.common.third.sqb.param.request.CommonRequest;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 创建收单Data
*/
@EqualsAndHashCode(callSuper = true)
@Data
@ApiModel(value = "创建收单Data")
@JsonIgnoreProperties(ignoreUnknown = true)
public class AcquiringCreateData extends CommonRequest.Acquiring {
......
package com.liquidnet.service.goblin.param.shouqianba.response.data;
package com.liquidnet.common.third.sqb.param.response.data;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.liquidnet.service.goblin.param.shouqianba.request.CommonRequest;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import com.liquidnet.common.third.sqb.param.request.CommonRequest;
import lombok.Data;
import java.util.List;
/**
* 收银台查询Data
*/
@Data
@ApiModel(value = "收银台查询Data")
@JsonIgnoreProperties(ignoreUnknown = true)
public class CashierQueryData {
@ApiModelProperty(value = "支付工具列表")
/** 支付工具列表 */
private List<PayTool> payTools;
@ApiModelProperty(value = "已选中的支付工具签名")
/** 已选中的支付工具签名 */
private String selectedSignature;
@ApiModelProperty(value = "全局提示")
/** 全局提示 */
private List<String> globalTips;
@ApiModelProperty(value = "响应唯一序列号")
/** 响应唯一序列号 */
private String seq;
@ApiModelProperty(value = "收单金额")
/** 收单金额 */
private Long amount;
@ApiModelProperty(value = "收款方信息")
/** 收款方信息 */
private Payee payee;
@ApiModelProperty(value = "业务信息")
/** 业务信息 */
private BizInfo bizInfo;
@ApiModelProperty(value = "金额模型")
/** 金额模型 */
private CashierAmount cashierAmount;
@Data
@ApiModel(value = "支付工具详情")
/**
* 支付工具详情
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public static class PayTool {
@ApiModelProperty(value = "支付工具id")
/** 支付工具id */
private Long id;
@ApiModelProperty(value = "支付工具代码")
/** 支付工具代码 */
private String code;
@ApiModelProperty(value = "支付工具名称")
/** 支付工具名称 */
private String name;
@ApiModelProperty(value = "支付工具类型 (0表示微信)")
/** 支付工具类型 (0表示微信) */
private Integer type;
@ApiModelProperty(value = "是否可选")
/** 是否可选 */
private Boolean selectable;
@ApiModelProperty(value = "是否选中")
/** 是否选中 */
private Boolean selected;
@ApiModelProperty(value = "展示金额")
/** 展示金额 */
private Long showAmount;
@ApiModelProperty(value = "提示列表")
/** 提示列表 */
private List<String> tips;
@ApiModelProperty(value = "金额构成")
/** 金额构成 */
private CommonRequest.AmountComposition amountComposition;
}
@Data
@ApiModel(value = "收款方信息")
/**
* 收款方信息
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public static class Payee {
@ApiModelProperty(value = "商户id")
/** 商户id */
private String merchantId;
@ApiModelProperty(value = "商户名称")
/** 商户名称 */
private String merchantName;
@ApiModelProperty(value = "门店id")
/** 门店id */
private String storeId;
@ApiModelProperty(value = "门店名称")
/** 门店名称 */
private String storeName;
@ApiModelProperty(value = "终端号")
/** 终端号 */
private String terminalSn;
}
@Data
@ApiModel(value = "业务信息")
/**
* 业务信息
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public static class BizInfo {
@ApiModelProperty(value = "业务方")
/** 业务方 */
private String bizParty;
@ApiModelProperty(value = "交易应用")
/** 交易应用 */
private String tradeApp;
}
@Data
@ApiModel(value = "金额明细模型")
/**
* 金额明细模型
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public static class CashierAmount {
@ApiModelProperty(value = "原始支付金额")
/** 原始支付金额 */
private Long oriPaymentAmount;
@ApiModelProperty(value = "实际支付金额")
/** 实际支付金额 */
private Long discPaymentAmount;
@ApiModelProperty(value = "优惠金额")
/** 优惠金额 */
private Long discAmount;
}
......
package com.liquidnet.service.goblin.param.shouqianba.response.data;
package com.liquidnet.common.third.sqb.param.response.data;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
@ApiModel(value = "查询券码响应Data")
/**
* 查询券码响应Data
*/
public class CouponQueryData {
@ApiModelProperty(value = "券名称")
/** 券名称 */
private String voucherName;
@ApiModelProperty(value = "商品SPU")
/** 商品SPU */
private String spuId;
@ApiModelProperty(value = "商品SKU")
/** 商品SKU */
private String skuId;
@ApiModelProperty(value = "商品地址")
/** 商品地址 */
private String itemImageUrl;
@ApiModelProperty(value = "券二维码")
/** 券二维码 */
private String url;
@ApiModelProperty(value = "券号")
/** 券号 */
private String voucherNo;
@ApiModelProperty(value = "券类型 0金额券 1商品券")
/** 券类型 0金额券 1商品券 */
private Byte type;
@ApiModelProperty(value = "券状态 0未核销 1已核销 2未核销退款 3已核销退款中 4未核销退款完成 5已核销退款完成 6已失效")
/** 券状态 0未核销 1已核销 2未核销退款 3已核销退款中 4未核销退款完成 5已核销退款完成 6已失效 */
private Byte status;
@ApiModelProperty(value = "操作时间")
/** 操作时间 */
private String operationTime;
......
package com.liquidnet.service.goblin.param.shouqianba.response.data;
package com.liquidnet.common.third.sqb.param.response.data;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 券退款响应结果
*/
@Data
@ApiModel(value = "券退款响应结果")
@JsonIgnoreProperties(ignoreUnknown = true)
public class CouponRefundData {
@ApiModelProperty(value = "退款单号")
/** 退款单号 */
private String ticketsSn;
@ApiModelProperty(value = "单号密码")
/** 单号密码 */
private String ticketSignature;
}
package com.liquidnet.service.goblin.param.shouqianba.response.data;
package com.liquidnet.common.third.sqb.param.response.data;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 创建微信预支付订单响应
*/
@Data
@ApiModel(value = "创建微信预支付订单响应")
@JsonIgnoreProperties(ignoreUnknown = true)
public class CreateWechatPrepayOrderData {
@ApiModelProperty(value = "收单号")
/** 收单号 */
private String acquiringSn;
@ApiModelProperty(value = "收单签名")
/** 收单签名 */
private String signature;
@ApiModelProperty(value = "收单状态", notes = "0:已创建, 1:待支付, 2:部分支付成功, 3:全部支付成功, 4:已部分退款, 5:已全额退款, 6:已关闭")
/** 收单状态 */
private Byte acquiringState;
@ApiModelProperty(value = "金额明细")
/** 金额明细 */
private AmountDetails amount;
@ApiModelProperty(value = "支付凭证", notes = "用于唤起微信支付")
/** 支付凭证 */
private PaymentVoucher paymentVoucher;
@ApiModelProperty(value = "通道信息")
/** 通道信息 */
private ChannelInfo channelInfo;
@Data
@ApiModel(value = "订单金额明细")
/**
* 订单金额明细
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public static class AmountDetails {
@ApiModelProperty(value = "收单总金额")
/** 收单总金额 */
private Long totalAmount;
@ApiModelProperty(value = "已付总金额")
/** 已付总金额 */
private Long paidAmount;
@ApiModelProperty(value = "已退总金额")
/** 已退总金额 */
private Long refundedAmount;
}
@Data
@ApiModel(value = "支付凭证详情")
/**
* 支付凭证详情
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public static class PaymentVoucher {
@ApiModelProperty(value = "时间戳")
/** 时间戳 */
private String timeStamp;
@ApiModelProperty(value = "订单详情扩展字符串")
/** 订单详情扩展字符串 */
private String packageStr;
@ApiModelProperty(value = "签名")
/** 签名 */
private String paySign;
@ApiModelProperty(value = "Appid")
/** Appid */
private String appId;
@ApiModelProperty(value = "签名方式")
/** 签名方式 */
private String signType;
@ApiModelProperty(value = "随机字符串")
/** 随机字符串 */
private String nonceStr;
}
@Data
@ApiModel(value = "通道信息详情")
/**
* 通道信息详情
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public static class ChannelInfo {
@ApiModelProperty(value = "收钱吧通道流水号")
/** 收钱吧通道流水号 */
private String payTsn;
}
......
package com.liquidnet.service.goblin.param.shouqianba.response.data;
package com.liquidnet.common.third.sqb.param.response.data;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
/**
* 商城列表查询响应数据
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
@ApiModel(value = "商城列表查询响应数据")
public class MallListQueryData {
@ApiModelProperty("商城编号")
/** 商城编号 */
private String mallSn;
@ApiModelProperty("商城签名")
/** 商城签名 */
private String signature;
@ApiModelProperty("商城名称")
/** 商城名称 */
private String mallName;
@ApiModelProperty("商城状态 0:待上线 1:已上线 2:已下线")
/** 商城状态 0:待上线 1:已上线 2:已下线 */
private Byte state;
@ApiModelProperty("商城状态描述")
/** 商城状态描述 */
private String stateDesc;
@ApiModelProperty("内部状态 1启用 0禁用")
/** 内部状态 1启用 0禁用 */
private Byte internalState;
@ApiModelProperty("内部状态描述")
/** 内部状态描述 */
private String internalStateDesc;
@ApiModelProperty("删除状态 0未删除 1已删除")
/** 删除状态 0未删除 1已删除 */
private Byte isDelete;
@ApiModelProperty("删除时间")
/** 删除时间 */
private String deleteTime;
@ApiModelProperty("大额开通状态")
/** 大额开通状态 */
private Byte crossCityPaymentStatus;
@ApiModelProperty("大额开通状态描述")
/** 大额开通状态描述 */
private String crossCityPaymentStatusDesc;
@ApiModelProperty("应用类型 0拼塔商城 目前都是0,无需关注")
/** 应用类型 0拼塔商城 目前都是0,无需关注 */
private Integer appType;
@ApiModelProperty("行业code")
/** 行业code */
private String industryCode;
@ApiModelProperty("商户信息")
/** 商户信息 */
private Seller seller;
@ApiModelProperty("订单统计")
/** 订单统计 */
private OrderStatistics orderStatistics;
@ApiModelProperty("商户统计")
/** 商户统计 */
private SellerStatisticsModel sellerStatisticsModel;
@ApiModelProperty("创建时间")
/** 创建时间 */
private String ctime;
@ApiModelProperty("跨城状态明细")
/** 跨城状态明细 */
private List<CrossCityPayment> crossCityPayments;
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
@ApiModel("商户信息")
/**
* 商户信息
*/
public static class Seller {
@ApiModelProperty("商户号")
/** 商户号 */
private String merchantSn;
@ApiModelProperty("商户id")
/** 商户id */
private String merchantId;
@ApiModelProperty("商户名称")
/** 商户名称 */
private String merchantName;
@ApiModelProperty("门店号")
/** 门店号 */
private String storeSn;
@ApiModelProperty("门店id")
/** 门店id */
private String storeId;
@ApiModelProperty("门店名称")
/** 门店名称 */
private String storeName;
@ApiModelProperty("终端号")
/** 终端号 */
private String terminalSn;
@ApiModelProperty("大额终端编号")
/** 大额终端编号 */
private String crossCityTerminalSn;
}
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
@ApiModel("订单统计")
/**
* 订单统计
*/
public static class OrderStatistics {
@ApiModelProperty("订单数量")
/** 订单数量 */
private Long totalNum;
@ApiModelProperty("商品数量")
/** 商品数量 */
private String totalQuantity;
@ApiModelProperty("订单总额(分)")
/** 订单总额(分) */
private Long totalAmount;
}
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
@ApiModel("商户统计")
/**
* 商户统计
*/
public static class SellerStatisticsModel {
@ApiModelProperty("异地交易失败订单数量")
/** 异地交易失败订单数量 */
private Long orderFailNum;
}
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
@ApiModel("跨城支付明细")
/**
* 跨城支付明细
*/
public static class CrossCityPayment {
@ApiModelProperty("支付工具code 2:支付宝 3:微信")
/** 支付工具code 2:支付宝 3:微信 */
private Byte payToolCode;
@ApiModelProperty("支付工具描述")
/** 支付工具描述 */
private String payToolCodeDesc;
@ApiModelProperty("大额开通状态")
/** 大额开通状态 */
private Integer status;
@ApiModelProperty("大额开通状态描述")
/** 大额开通状态描述 */
private String statusDesc;
}
}
package com.liquidnet.service.goblin.param.shouqianba.response.data;
package com.liquidnet.common.third.sqb.param.response.data;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
/**
* 商城商品接口响应数据
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
@ApiModel(value = "商城商品接口响应数据")
public class MallProductsQueryData {
@ApiModelProperty(value = "商品spuId")
/** 商品spuId */
private String spuId;
@ApiModelProperty(value = "商品图片")
/** 商品图片 */
private List<String> converImages;
@ApiModelProperty(value = "商品描述")
/** 商品描述 */
private String productIntroduction;
@ApiModelProperty(value = "商品标题")
/** 商品标题 */
private String title;
@ApiModelProperty(value = "商品规格")
/** 商品规格 */
private List<Sku> skuResults;
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
@ApiModel(value = "商品规格")
/**
* 商品规格
*/
public static class Sku {
@ApiModelProperty(value = "库存类型")
/** 库存类型 */
private Integer stockType;
@ApiModelProperty(value = "商品skuId")
/** 商品skuId */
private String skuId;
@ApiModelProperty(value = "库存值")
/** 库存值 */
private BigDecimal quantity;
@ApiModelProperty(value = "规格标题")
/** 规格标题 */
private String skuTitle;
@ApiModelProperty(value = "规格名称")
/** 规格名称 */
private String skuName;
@ApiModelProperty(value = "价格")
/** 价格 */
private Long price;
}
}
package com.liquidnet.service.goblin.param.shouqianba.response.data;
package com.liquidnet.common.third.sqb.param.response.data;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.liquidnet.service.goblin.param.shouqianba.request.CommonRequest;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import com.liquidnet.common.third.sqb.param.request.CommonRequest;
import lombok.Data;
/**
* 收钱吧创建订单响应参数Data
*/
@Data
@ApiModel(value = "收钱吧创建订单响应参数Data")
@JsonIgnoreProperties(ignoreUnknown = true)
public class OrderCreateData {
@ApiModelProperty(value = "订单编号)")
/** 订单编号) */
private String orderSn;
@ApiModelProperty(value = "订单密钥)")
/** 订单密钥) */
private String orderSignature;
@ApiModelProperty(value = "收单信息)")
/** 收单信息) */
private CommonRequest.Acquiring acquiring;
......
package com.liquidnet.service.goblin.param.shouqianba.response.data;
package com.liquidnet.common.third.sqb.param.response.data;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.Data;
/**
* 收钱吧创建结算明细响应参数Data
*/
@Data
@ApiModel(value = "收钱吧创建结算明细响应参数Data")
@JsonIgnoreProperties(ignoreUnknown = true)
public class SettlementCreateData {
@ApiModelProperty(value = "结算项ID)")
/** 结算项ID) */
private String checkoutItemsId;
}
......@@ -16,5 +16,6 @@
<module>liquidnet-common-third-zxlnft</module>
<module>liquidnet-common-third-antchain</module>
<module>liquidnet-common-third-xuper</module>
<module>liquidnet-common-third-sqb</module>
</modules>
</project>
......@@ -109,6 +109,12 @@
<artifactId>dg-java-sdk</artifactId>
<version>3.0.27</version>
</dependency>
<dependency>
<groupId>com.liquidnet</groupId>
<artifactId>liquidnet-common-third-sqb</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
......
......@@ -3,20 +3,17 @@ package com.liquidnet.service.goblin.controller;
import com.liquidnet.commons.lang.util.CurrentUtil;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.goblin.dto.vo.GoblinSqbCouponVo;
import com.liquidnet.service.goblin.dto.vo.GoblinSqbOrderCreateVo;
import com.liquidnet.service.goblin.dto.vo.GoblinSqbOrderDetailVo;
import com.liquidnet.service.goblin.service.IGoblinSqbOrderService;
import com.liquidnet.service.goblin.service.IGoblinSqbService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
* 收钱吧订单 Controller
......@@ -24,51 +21,12 @@ import javax.validation.constraints.NotNull;
@Slf4j
@Api(tags = "收钱吧订单")
@RestController
@RequestMapping("/goblin/sqb/order")
public class GoblinSqbOrderController {
@RequestMapping("/goblin/sqb")
public class GoblinSqbController {
@Autowired
private IGoblinSqbOrderService goblinSqbOrderService;
private IGoblinSqbService goblinSqbService;
/**
* 创建收钱吧订单
*/
@PostMapping("/create")
@ApiOperation("创建收钱吧订单")
@ApiImplicitParams({
@ApiImplicitParam(type = "form", required = true, dataType = "String", name = "spuId", value = "商品 SPU ID"),
@ApiImplicitParam(type = "form", required = true, dataType = "String", name = "skuId", value = "商品 SKU ID"),
@ApiImplicitParam(type = "form", required = true, dataType = "Integer", name = "quantity", value = "购买数量", example = "1"),
@ApiImplicitParam(type = "form", required = true, dataType = "String", name = "performancesId", value = "关联演出 ID"),
})
public ResponseDto<GoblinSqbOrderCreateVo> createOrder(
@NotBlank(message = "spuId 不能为空") @RequestParam("spuId") String spuId,
@NotBlank(message = "skuId 不能为空") @RequestParam("skuId") String skuId,
@NotNull(message = "quantity 不能为空")
@Min(value = 1, message = "购买数量至少为 1") @RequestParam("quantity") Integer quantity,
@NotBlank(message = "performancesId 不能为空") @RequestParam("performancesId") String performancesId) {
String userId = CurrentUtil.getCurrentUid();
log.info("[收钱吧下单] 接收请求 userId={}, spuId={}, skuId={}, quantity={}, performancesId={}",
userId, spuId, skuId, quantity, performancesId);
return goblinSqbOrderService.createOrder(userId, spuId, skuId, quantity, performancesId);
}
/**
* 查询支付状态
*/
@GetMapping("/pay/status")
@ApiOperation("查询支付状态")
@ApiImplicitParam(type = "query", required = true, dataType = "String", name = "orderId", value = "本地订单ID")
public ResponseDto<Integer> queryPayStatus(
@NotBlank(message = "orderId 不能为空") @RequestParam("orderId") String orderId) {
String userId = CurrentUtil.getCurrentUid();
log.info("[收钱吧支付状态] 接收请求 userId={}, orderId={}", userId, orderId);
return goblinSqbOrderService.queryPayStatus(userId, orderId);
}
/**
* 获取核销二维码(券码)
......@@ -82,7 +40,7 @@ public class GoblinSqbOrderController {
String userId = CurrentUtil.getCurrentUid();
log.info("[收钱吧券码] 接收请求 userId={}, orderId={}", userId, orderId);
return goblinSqbOrderService.queryCoupon(userId, orderId);
return goblinSqbService.queryCoupon(userId, orderId);
}
/**
......@@ -97,9 +55,10 @@ public class GoblinSqbOrderController {
String userId = CurrentUtil.getCurrentUid();
log.info("[收钱吧退款] 接收请求 userId={}, orderId={}", userId, orderId);
return goblinSqbOrderService.refund(userId, orderId);
return goblinSqbService.refund(userId, orderId);
}
/**
* 主动同步核销状态
*/
......@@ -110,7 +69,7 @@ public class GoblinSqbOrderController {
@NotBlank(message = "orderId 不能为空") @RequestParam("orderId") String orderId) {
String userId = CurrentUtil.getCurrentUid();
log.info("[收钱吧核销同步] 接收请求 userId={}, orderId={}", userId, orderId);
return goblinSqbOrderService.syncCouponStatus(userId, orderId);
return goblinSqbService.syncCouponStatus(userId, orderId);
}
/**
......@@ -118,10 +77,10 @@ public class GoblinSqbOrderController {
*/
@GetMapping("/list")
@ApiOperation("用户收钱吧订单列表")
public ResponseDto<java.util.List<GoblinSqbOrderDetailVo>> getOrderList() {
public ResponseDto<List<GoblinSqbOrderDetailVo>> getOrderList() {
String userId = CurrentUtil.getCurrentUid();
log.info("[收钱吧订单列表] 接收请求 userId={}", userId);
return goblinSqbOrderService.getOrderList(userId);
return goblinSqbService.getOrderList(userId);
}
/**
......@@ -134,19 +93,8 @@ public class GoblinSqbOrderController {
@NotBlank(message = "orderId 不能为空") @PathVariable("orderId") String orderId) {
String userId = CurrentUtil.getCurrentUid();
log.info("[收钱吧订单详情] 接收请求 userId={}, orderId={}", userId, orderId);
return goblinSqbOrderService.getOrderDetail(userId, orderId);
return goblinSqbService.getOrderDetail(userId, orderId);
}
/**
* 再次付款(待支付状态下重新拉起微信支付)
*/
@PostMapping("/repay")
@ApiOperation("再次付款")
@ApiImplicitParam(type = "form", required = true, dataType = "String", name = "orderId", value = "本地订单ID")
public ResponseDto<GoblinSqbOrderCreateVo> repay(
@NotBlank(message = "orderId 不能为空") @RequestParam("orderId") String orderId) {
String userId = CurrentUtil.getCurrentUid();
log.info("[收钱吧再次付款] 接收请求 userId={}, orderId={}", userId, orderId);
return goblinSqbOrderService.repay(userId, orderId);
}
}
package com.liquidnet.service.goblin.controller.Inner;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.goblin.service.IGoblinSqbOrderService;
import com.liquidnet.service.goblin.service.IGoblinSqbService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
......@@ -29,12 +29,12 @@ import org.springframework.web.bind.annotation.RestController;
public class GoblinSqbJobController {
@Autowired
private IGoblinSqbOrderService goblinSqbOrderService;
private IGoblinSqbService goblinSqbService;
@PostMapping("/autoRefund")
@ApiOperation("演出结束自动退款")
public ResponseDto<String> autoRefund(@RequestParam("performancesId") String performancesId) {
log.info("[收钱吧自动退款] 收到任务,performancesId={}", performancesId);
return goblinSqbOrderService.autoRefundByPerformance(performancesId);
return goblinSqbService.autoRefundByPerformance(performancesId);
}
}
......@@ -2,6 +2,8 @@ package com.liquidnet.service.goblin.controller.manage;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.liquidnet.common.third.sqb.biz.SqbBiz;
import com.liquidnet.common.third.sqb.param.response.data.MallProductsQueryData;
import com.liquidnet.commons.lang.util.CurrentUtil;
import com.liquidnet.commons.lang.util.JsonUtils;
import com.liquidnet.service.base.ErrorMapping;
......@@ -13,8 +15,6 @@ import com.liquidnet.service.goblin.dto.vo.GoblinGoodsSpecVo;
import com.liquidnet.service.goblin.dto.vo.GoblinSqbPerfGoodsVo;
import com.liquidnet.service.goblin.entity.GoblinSqbGoodsExt;
import com.liquidnet.service.goblin.mapper.GoblinSqbGoodsExtMapper;
import com.liquidnet.service.goblin.param.shouqianba.response.data.MallProductsQueryData;
import com.liquidnet.service.goblin.service.IGoblinShouQianBaService;
import com.liquidnet.service.goblin.service.manage.IGoblinStoreMgtSqbGoodsService;
import com.liquidnet.service.goblin.util.GoblinRedisUtils;
import com.liquidnet.service.goblin.util.ObjectUtil;
......@@ -51,7 +51,7 @@ public class GoblinStoreMgtSqbGoodsController {
@Autowired
private GoblinSqbGoodsExtMapper goblinSqbGoodsExtMapper;
@Autowired
private IGoblinShouQianBaService goblinShouQianBaService;
private SqbBiz goblinShouQianBaService;
/**
* 查询所有商城及商品列表
......
package com.liquidnet.service.goblin.service.impl;
import com.liquidnet.common.third.sqb.biz.SqbBiz;
import com.liquidnet.common.third.sqb.param.request.CommonRequest;
import com.liquidnet.common.third.sqb.param.request.CouponQueryRequest;
import com.liquidnet.common.third.sqb.param.request.CouponRefundRequest;
import com.liquidnet.common.third.sqb.param.request.CouponStatusSyncRequest;
import com.liquidnet.common.third.sqb.param.response.data.CouponQueryData;
import com.liquidnet.common.third.sqb.param.response.data.CouponRefundData;
import com.liquidnet.commons.lang.util.IDGenerator;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.goblin.dto.vo.*;
import com.liquidnet.service.goblin.service.IGoblinSqbService;
import com.liquidnet.service.goblin.util.GoblinMongoUtils;
import com.liquidnet.service.goblin.util.GoblinRedisUtils;
import com.liquidnet.service.goblin.util.GoblinSqbRedisUtils;
import com.liquidnet.service.goblin.util.QueueUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* 收钱吧订单服务实现
*/
@Slf4j
@Service
public class GoblinSqbServiceImpl implements IGoblinSqbService {
@Autowired
private GoblinSqbRedisUtils goblinSqbRedisUtils;
@Autowired
private GoblinRedisUtils goblinRedisUtils;
@Autowired
private GoblinMongoUtils goblinMongoUtils;
@Autowired
private QueueUtils queueUtils;
@Autowired
private SqbBiz sqbBiz;
private static final DateTimeFormatter DTF = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// ================================ 获取券码 ================================
@Override
public ResponseDto<GoblinSqbCouponVo> queryCoupon(String userId, String orderId) {
log.info("[收钱吧券码] 开始获取 userId={}, orderId={}", userId, orderId);
GoblinSqbOrderVo orderVo = goblinSqbRedisUtils.getSqbOrder(orderId);
if (orderVo == null) return ResponseDto.failure("订单不存在");
if (!userId.equals(orderVo.getUserId())) return ResponseDto.failure("无权限访问该订单");
if (!Integer.valueOf(1).equals(orderVo.getStatus())) return ResponseDto.failure("订单未支付,无法获取券码");
// 幂等:已存在则直接返回
if (orderVo.getCouponQrCode() != null && !orderVo.getCouponQrCode().isEmpty()) {
GoblinSqbCouponVo couponVo = new GoblinSqbCouponVo();
couponVo.setCouponSn(orderVo.getCouponSn());
couponVo.setCouponQrCode(orderVo.getCouponQrCode());
couponVo.setCouponExpireTime(orderVo.getCouponExpireTime());
return ResponseDto.success(couponVo);
}
// 调用收钱吧查询券码
CouponQueryRequest req = new CouponQueryRequest();
req.setAppid(sqbBiz.getSqbConfig().getAppId());
req.setSeller(buildSeller());
CouponQueryData couponData = sqbBiz.queryCoupon(req);
if (couponData == null) return ResponseDto.failure("获取券码失败");
// 更新订单 coupon 字段
String now = LocalDateTime.now().format(DTF);
orderVo.setCouponSn(couponData.getVoucherNo());
orderVo.setCouponQrCode(couponData.getUrl());
orderVo.setCouponExpireTime(couponData.getOperationTime());
orderVo.setUpdatedAt(now);
goblinSqbRedisUtils.setSqbOrder(orderId, orderVo);
// 券码信息保存在 Redis,MySQL和MongoDB商城基础模型无此字段,无需同步
GoblinSqbCouponVo couponVo = new GoblinSqbCouponVo();
couponVo.setCouponSn(couponData.getVoucherNo());
couponVo.setCouponQrCode(couponData.getUrl());
couponVo.setCouponExpireTime(couponData.getOperationTime());
log.info("[收钱吧券码] 获取成功,orderId={}", orderId);
return ResponseDto.success(couponVo);
}
// ================================ 申请退款 ================================
@Override
public ResponseDto<Boolean> refund(String userId, String orderId) {
log.info("[收钱吧退款] 开始 userId={}, orderId={}", userId, orderId);
GoblinSqbOrderVo orderVo = goblinSqbRedisUtils.getSqbOrder(orderId);
if (orderVo == null) return ResponseDto.failure("订单不存在");
if (!userId.equals(orderVo.getUserId())) return ResponseDto.failure("无权限访问该订单");
if (!Integer.valueOf(1).equals(orderVo.getStatus())) return ResponseDto.failure("订单状态不可退款");
if (Integer.valueOf(1).equals(orderVo.getCouponUsedStatus())) return ResponseDto.failure("券码已核销,不可退款");
// 更新状态为退款中
String now = LocalDateTime.now().format(DTF);
orderVo.setStatus(4);
orderVo.setUpdatedAt(now);
goblinSqbRedisUtils.setSqbOrder(orderId, orderVo);
syncOrderStatus(orderId, 4);
try {
// 调用收钱吧退款
CouponRefundRequest refundReq = new CouponRefundRequest();
refundReq.setAppid(sqbBiz.getSqbConfig().getAppId());
refundReq.setSeller(buildSeller());
refundReq.setRequestSource("EXTERN");
refundReq.setRequestId(IDGenerator.nextSnowId());
CouponRefundRequest.RefundInfo refundInfo = new CouponRefundRequest.RefundInfo();
// amount 字段待接入实际金额(GoblinSqbOrderVo 需补充 amount)
refundInfo.setApplyAmount(0L); // TODO: 替换为实际订单金额
refundInfo.setType((byte) 2); // 2-按金额退款
refundInfo.setRefundReason("用户申请退款");
refundReq.setRefundInfo(refundInfo);
CouponRefundData refundData = sqbBiz.refundCoupon(refundReq);
if (refundData == null) {
// 退款失败,回滚状态
orderVo.setStatus(1);
orderVo.setUpdatedAt(LocalDateTime.now().format(DTF));
goblinSqbRedisUtils.setSqbOrder(orderId, orderVo);
syncOrderStatus(orderId, 1);
return ResponseDto.failure("退款失败,请稍后重试");
}
// 退款成功
orderVo.setStatus(3);
orderVo.setUpdatedAt(LocalDateTime.now().format(DTF));
goblinSqbRedisUtils.setSqbOrder(orderId, orderVo);
goblinRedisUtils.incrSkuStock(null, orderVo.getSkuId(), orderVo.getQuantity());
syncOrderStatus(orderId, 3);
log.info("[收钱吧退款] 退款成功,orderId={}", orderId);
return ResponseDto.success(Boolean.TRUE);
} catch (Exception e) {
log.error("[收钱吧退款] 退款异常,orderId={},回滚 status=1", orderId, e);
orderVo.setStatus(1);
orderVo.setUpdatedAt(LocalDateTime.now().format(DTF));
goblinSqbRedisUtils.setSqbOrder(orderId, orderVo);
syncOrderStatus(orderId, 1);
return ResponseDto.failure("退款失败:" + e.getMessage());
}
}
// ================================ 同步核销状态 ================================
@Override
public ResponseDto<Boolean> syncCouponStatus(String userId, String orderId) {
log.info("[收钱吧核销同步] 开始 userId={}, orderId={}", userId, orderId);
GoblinSqbOrderVo orderVo = goblinSqbRedisUtils.getSqbOrder(orderId);
if (orderVo == null) return ResponseDto.failure("订单不存在");
if (!userId.equals(orderVo.getUserId())) return ResponseDto.failure("无权限访问该订单");
CouponStatusSyncRequest req = new CouponStatusSyncRequest();
req.setAppid(sqbBiz.getSqbConfig().getAppId());
req.setRedeemSource("EXTERN");
// TODO: 填充 voucherNos(券号列表)、redeemMerchantId、redeemExternalOrderSn、clientSn、status
// 需要从 orderVo 中获取 couponSn 和其他必要字段
if (orderVo.getCouponSn() != null) {
req.setVoucherNos(java.util.Collections.singletonList(orderVo.getCouponSn()));
}
req.setRedeemMerchantId(sqbBiz.getSqbConfig().getMerchantId());
req.setRedeemExternalOrderSn(IDGenerator.nextSnowId());
req.setClientSn("terminal_001"); // TODO: 配置终端号
req.setStatus((byte) 1); // 1-已核销
boolean couponUsed = sqbBiz.syncCouponStatus(req);
if (couponUsed) {
String now = LocalDateTime.now().format(DTF);
orderVo.setStatus(2);
orderVo.setCouponUsedStatus(1);
orderVo.setUpdatedAt(now);
goblinSqbRedisUtils.setSqbOrder(orderId, orderVo);
syncOrderStatus(orderId, 2);
log.info("[收钱吧核销同步] 核销成功,orderId={}", orderId);
}
return ResponseDto.success(couponUsed);
}
// ================================ 自动退款(定时任务) ================================
@Override
public ResponseDto<String> autoRefundByPerformance(String performancesId) {
log.info("[收钱吧自动退款] 开始处理演出 performancesId={}", performancesId);
// 查询该演出下 status=1(已支付)的订单(MySQL)
// TODO: 通过 GoblinSqbOrderMapper 查询(需注入后解注释)
// LambdaQueryWrapper<GoblinSqbOrder> query = new LambdaQueryWrapper<>();
// query.eq(GoblinSqbOrder::getPerformancesId, performancesId).eq(GoblinSqbOrder::getStatus, 1);
// List<GoblinSqbOrder> orders = goblinSqbOrderMapper.selectList(query);
int successCount = 0;
int failCount = 0;
// TODO: 取消注释并接入 GoblinSqbOrderMapper 后启用
// for (GoblinSqbOrder order : orders) {
// try {
// ResponseDto<Boolean> result = refund(order.getUserId(), order.getOrderId());
// if (result != null && result.isSuccess()) {
// successCount++;
// } else {
// log.warn("[收钱吧自动退款] 订单退款失败 orderId={}", order.getOrderId());
// failCount++;
// }
// } catch (Exception e) {
// log.error("[收钱吧自动退款] 订单退款异常 orderId={}", order.getOrderId(), e);
// failCount++;
// }
// }
String summary = String.format("演出 %s 自动退款完成:成功 %d 笔,失败 %d 笔", performancesId, successCount, failCount);
log.info("[收钱吧自动退款] {}", summary);
return ResponseDto.success(summary);
}
// ================================ 订单列表 ================================
@Override
public ResponseDto<List<GoblinSqbOrderDetailVo>> getOrderList(String userId) {
log.info("[收钱吧订单列表] userId={}", userId);
List<String> orderIds = goblinRedisUtils.getOrderList(userId);
if (CollectionUtils.isEmpty(orderIds)) {
return ResponseDto.success(Collections.emptyList());
}
List<GoblinSqbOrderDetailVo> result = new ArrayList<>();
for (String orderId : orderIds) {
GoblinStoreOrderVo storeOrderVo = goblinRedisUtils.getGoblinOrder(orderId);
if (storeOrderVo == null) continue;
// 取第一个 orderSkuId 判断 skuType
List<String> orderSkuVoIds = storeOrderVo.getOrderSkuVoIds();
if (CollectionUtils.isEmpty(orderSkuVoIds)) continue;
GoblinOrderSkuVo skuVo = goblinRedisUtils.getGoblinOrderSkuVo(orderSkuVoIds.get(0));
if (skuVo == null) continue;
// 过滤:只处理 skuType=33 的收钱吧订单
if (!Integer.valueOf(33).equals(skuVo.getSkuType())) continue;
GoblinSqbOrderVo sqbOrderVo = goblinSqbRedisUtils.getSqbOrder(orderId);
result.add(buildDetailVo(storeOrderVo, skuVo, sqbOrderVo));
}
// 按创建时间倒序排列
result.sort((a, b) -> {
if (a.getCreatedAt() == null) return 1;
if (b.getCreatedAt() == null) return -1;
return b.getCreatedAt().compareTo(a.getCreatedAt());
});
log.info("[收钱吧订单列表] userId={}, 共 {} 条", userId, result.size());
return ResponseDto.success(result);
}
// ================================ 订单详情 ================================
@Override
public ResponseDto<GoblinSqbOrderDetailVo> getOrderDetail(String userId, String orderId) {
log.info("[收钱吧订单详情] userId={}, orderId={}", userId, orderId);
GoblinStoreOrderVo storeOrderVo = goblinRedisUtils.getGoblinOrder(orderId);
if (storeOrderVo == null) return ResponseDto.failure("订单不存在");
if (!userId.equals(storeOrderVo.getUserId())) return ResponseDto.failure("无权限访问该订单");
List<String> orderSkuVoIds = storeOrderVo.getOrderSkuVoIds();
if (CollectionUtils.isEmpty(orderSkuVoIds)) return ResponseDto.failure("订单数据异常");
GoblinOrderSkuVo skuVo = goblinRedisUtils.getGoblinOrderSkuVo(orderSkuVoIds.get(0));
if (skuVo == null) return ResponseDto.failure("订单商品数据异常");
// 校验是收钱吧订单
if (!Integer.valueOf(33).equals(skuVo.getSkuType())) {
return ResponseDto.failure("该订单非收钱吧订单");
}
GoblinSqbOrderVo sqbOrderVo = goblinSqbRedisUtils.getSqbOrder(orderId);
GoblinSqbOrderDetailVo detailVo = buildDetailVo(storeOrderVo, skuVo, sqbOrderVo);
log.info("[收钱吧订单详情] 查询成功,orderId={}", orderId);
return ResponseDto.success(detailVo);
}
// ================================ 私有辅助方法 ================================
private CommonRequest.Seller buildSeller() {
CommonRequest.Seller seller = new CommonRequest.Seller();
seller.setMerchantId(sqbBiz.getSqbConfig().getMerchantId());
seller.setMerchantUserId(sqbBiz.getSqbConfig().getMerchantUserId());
seller.setRole(sqbBiz.getSqbConfig().getRole());
return seller;
}
private GoblinSqbOrderDetailVo buildDetailVo(GoblinStoreOrderVo storeOrderVo,
GoblinOrderSkuVo skuVo,
GoblinSqbOrderVo sqbOrderVo) {
GoblinSqbOrderDetailVo detailVo = new GoblinSqbOrderDetailVo();
// 来自 GoblinStoreOrderVo
detailVo.setOrderId(storeOrderVo.getOrderId());
detailVo.setOrderCode(storeOrderVo.getOrderCode());
detailVo.setStatus(storeOrderVo.getStatus());
detailVo.setPriceActual(storeOrderVo.getPriceActual());
detailVo.setCreatedAt(storeOrderVo.getCreatedAt());
detailVo.setPayTime(storeOrderVo.getPayTime());
// 来自 GoblinOrderSkuVo
detailVo.setSpuId(skuVo.getSpuId());
detailVo.setSpuName(skuVo.getSpuName());
detailVo.setSkuId(skuVo.getSkuId());
detailVo.setSkuName(skuVo.getSkuName());
detailVo.setSkuImage(skuVo.getSkuImage());
detailVo.setQuantity(skuVo.getNum());
// 来自 GoblinSqbOrderVo
if (sqbOrderVo != null) {
detailVo.setSqbStatus(sqbOrderVo.getStatus());
detailVo.setPerformancesId(sqbOrderVo.getPerformancesId());
detailVo.setSqbAcquiringSn(sqbOrderVo.getSqbAcquiringSn());
detailVo.setCouponSn(sqbOrderVo.getCouponSn());
detailVo.setCouponQrCode(sqbOrderVo.getCouponQrCode());
detailVo.setCouponExpireTime(sqbOrderVo.getCouponExpireTime());
detailVo.setCouponUsedStatus(sqbOrderVo.getCouponUsedStatus());
}
return detailVo;
}
/**
* 构建收钱吧请求唯一ID,规则:AppCode(4位)+ id,总长不超过40位。
*
* @param id 业务唯一标识(如雪花ID)
* @return 不超过40位的请求ID字符串
*/
private String buildRequestId(String id) {
String appCode = sqbBiz.getSqbConfig().getAppCode();
if (appCode == null) appCode = "";
String raw = appCode + id;
return raw.length() > 40 ? raw.substring(0, 40) : raw;
}
/**
* 构建收钱吧订单标题,不超过32位。
*
* @param name 商品名称
* @return 不超过32位的标题字符串
*/
private String buildTitle(String name) {
if (name == null || name.isEmpty()) return "商品支付";
return name.length() > 32 ? name.substring(0, 32) : name;
}
private void syncOrderStatus(String orderId, int status) {
GoblinStoreOrderVo storeOrderVo = goblinRedisUtils.getGoblinOrder(orderId);
if (storeOrderVo == null) return;
String now = LocalDateTime.now().format(DTF);
storeOrderVo.setStatus(status);
if (status == 1) { // 支付成功
storeOrderVo.setPayTime(now);
}
// 1. 同步 Redis
goblinRedisUtils.setGoblinOrder(orderId, storeOrderVo);
// 2. 同步 MongoDB
goblinMongoUtils.updateGoblinStoreOrderVo(orderId, storeOrderVo);
// 3. 同步 MySQL (复用下单 MQ 发送 Update 语句)
String sql;
Object[] data;
if (status == 1) {
sql = "UPDATE goblin_store_order SET status = ?, pay_time = ?, updated_at = ? WHERE order_id = ?";
data = new Object[]{status, now, now, orderId};
} else {
sql = "UPDATE goblin_store_order SET status = ?, updated_at = ? WHERE order_id = ?";
data = new Object[]{status, now, orderId};
}
java.util.LinkedList<String> sqls = new java.util.LinkedList<>();
sqls.add(sql);
java.util.LinkedList<Object[]> sqlData = new java.util.LinkedList<>();
sqlData.add(data);
if (queueUtils != null) {
queueUtils.sendMsgByRedis(com.liquidnet.service.base.constant.MQConst.GoblinQueue.GOBLIN_ORDER_CREATE_PAY.getKey(),
com.liquidnet.service.base.SqlMapping.gets(sqls, sqlData));
}
}
}
package com.liquidnet.service.goblin.service.impl.manage;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.liquidnet.common.third.sqb.biz.SqbBiz;
import com.liquidnet.common.third.sqb.param.request.CommonRequest;
import com.liquidnet.common.third.sqb.param.request.MallListQueryRequest;
import com.liquidnet.common.third.sqb.param.request.MallProductsQueryRequest;
import com.liquidnet.common.third.sqb.param.response.data.MallListQueryData;
import com.liquidnet.common.third.sqb.param.response.data.MallProductsQueryData;
import com.liquidnet.commons.lang.util.CollectionUtil;
import com.liquidnet.commons.lang.util.JsonUtils;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.base.SqlMapping;
import com.liquidnet.service.base.constant.MQConst;
import com.liquidnet.service.goblin.config.properties.ShouqianbaProperties;
import com.liquidnet.service.goblin.dto.GoblinGoodsSpecDto;
import com.liquidnet.service.goblin.dto.manage.GoblinStoreMgtGoodsSqbAddParam;
import com.liquidnet.service.goblin.dto.manage.vo.GoblinMgtCategorySpecVo;
import com.liquidnet.service.goblin.dto.vo.*;
import com.liquidnet.service.goblin.entity.GoblinSqbGoodsExt;
import com.liquidnet.service.goblin.mapper.GoblinSqbGoodsExtMapper;
import com.liquidnet.service.goblin.param.shouqianba.request.CommonRequest;
import com.liquidnet.service.goblin.param.shouqianba.request.MallListQueryRequest;
import com.liquidnet.service.goblin.param.shouqianba.request.MallProductsQueryRequest;
import com.liquidnet.service.goblin.param.shouqianba.response.data.MallListQueryData;
import com.liquidnet.service.goblin.param.shouqianba.response.data.MallProductsQueryData;
import com.liquidnet.service.goblin.service.IGoblinShouQianBaService;
import com.liquidnet.service.goblin.service.manage.IGoblinStoreMgtSqbGoodsService;
import com.liquidnet.service.goblin.util.GoblinMongoUtils;
import com.liquidnet.service.goblin.util.GoblinRedisUtils;
import com.liquidnet.service.goblin.util.ObjectUtil;
import com.liquidnet.service.goblin.util.QueueUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
......@@ -51,9 +49,8 @@ public class GoblinStoreMgtSqbGoodsServiceImpl implements IGoblinStoreMgtSqbGood
@Autowired
GoblinSqbGoodsExtMapper goblinSqbGoodsExtMapper;
@Autowired
private IGoblinShouQianBaService goblinShouQianBaService;
@Autowired
private ShouqianbaProperties shouqianbaProperties;
private SqbBiz goblinShouQianBaService;
@Override
public ResponseDto<List<GoblinSqbPerfGoodsVo>> getProductList() {
......@@ -114,7 +111,7 @@ public class GoblinStoreMgtSqbGoodsServiceImpl implements IGoblinStoreMgtSqbGood
String lastMallSn = null;
while (true) {
MallListQueryRequest mallRequest = new MallListQueryRequest();
mallRequest.setAppid(shouqianbaProperties.getAppId());
mallRequest.setAppid(goblinShouQianBaService.getSqbConfig().getAppId());
MallListQueryRequest.Filter filter = new MallListQueryRequest.Filter();
filter.setSeller(buildSeller());
mallRequest.setFilter(filter);
......@@ -148,7 +145,7 @@ public class GoblinStoreMgtSqbGoodsServiceImpl implements IGoblinStoreMgtSqbGood
*/
private List<MallProductsQueryData> fetchAllProducts(MallListQueryData mall) {
MallProductsQueryRequest productRequest = new MallProductsQueryRequest();
productRequest.setAppid(shouqianbaProperties.getAppId());
productRequest.setAppid(goblinShouQianBaService.getSqbConfig().getAppId());
productRequest.setSeller(buildSeller());
CommonRequest.Mall mallId = new CommonRequest.Mall();
mallId.setMallSn(mall.getMallSn());
......@@ -159,9 +156,9 @@ public class GoblinStoreMgtSqbGoodsServiceImpl implements IGoblinStoreMgtSqbGood
}
private CommonRequest.Seller buildSeller() {
CommonRequest.Seller seller = new CommonRequest.Seller();
seller.setMerchantId(shouqianbaProperties.getMerchantId());
seller.setMerchantUserId(shouqianbaProperties.getMerchantUserId());
seller.setRole(shouqianbaProperties.getRole());
seller.setMerchantId(goblinShouQianBaService.getSqbConfig().getMerchantId());
seller.setMerchantUserId(goblinShouQianBaService.getSqbConfig().getMerchantUserId());
seller.setRole(goblinShouQianBaService.getSqbConfig().getRole());
return seller;
}
......
package com.liquidnet.service.goblin.util;
import com.liquidnet.service.goblin.constant.GoblinRedisConst;
import com.liquidnet.service.base.constant.RedisKeyExpireConst;
import com.liquidnet.common.cache.redis.util.RedisUtil;
import com.liquidnet.commons.lang.util.CollectionUtil;
import com.liquidnet.service.base.constant.RedisKeyExpireConst;
import com.liquidnet.service.goblin.constant.GoblinRedisConst;
import com.liquidnet.service.goblin.dto.vo.GoblinSqbOrderVo;
import com.liquidnet.service.goblin.dto.vo.GoblinSqbPerfGoodsVo;
import lombok.extern.slf4j.Slf4j;
......@@ -73,4 +74,18 @@ public class GoblinSqbRedisUtils {
String key = GoblinRedisConst.SQB_ORDER_LOCK.concat(userId).concat(":").concat(skuId);
redisUtil.uLock(key);
}
// 获取 收钱吧订单id列表
public List<String> getSqbOrderList(String uid) {
String redisKey = GoblinRedisConst.SQB_GOBLIN_ORDER_LIST.concat(uid);
Object obj = redisUtil.get(redisKey);
if (obj == null) {
return CollectionUtil.arrayListString();
} else {
return (List<String>) obj;
}
}
}
......@@ -193,8 +193,9 @@ goblin_nft_order.update_artwork=UPDATE goblin_nft_order SET artwork_id=? WHERE o
goblin_sku.stock=UPDATE goblin_goods_sku SET sku_stock = ? , stock = ?, updated_at = ? WHERE sku_erp_code = ? and erp_warehouse_no = ?
#----
candy_user_coupon.update_apply_refund=UPDATE candy_user_coupon SET state=?,operator=?,updated_at=? WHERE ucoupon_id=?
#----
#----
# ----- \u6536\u94B1\u5427 ----
goblin_sqb_order.insert=INSERT INTO goblin_sqb_order (order_id,user_id,performances_id,spu_id,sku_id,quantity,amount,sqb_order_sn,sqb_order_signature,sqb_acquiring_sn, sqb_acquiring_sign,sqb_checkout_items_id,status,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
# ---- \u624B\u73AF\u8BA2\u5355 ----
goblin_bracelet_order_insert = INSERT INTO `goblin_bracelet_order`(`order_id`, `user_id`, `bind_name`, `bind_mobile`, `bind_idcard`, `req_date`, `goods_desc`, `wristband_id`, `wristband_price`, `amount_id`, `amount_price`, `req_seq_id`, `hf_seq_id`, `trade_type`, `party_order_id`, `price`, `price_total`, `price_refund`, `refund_price_charges`, `refund_number`, `status`, `pay_status`, `created_at`, `updated_at`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
gpblin_bracelet_order_update= update goblin_bracelet_order set out_trans_id=?, end_time=?, acct_date=?, price_actual=?, time_pay=?, status=?, pay_status=?, updated_at=? where order_id=?
......
......@@ -76,6 +76,12 @@
<scope>system</scope>
<systemPath>${basedir}/lib/taobao-sdk-java-auto_1600401599540-20210607-impl.jar</systemPath>
</dependency>
<dependency>
<groupId>com.liquidnet</groupId>
<artifactId>liquidnet-common-third-sqb</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
......
package com.liquidnet.service.goblin.controller;
package com.liquidnet.service.order.controller;
import com.liquidnet.common.third.sqb.biz.SqbBiz;
import com.liquidnet.common.third.sqb.param.callback.CallbackParams;
import com.liquidnet.common.third.sqb.param.callback.CouponCallbackContent;
import com.liquidnet.common.third.sqb.param.callback.OrderCallbackContent;
import com.liquidnet.common.third.sqb.param.callback.RefundCallbackContent;
import com.liquidnet.commons.lang.util.CurrentUtil;
import com.liquidnet.commons.lang.util.JsonUtils;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.goblin.param.shouqianba.callback.CallbackParams;
import com.liquidnet.service.goblin.param.shouqianba.callback.CouponCallbackContent;
import com.liquidnet.service.goblin.param.shouqianba.callback.OrderCallbackContent;
import com.liquidnet.service.goblin.param.shouqianba.callback.RefundCallbackContent;
import com.liquidnet.service.goblin.service.IGoblinShouQianBaService;
import com.liquidnet.service.base.codec.vo.EncryptedReq;
import com.liquidnet.service.goblin.dto.manage.GoblinSqbOrderParam;
import com.liquidnet.service.goblin.dto.vo.GoblinSqbOrderCreateVo;
import com.liquidnet.service.goblin.service.IGoblinSqbOrderService;
import com.liquidnet.service.goblin.service.IGoblinSqbService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotBlank;
@Slf4j
@Api(tags = "收钱吧相关")
@Api(tags = "商城-收钱吧支付相关")
@RestController
@RequestMapping("/sqb")
public class GoblinShouqianbaController {
@RequestMapping("/goblin/sqb")
public class GoblinSqbOrderController {
@Autowired
private IGoblinShouQianBaService shouQianBaService;
private IGoblinSqbOrderService goblinSqbOrderService;
@Autowired
private IGoblinSqbOrderService sqbOrderService;
private SqbBiz sqbBiz;
/**
* 创建收钱吧订单
*/
@PostMapping("/pre")
@ApiOperation("创建收钱吧下单")
public ResponseDto<GoblinSqbOrderCreateVo> preOrder(EncryptedReq<GoblinSqbOrderParam> param) {
String userId = CurrentUtil.getCurrentUid();
GoblinSqbOrderParam orderParam = param.getData();
return goblinSqbOrderService.createOrder(userId, orderParam);
}
/**
* 查询支付状态
*/
@GetMapping("/pay/status")
@ApiOperation("查询支付状态")
@ApiImplicitParam(type = "query", required = true, dataType = "String", name = "orderId", value = "本地订单ID")
public ResponseDto<Integer> queryPayStatus(
@NotBlank(message = "orderId 不能为空") @RequestParam("orderId") String orderId) {
String userId = CurrentUtil.getCurrentUid();
log.info("[收钱吧支付状态] 接收请求 userId={}, orderId={}", userId, orderId);
return goblinSqbOrderService.queryPayStatus(userId, orderId);
}
/**
* 再次付款(待支付状态下重新拉起微信支付)
*/
@PostMapping("/repay")
@ApiOperation("再次付款")
@ApiImplicitParam(type = "form", required = true, dataType = "String", name = "orderId", value = "本地订单ID")
public ResponseDto<GoblinSqbOrderCreateVo> repay(
@NotBlank(message = "orderId 不能为空") @RequestParam("orderId") String orderId) {
String userId = CurrentUtil.getCurrentUid();
log.info("[收钱吧再次付款] 接收请求 userId={}, orderId={}", userId, orderId);
return goblinSqbOrderService.repay(userId, orderId);
}
//******************************** 回调相关 *******************************
@ApiOperation("下单回调")
@PostMapping("/order/callback")
public ResponseDto<String> orderCallback(@RequestBody CallbackParams callbackParams) {
......@@ -36,7 +82,7 @@ public class GoblinShouqianbaController {
log.error("下单回调参数为空");
return ResponseDto.failure("下单回调参数为空");
}
boolean verified = shouQianBaService.verifySignature(callbackParams);
boolean verified = sqbBiz.verifySignature(callbackParams);
if (!verified) {
log.error("下单回调验签失败");
return ResponseDto.failure("验签失败");
......@@ -45,7 +91,7 @@ public class GoblinShouqianbaController {
OrderCallbackContent orderCallbackContent = JsonUtils.fromJson(callbackParams.getContent(), OrderCallbackContent.class);
log.info("下单回调content: {}", callbackParams.getContent());
// 业务
return sqbOrderService.handlePayCallback(orderCallbackContent);
return goblinSqbOrderService.handlePayCallback(orderCallbackContent);
}
@ApiOperation("退款回调")
......@@ -55,7 +101,7 @@ public class GoblinShouqianbaController {
log.error("退款回调参数为空");
return ResponseDto.failure("退款回调参数为空");
}
boolean verified = shouQianBaService.verifySignature(callbackParams);
boolean verified = sqbBiz.verifySignature(callbackParams);
if (!verified) {
log.error("退款回调验签失败");
return ResponseDto.failure("验签失败");
......@@ -64,7 +110,7 @@ public class GoblinShouqianbaController {
RefundCallbackContent refundCallbackContent = JsonUtils.fromJson(callbackParams.getContent(), RefundCallbackContent.class);
log.info("退款回调content: {}", callbackParams.getContent());
// 业务
return sqbOrderService.handleRefundCallback(refundCallbackContent);
return goblinSqbOrderService.handleRefundCallback(refundCallbackContent);
}
@ApiOperation("券状态回调")
......@@ -74,7 +120,7 @@ public class GoblinShouqianbaController {
log.error("券状态回调参数为空");
return ResponseDto.failure("券状态回调参数为空");
}
boolean verified = shouQianBaService.verifySignature(callbackParams);
boolean verified = sqbBiz.verifySignature(callbackParams);
if (!verified) {
log.error("券状态回调验签失败");
return ResponseDto.failure("验签失败");
......@@ -84,7 +130,6 @@ public class GoblinShouqianbaController {
log.info("券状态回调content: {}", callbackParams.getContent());
// 业务
return sqbOrderService.handleCouponCallback(callbackContent);
return goblinSqbOrderService.handleCouponCallback(callbackContent);
}
}
package com.liquidnet.service.goblin.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
package com.liquidnet.service.order.service.impl;
import com.liquidnet.common.third.sqb.biz.SqbBiz;
import com.liquidnet.common.third.sqb.param.callback.CouponCallbackContent;
import com.liquidnet.common.third.sqb.param.callback.OrderCallbackContent;
import com.liquidnet.common.third.sqb.param.callback.RefundCallbackContent;
import com.liquidnet.common.third.sqb.param.request.CashierQueryRequest;
import com.liquidnet.common.third.sqb.param.request.CommonRequest;
import com.liquidnet.common.third.sqb.param.request.CreateWechatPrepayOrderRequest;
import com.liquidnet.common.third.sqb.param.request.SettlementCreateRequest;
import com.liquidnet.common.third.sqb.param.response.data.*;
import com.liquidnet.commons.lang.util.IDGenerator;
import com.liquidnet.commons.lang.util.JsonUtils;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.goblin.config.properties.ShouqianbaProperties;
import com.liquidnet.service.goblin.dto.manage.GoblinSqbOrderParam;
import com.liquidnet.service.goblin.dto.vo.*;
import com.liquidnet.service.goblin.entity.GoblinSqbPerformanceGoods;
import com.liquidnet.service.goblin.mapper.GoblinSqbPerformanceGoodsMapper;
import com.liquidnet.service.goblin.param.shouqianba.callback.CouponCallbackContent;
import com.liquidnet.service.goblin.param.shouqianba.callback.OrderCallbackContent;
import com.liquidnet.service.goblin.param.shouqianba.callback.RefundCallbackContent;
import com.liquidnet.service.goblin.param.shouqianba.request.*;
import com.liquidnet.service.goblin.param.shouqianba.response.data.*;
import com.liquidnet.service.goblin.service.IGoblinShouQianBaService;
import com.liquidnet.service.goblin.service.IGoblinSqbOrderService;
import com.liquidnet.service.goblin.util.GoblinRedisUtils;
import com.liquidnet.service.goblin.util.GoblinSqbConvertUtils;
import com.liquidnet.service.goblin.util.GoblinSqbRedisUtils;
import com.liquidnet.service.order.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
/**
* 收钱吧订单服务实现
*/
@Slf4j
@Service
@Slf4j
public class GoblinSqbOrderServiceImpl implements IGoblinSqbOrderService {
@Autowired
private GoblinSqbRedisUtils goblinSqbRedisUtils;
@Autowired
private GoblinRedisUtils goblinRedisUtils;
@Autowired
private com.liquidnet.service.goblin.util.GoblinMongoUtils goblinMongoUtils;
private GoblinSqbRedisUtils goblinSqbRedisUtils;
@Autowired
private com.liquidnet.service.goblin.util.QueueUtils queueUtils;
private GoblinMongoUtils goblinMongoUtils;
@Autowired
private GoblinSqbPerformanceGoodsMapper goblinSqbPerformanceGoodsMapper;
private QueueUtils queueUtils;
@Autowired
private IGoblinShouQianBaService goblinShouQianBaService;
private SqbBiz sqbBiz;
private static final DateTimeFormatter DTF = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Autowired
private ShouqianbaProperties shouqianbaProperties;
@Autowired
private GoblinSqbConvertUtils sqbConvertUtils;
// ================================ 创建订单 ================================
@Override
public ResponseDto<GoblinSqbOrderCreateVo> createOrder(String userId, String spuId, String skuId,
Integer quantity, String performancesId) {
log.info("[收钱吧下单] 开始 userId={}, spuId={}, skuId={}, quantity={}, performancesId={}",
userId, spuId, skuId, quantity, performancesId);
public ResponseDto<GoblinSqbOrderCreateVo> createOrder(String userId, GoblinSqbOrderParam orderParam) {
log.info("[收钱吧下单] 下单开始 userId={}, param: {}", userId, JsonUtils.toJson(orderParam));
String skuId = orderParam.getSkuId();
String spuId = orderParam.getSpuId();
String performancesId = orderParam.getPerformancesId();
Integer quantity = orderParam.getQuantity();
// Step 1: 分布式锁防重
boolean locked = goblinSqbRedisUtils.tryOrderLock(userId, skuId);
......@@ -76,18 +71,28 @@ public class GoblinSqbOrderServiceImpl implements IGoblinSqbOrderService {
try {
// Step 2: 校验演出-商品关联
LambdaQueryWrapper<GoblinSqbPerformanceGoods> query = new LambdaQueryWrapper<>();
query.eq(GoblinSqbPerformanceGoods::getPerformancesId, performancesId)
.eq(GoblinSqbPerformanceGoods::getSkuId, skuId)
.eq(GoblinSqbPerformanceGoods::getStatus, 1);
GoblinSqbPerformanceGoods relation = goblinSqbPerformanceGoodsMapper.selectOne(query);
if (relation == null) {
log.warn("[收钱吧下单] 演出-商品关联不存在或已禁用,performancesId={}, skuId={}", performancesId, skuId);
List<GoblinSqbPerfGoodsVo> perfGoods = goblinSqbRedisUtils.getPerfGoods(performancesId);
if (perfGoods.isEmpty()) {
log.error("[收钱吧下单] 演出关联商品列表为空,performancesId={}, skuId={}", performancesId, skuId);
return ResponseDto.failure("商品与演出关联不存在");
}
boolean skuIdExists = false;
for (GoblinSqbPerfGoodsVo perfGood : perfGoods) {
for (MallProductsQueryData.Sku skuResult : perfGood.getSkuResults()) {
if (skuId.equals(skuResult.getSkuId())) {
skuIdExists = true;
}
}
}
if (!skuIdExists) {
log.error("[收钱吧下单] 演出-商品关联不存在或已禁用,performancesId={}, skuId={}", performancesId, skuId);
return ResponseDto.failure("商品与演出关联不存在");
}
// Step 3: 原子扣减库存
long remaining = goblinRedisUtils.decrSkuStock(null, skuId, quantity);
int remaining = goblinRedisUtils.decrSkuStock(null, skuId, quantity);
if (remaining < 0) {
goblinRedisUtils.incrSkuStock(null, skuId, quantity);
log.warn("[收钱吧下单] 库存不足,skuId={}, quantity={}", skuId, quantity);
......@@ -98,6 +103,7 @@ public class GoblinSqbOrderServiceImpl implements IGoblinSqbOrderService {
GoblinGoodsSkuInfoVo skuVo = goblinRedisUtils.getGoodsSkuInfoVo(skuId);
if (skuVo == null) {
log.error("[收钱吧下单] 未找到商品, skuId: {}, spuId: {}", skuId, spuId);
return ResponseDto.failure("商品不存在");
}
if (!skuId.equals(skuVo.getSkuId())) {
return ResponseDto.failure("下单失败");
......@@ -106,7 +112,7 @@ public class GoblinSqbOrderServiceImpl implements IGoblinSqbOrderService {
//TODO 获取该商品对应的商城的编号和密码
Map<String, String> sqbInfoMap = sqbConvertUtils.getSqbInfoByzhengzaiSkuIdAndSpuId(skuId, spuId);
SettlementCreateData settlementData = goblinShouQianBaService.createSettlement(
SettlementCreateData settlementData = sqbBiz.createSettlement(
sqbInfoMap.get("mallSn"),
sqbInfoMap.get("signature"),
userId,
......@@ -119,13 +125,14 @@ public class GoblinSqbOrderServiceImpl implements IGoblinSqbOrderService {
log.info("[收钱吧下单] 创建结算明细成功,checkoutItemsId={}", checkoutItemsId);
// Step 4.2: createOrder → 得 sqbOrderSn + sqbOrderSignature + sqbAcquiringSn
OrderCreateData orderData = goblinShouQianBaService.createOrder(
String goodsName = skuVo.getName();
OrderCreateData orderData = sqbBiz.createOrder(
sqbInfoMap.get("mallSn"),
sqbInfoMap.get("signature"),
checkoutItemsId,
userId,
"", // TODO 构建请求ID
"" // TODO 构建标题
buildRequestId(IDGenerator.nextSnowId()),
buildTitle(goodsName)
);
if (orderData == null) {
goblinRedisUtils.incrSkuStock(null, skuId, quantity);
......@@ -138,7 +145,7 @@ public class GoblinSqbOrderServiceImpl implements IGoblinSqbOrderService {
log.info("[收钱吧下单] 创建订单成功,订单编号={}, 收单号={}", sqbOrderSn, sqbAcquiringSn);
// Step 4.3: queryCashier → 得 selectedSignature + seq
CashierQueryData cashierData = goblinShouQianBaService.queryCashier(sqbAcquiringSn, sqbAcquiringSign, userId);
CashierQueryData cashierData = sqbBiz.queryCashier(sqbAcquiringSn, sqbAcquiringSign, userId);
if (cashierData == null) {
goblinRedisUtils.incrSkuStock(null, skuId, quantity);
return ResponseDto.failure("查询收银台失败");
......@@ -148,11 +155,11 @@ public class GoblinSqbOrderServiceImpl implements IGoblinSqbOrderService {
String seq = cashierData.getSeq(); // 响应唯一序列号
log.info("[收钱吧下单] 查询收银台成功,selectedSignature={}, seq={}", selectedSignature, seq);
CreateWechatPrepayOrderData prepayData = goblinShouQianBaService.createWechatPrepayOrder(sqbAcquiringSn,
CreateWechatPrepayOrderData prepayData = sqbBiz.createWechatPrepayOrder(sqbAcquiringSn,
sqbAcquiringSign,
userId,
"",
"",
String.valueOf(cashierData.getAmount()),
buildRequestId(IDGenerator.nextSnowId()),
cashierData.getPayTools().get(0),
new HashMap<String, Object>(),
selectedSignature,
......@@ -187,15 +194,15 @@ public class GoblinSqbOrderServiceImpl implements IGoblinSqbOrderService {
storeOrderVo.setUserName("");
storeOrderVo.setUserMobile("");
java.math.BigDecimal skuPrice = skuInfo != null ? skuInfo.getPrice() : java.math.BigDecimal.ZERO;
java.math.BigDecimal priceTotal = skuPrice.multiply(new java.math.BigDecimal(quantity));
BigDecimal skuPrice = skuInfo != null ? skuInfo.getPrice() : BigDecimal.ZERO;
BigDecimal priceTotal = skuPrice.multiply(new BigDecimal(quantity));
storeOrderVo.setPriceTotal(priceTotal);
storeOrderVo.setPriceActual(priceTotal); // 收钱吧暂无运费及优惠逻辑,实际价格等于总价
storeOrderVo.setPriceRefund(java.math.BigDecimal.ZERO);
storeOrderVo.setPriceExpress(java.math.BigDecimal.ZERO);
storeOrderVo.setPriceCoupon(java.math.BigDecimal.ZERO);
storeOrderVo.setStorePriceCoupon(java.math.BigDecimal.ZERO);
storeOrderVo.setPriceVoucher(java.math.BigDecimal.ZERO);
storeOrderVo.setPriceRefund(BigDecimal.ZERO);
storeOrderVo.setPriceExpress(BigDecimal.ZERO);
storeOrderVo.setPriceCoupon(BigDecimal.ZERO);
storeOrderVo.setStorePriceCoupon(BigDecimal.ZERO);
storeOrderVo.setPriceVoucher(BigDecimal.ZERO);
// 待支付
storeOrderVo.setStatus(0);
storeOrderVo.setPayType("SQB_PAY"); // 标识为收钱吧支付类型
......@@ -219,7 +226,7 @@ public class GoblinSqbOrderServiceImpl implements IGoblinSqbOrderService {
orderSkuVo.setSkuName(skuInfo != null ? skuInfo.getName() : "收钱吧未匹配SKU");
orderSkuVo.setSkuImage(skuInfo != null ? skuInfo.getSkuPic() : "");
orderSkuVo.setSkuSpecs("[]");
orderSkuVo.setPriceVoucher(java.math.BigDecimal.ZERO);
orderSkuVo.setPriceVoucher(BigDecimal.ZERO);
orderSkuVo.setCreatedAt(now);
// 特殊标识类型:33
orderSkuVo.setSkuType(33);
......@@ -243,6 +250,7 @@ public class GoblinSqbOrderServiceImpl implements IGoblinSqbOrderService {
orderVo.setSqbOrderSn(sqbOrderSn);
orderVo.setSqbOrderSignature(sqbOrderSignature);
orderVo.setSqbAcquiringSn(sqbAcquiringSn);
orderVo.setSqbAcquiringSign(sqbAcquiringSign);
orderVo.setSqbCheckoutItemsId(checkoutItemsId);
// 内部状态同步使用
orderVo.setStatus(0);
......@@ -250,7 +258,7 @@ public class GoblinSqbOrderServiceImpl implements IGoblinSqbOrderService {
orderVo.setUpdatedAt(now);
goblinSqbRedisUtils.setSqbOrder(orderId, orderVo);
goblinRedisUtils.addOrderList(userId, orderId);
goblinSqbRedisUtils.addSqbOrderList(userId, orderId);
log.info("[收钱吧下单] 订单写入 Redis 成功,orderId={}", orderId);
// Step 6: 写 MongoDB + 发送复用的 SQL MQ
......@@ -260,11 +268,12 @@ public class GoblinSqbOrderServiceImpl implements IGoblinSqbOrderService {
// 收钱吧扩展暂无需单独写 MongoDB 除非专门需要查询
// 拼接 SQL 数据并丢队列
java.util.LinkedList<String> sqls = new java.util.LinkedList<>();
LinkedList<String> sqls = new LinkedList<>();
sqls.add(com.liquidnet.service.base.SqlMapping.get("goblin.order.create.sku_insert"));
sqls.add(com.liquidnet.service.base.SqlMapping.get("goblin.order.create.order_insert"));
sqls.add(com.liquidnet.service.base.SqlMapping.get("goblin_sqb_order.insert"));
java.util.LinkedList<Object[]> sqlDataSku = new java.util.LinkedList<>();
LinkedList<Object[]> sqlDataSku = new LinkedList<>();
sqlDataSku.add(new Object[]{
orderSkuVo.getOrderSkuId(), orderSkuVo.getOrderId(), orderSkuVo.getSpuId(), orderSkuVo.getSpuName(), (goodsInfo != null ? goodsInfo.getCoverPic() : ""),
orderSkuVo.getSkuId(), orderSkuVo.getNum(), orderSkuVo.getSkuPrice(), orderSkuVo.getSkuPriceActual(), orderSkuVo.getSkuName(),
......@@ -273,7 +282,7 @@ public class GoblinSqbOrderServiceImpl implements IGoblinSqbOrderService {
orderSkuVo.getCreatedAt()
});
java.util.LinkedList<Object[]> sqlDataOrder = new java.util.LinkedList<>();
LinkedList<Object[]> sqlDataOrder = new LinkedList<>();
sqlDataOrder.add(new Object[]{
storeOrderVo.getMasterOrderCode(), storeOrderVo.getOrderId(), storeOrderVo.getStoreId(), storeOrderVo.getStoreName(), storeOrderVo.getOrderCode(),
storeOrderVo.getUserId(), storeOrderVo.getUserName(), storeOrderVo.getUserMobile(), storeOrderVo.getPriceTotal(), storeOrderVo.getPayCode(),
......@@ -283,10 +292,21 @@ public class GoblinSqbOrderServiceImpl implements IGoblinSqbOrderService {
storeOrderVo.getIpAddress(), storeOrderVo.getMarketId(), storeOrderVo.getMarketType(), storeOrderVo.getCreatedAt(), "", ""
});
// 收钱吧订单扩展表写库数据
// order_id, user_id, performances_id, spu_id, sku_id, quantity, amount(分),
// sqb_order_sn, sqb_order_signature, sqb_acquiring_sn, sqb_checkout_items_id, status, created_at, updated_at
LinkedList<Object[]> sqlDataSqbOrder = new LinkedList<>();
sqlDataSqbOrder.add(new Object[]{
orderId, userId, performancesId, spuId, skuId, quantity,
sqbConvertUtils.yuanToFen(priceTotal),
sqbOrderSn, sqbOrderSignature, sqbAcquiringSn, sqbAcquiringSign, checkoutItemsId,
0, now, now
});
// 借用 Base 模块中 ConsumerGoblinOrderCPRdsReceiver 这个队列消费类进行写库
if (queueUtils != null) {
queueUtils.sendMsgByRedis(com.liquidnet.service.base.constant.MQConst.GoblinQueue.GOBLIN_ORDER_CREATE_PAY.getKey(),
com.liquidnet.service.base.SqlMapping.gets(sqls, sqlDataSku, sqlDataOrder));
com.liquidnet.service.base.SqlMapping.gets(sqls, sqlDataSku, sqlDataOrder, sqlDataSqbOrder));
// 待支付超时回调等处理也可放入原有股票队列逻辑,暂省略
}
log.info("[收钱吧下单] 完成 MongoDB 及 MQ 落库,orderId={}, masterCode={}", orderId, masterOrderCode);
......@@ -317,6 +337,7 @@ public class GoblinSqbOrderServiceImpl implements IGoblinSqbOrderService {
/**
* 构建收钱吧-结算明细条目
*
* @param skuVo
* @param quantity
* @param sqbSkuId
......@@ -358,7 +379,7 @@ public class GoblinSqbOrderServiceImpl implements IGoblinSqbOrderService {
// 调用收钱吧查询收单状态
CommonRequest.Seller seller = buildSeller();
CashierQueryRequest cashierReq = buildCashierQueryRequest(seller, orderVo.getSqbAcquiringSn(), orderVo.getSqbOrderSignature());
CashierQueryData cashierData = goblinShouQianBaService.queryCashier(cashierReq);
CashierQueryData cashierData = sqbBiz.queryCashier(cashierReq);
if (cashierData == null) {
log.warn("[收钱吧支付状态] queryCashier 调用失败,orderId={}", orderId);
......@@ -381,151 +402,10 @@ public class GoblinSqbOrderServiceImpl implements IGoblinSqbOrderService {
return ResponseDto.success(orderVo.getStatus());
}
// ================================ 获取券码 ================================
@Override
public ResponseDto<GoblinSqbCouponVo> queryCoupon(String userId, String orderId) {
log.info("[收钱吧券码] 开始获取 userId={}, orderId={}", userId, orderId);
GoblinSqbOrderVo orderVo = goblinSqbRedisUtils.getSqbOrder(orderId);
if (orderVo == null) return ResponseDto.failure("订单不存在");
if (!userId.equals(orderVo.getUserId())) return ResponseDto.failure("无权限访问该订单");
if (!Integer.valueOf(1).equals(orderVo.getStatus())) return ResponseDto.failure("订单未支付,无法获取券码");
// 幂等:已存在则直接返回
if (orderVo.getCouponQrCode() != null && !orderVo.getCouponQrCode().isEmpty()) {
GoblinSqbCouponVo couponVo = new GoblinSqbCouponVo();
couponVo.setCouponSn(orderVo.getCouponSn());
couponVo.setCouponQrCode(orderVo.getCouponQrCode());
couponVo.setCouponExpireTime(orderVo.getCouponExpireTime());
return ResponseDto.success(couponVo);
}
// 调用收钱吧查询券码
CouponQueryRequest req = new CouponQueryRequest();
req.setAppid(shouqianbaProperties.getAppId());
req.setSeller(buildSeller());
CouponQueryData couponData = goblinShouQianBaService.queryCoupon(req);
if (couponData == null) return ResponseDto.failure("获取券码失败");
// 更新订单 coupon 字段
String now = LocalDateTime.now().format(DTF);
orderVo.setCouponSn(couponData.getVoucherNo());
orderVo.setCouponQrCode(couponData.getUrl());
orderVo.setCouponExpireTime(couponData.getOperationTime());
orderVo.setUpdatedAt(now);
goblinSqbRedisUtils.setSqbOrder(orderId, orderVo);
// 券码信息保存在 Redis,MySQL和MongoDB商城基础模型无此字段,无需同步
GoblinSqbCouponVo couponVo = new GoblinSqbCouponVo();
couponVo.setCouponSn(couponData.getVoucherNo());
couponVo.setCouponQrCode(couponData.getUrl());
couponVo.setCouponExpireTime(couponData.getOperationTime());
log.info("[收钱吧券码] 获取成功,orderId={}", orderId);
return ResponseDto.success(couponVo);
}
// ================================ 申请退款 ================================
@Override
public ResponseDto<Boolean> refund(String userId, String orderId) {
log.info("[收钱吧退款] 开始 userId={}, orderId={}", userId, orderId);
GoblinSqbOrderVo orderVo = goblinSqbRedisUtils.getSqbOrder(orderId);
if (orderVo == null) return ResponseDto.failure("订单不存在");
if (!userId.equals(orderVo.getUserId())) return ResponseDto.failure("无权限访问该订单");
if (!Integer.valueOf(1).equals(orderVo.getStatus())) return ResponseDto.failure("订单状态不可退款");
if (Integer.valueOf(1).equals(orderVo.getCouponUsedStatus())) return ResponseDto.failure("券码已核销,不可退款");
// 更新状态为退款中
String now = LocalDateTime.now().format(DTF);
orderVo.setStatus(4);
orderVo.setUpdatedAt(now);
goblinSqbRedisUtils.setSqbOrder(orderId, orderVo);
syncOrderStatus(orderId, 4);
try {
// 调用收钱吧退款
CouponRefundRequest refundReq = new CouponRefundRequest();
refundReq.setAppid(shouqianbaProperties.getAppId());
refundReq.setSeller(buildSeller());
refundReq.setRequestSource("EXTERN");
refundReq.setRequestId(IDGenerator.nextSnowId());
CouponRefundRequest.RefundInfo refundInfo = new CouponRefundRequest.RefundInfo();
// amount 字段待接入实际金额(GoblinSqbOrderVo 需补充 amount)
refundInfo.setApplyAmount(0L); // TODO: 替换为实际订单金额
refundInfo.setType((byte) 2); // 2-按金额退款
refundInfo.setRefundReason("用户申请退款");
refundReq.setRefundInfo(refundInfo);
CouponRefundData refundData = goblinShouQianBaService.refundCoupon(refundReq);
if (refundData == null) {
// 退款失败,回滚状态
orderVo.setStatus(1);
orderVo.setUpdatedAt(LocalDateTime.now().format(DTF));
goblinSqbRedisUtils.setSqbOrder(orderId, orderVo);
syncOrderStatus(orderId, 1);
return ResponseDto.failure("退款失败,请稍后重试");
}
// 退款成功
orderVo.setStatus(3);
orderVo.setUpdatedAt(LocalDateTime.now().format(DTF));
goblinSqbRedisUtils.setSqbOrder(orderId, orderVo);
goblinRedisUtils.incrSkuStock(null, orderVo.getSkuId(), orderVo.getQuantity());
syncOrderStatus(orderId, 3);
log.info("[收钱吧退款] 退款成功,orderId={}", orderId);
return ResponseDto.success(Boolean.TRUE);
} catch (Exception e) {
log.error("[收钱吧退款] 退款异常,orderId={},回滚 status=1", orderId, e);
orderVo.setStatus(1);
orderVo.setUpdatedAt(LocalDateTime.now().format(DTF));
goblinSqbRedisUtils.setSqbOrder(orderId, orderVo);
syncOrderStatus(orderId, 1);
return ResponseDto.failure("退款失败:" + e.getMessage());
}
}
// ================================ 同步核销状态 ================================
@Override
public ResponseDto<Boolean> syncCouponStatus(String userId, String orderId) {
log.info("[收钱吧核销同步] 开始 userId={}, orderId={}", userId, orderId);
GoblinSqbOrderVo orderVo = goblinSqbRedisUtils.getSqbOrder(orderId);
if (orderVo == null) return ResponseDto.failure("订单不存在");
if (!userId.equals(orderVo.getUserId())) return ResponseDto.failure("无权限访问该订单");
CouponStatusSyncRequest req = new CouponStatusSyncRequest();
req.setAppid(shouqianbaProperties.getAppId());
req.setRedeemSource("EXTERN");
// TODO: 填充 voucherNos(券号列表)、redeemMerchantId、redeemExternalOrderSn、clientSn、status
// 需要从 orderVo 中获取 couponSn 和其他必要字段
if (orderVo.getCouponSn() != null) {
req.setVoucherNos(java.util.Collections.singletonList(orderVo.getCouponSn()));
}
req.setRedeemMerchantId(shouqianbaProperties.getMerchantId());
req.setRedeemExternalOrderSn(IDGenerator.nextSnowId());
req.setClientSn("terminal_001"); // TODO: 配置终端号
req.setStatus((byte) 1); // 1-已核销
boolean couponUsed = goblinShouQianBaService.syncCouponStatus(req);
if (couponUsed) {
String now = LocalDateTime.now().format(DTF);
orderVo.setStatus(2);
orderVo.setCouponUsedStatus(1);
orderVo.setUpdatedAt(now);
goblinSqbRedisUtils.setSqbOrder(orderId, orderVo);
syncOrderStatus(orderId, 2);
log.info("[收钱吧核销同步] 核销成功,orderId={}", orderId);
}
return ResponseDto.success(couponUsed);
}
// ================================ 回调处理 ================================
......@@ -590,109 +470,6 @@ public class GoblinSqbOrderServiceImpl implements IGoblinSqbOrderService {
return ResponseDto.success("success");
}
// ================================ 自动退款(定时任务) ================================
@Override
public ResponseDto<String> autoRefundByPerformance(String performancesId) {
log.info("[收钱吧自动退款] 开始处理演出 performancesId={}", performancesId);
// 查询该演出下 status=1(已支付)的订单(MySQL)
// TODO: 通过 GoblinSqbOrderMapper 查询(需注入后解注释)
// LambdaQueryWrapper<GoblinSqbOrder> query = new LambdaQueryWrapper<>();
// query.eq(GoblinSqbOrder::getPerformancesId, performancesId).eq(GoblinSqbOrder::getStatus, 1);
// List<GoblinSqbOrder> orders = goblinSqbOrderMapper.selectList(query);
int successCount = 0;
int failCount = 0;
// TODO: 取消注释并接入 GoblinSqbOrderMapper 后启用
// for (GoblinSqbOrder order : orders) {
// try {
// ResponseDto<Boolean> result = refund(order.getUserId(), order.getOrderId());
// if (result != null && result.isSuccess()) {
// successCount++;
// } else {
// log.warn("[收钱吧自动退款] 订单退款失败 orderId={}", order.getOrderId());
// failCount++;
// }
// } catch (Exception e) {
// log.error("[收钱吧自动退款] 订单退款异常 orderId={}", order.getOrderId(), e);
// failCount++;
// }
// }
String summary = String.format("演出 %s 自动退款完成:成功 %d 笔,失败 %d 笔", performancesId, successCount, failCount);
log.info("[收钱吧自动退款] {}", summary);
return ResponseDto.success(summary);
}
// ================================ 订单列表 ================================
@Override
public ResponseDto<List<GoblinSqbOrderDetailVo>> getOrderList(String userId) {
log.info("[收钱吧订单列表] userId={}", userId);
List<String> orderIds = goblinRedisUtils.getOrderList(userId);
if (CollectionUtils.isEmpty(orderIds)) {
return ResponseDto.success(Collections.emptyList());
}
List<GoblinSqbOrderDetailVo> result = new ArrayList<>();
for (String orderId : orderIds) {
GoblinStoreOrderVo storeOrderVo = goblinRedisUtils.getGoblinOrder(orderId);
if (storeOrderVo == null) continue;
// 取第一个 orderSkuId 判断 skuType
List<String> orderSkuVoIds = storeOrderVo.getOrderSkuVoIds();
if (CollectionUtils.isEmpty(orderSkuVoIds)) continue;
GoblinOrderSkuVo skuVo = goblinRedisUtils.getGoblinOrderSkuVo(orderSkuVoIds.get(0));
if (skuVo == null) continue;
// 过滤:只处理 skuType=33 的收钱吧订单
if (!Integer.valueOf(33).equals(skuVo.getSkuType())) continue;
GoblinSqbOrderVo sqbOrderVo = goblinSqbRedisUtils.getSqbOrder(orderId);
result.add(buildDetailVo(storeOrderVo, skuVo, sqbOrderVo));
}
// 按创建时间倒序排列
result.sort((a, b) -> {
if (a.getCreatedAt() == null) return 1;
if (b.getCreatedAt() == null) return -1;
return b.getCreatedAt().compareTo(a.getCreatedAt());
});
log.info("[收钱吧订单列表] userId={}, 共 {} 条", userId, result.size());
return ResponseDto.success(result);
}
// ================================ 订单详情 ================================
@Override
public ResponseDto<GoblinSqbOrderDetailVo> getOrderDetail(String userId, String orderId) {
log.info("[收钱吧订单详情] userId={}, orderId={}", userId, orderId);
GoblinStoreOrderVo storeOrderVo = goblinRedisUtils.getGoblinOrder(orderId);
if (storeOrderVo == null) return ResponseDto.failure("订单不存在");
if (!userId.equals(storeOrderVo.getUserId())) return ResponseDto.failure("无权限访问该订单");
List<String> orderSkuVoIds = storeOrderVo.getOrderSkuVoIds();
if (CollectionUtils.isEmpty(orderSkuVoIds)) return ResponseDto.failure("订单数据异常");
GoblinOrderSkuVo skuVo = goblinRedisUtils.getGoblinOrderSkuVo(orderSkuVoIds.get(0));
if (skuVo == null) return ResponseDto.failure("订单商品数据异常");
// 校验是收钱吧订单
if (!Integer.valueOf(33).equals(skuVo.getSkuType())) {
return ResponseDto.failure("该订单非收钱吧订单");
}
GoblinSqbOrderVo sqbOrderVo = goblinSqbRedisUtils.getSqbOrder(orderId);
GoblinSqbOrderDetailVo detailVo = buildDetailVo(storeOrderVo, skuVo, sqbOrderVo);
log.info("[收钱吧订单详情] 查询成功,orderId={}", orderId);
return ResponseDto.success(detailVo);
}
// ================================ 再次付款 ================================
@Override
......@@ -715,14 +492,14 @@ public class GoblinSqbOrderServiceImpl implements IGoblinSqbOrderService {
// 重新查询收银台,获取新的 selectedSignature + seq
CashierQueryRequest cashierReq = buildCashierQueryRequest(
seller, orderVo.getSqbAcquiringSn(), orderVo.getSqbOrderSignature());
CashierQueryData cashierData = goblinShouQianBaService.queryCashier(cashierReq);
CashierQueryData cashierData = sqbBiz.queryCashier(cashierReq);
if (cashierData == null) return ResponseDto.failure("查询收银台失败,请稍后重试");
// 重新创建微信预支付
CreateWechatPrepayOrderRequest prepayReq = buildWechatPrepayRequest(
seller, orderVo.getSqbAcquiringSn(), orderVo.getSqbOrderSignature(),
cashierData.getSelectedSignature(), cashierData.getSeq(), cashierData);
CreateWechatPrepayOrderData prepayData = goblinShouQianBaService.createWechatPrepayOrder(prepayReq);
CreateWechatPrepayOrderData prepayData = sqbBiz.createWechatPrepayOrder(prepayReq);
if (prepayData == null || prepayData.getPaymentVoucher() == null) {
return ResponseDto.failure("创建微信预支付失败,请稍后重试");
}
......@@ -751,16 +528,16 @@ public class GoblinSqbOrderServiceImpl implements IGoblinSqbOrderService {
private CommonRequest.Seller buildSeller() {
CommonRequest.Seller seller = new CommonRequest.Seller();
seller.setMerchantId(shouqianbaProperties.getMerchantId());
seller.setMerchantUserId(shouqianbaProperties.getMerchantUserId());
seller.setRole(shouqianbaProperties.getRole());
seller.setMerchantId(sqbBiz.getSqbConfig().getMerchantId());
seller.setMerchantUserId(sqbBiz.getSqbConfig().getMerchantUserId());
seller.setRole(sqbBiz.getSqbConfig().getRole());
return seller;
}
private CashierQueryRequest buildCashierQueryRequest(CommonRequest.Seller seller,
String acquiringSn, String acquiringSignature) {
CashierQueryRequest req = new CashierQueryRequest();
req.setAppid(shouqianbaProperties.getAppId());
req.setAppid(sqbBiz.getSqbConfig().getAppId());
req.setSeller(seller);
req.setPaymentMode(4); // 4-微信小程序支付
......@@ -782,7 +559,7 @@ public class GoblinSqbOrderServiceImpl implements IGoblinSqbOrderService {
String seq,
CashierQueryData cashierData) {
CreateWechatPrepayOrderRequest req = new CreateWechatPrepayOrderRequest();
req.setAppid(shouqianbaProperties.getAppId());
req.setAppid(sqbBiz.getSqbConfig().getAppId());
req.setSeller(seller);
req.setAcquiringSn(acquiringSn);
req.setSignature(acquiringSignature);
......@@ -810,42 +587,31 @@ public class GoblinSqbOrderServiceImpl implements IGoblinSqbOrderService {
return req;
}
private GoblinSqbOrderDetailVo buildDetailVo(GoblinStoreOrderVo storeOrderVo,
GoblinOrderSkuVo skuVo,
GoblinSqbOrderVo sqbOrderVo) {
GoblinSqbOrderDetailVo detailVo = new GoblinSqbOrderDetailVo();
// 来自 GoblinStoreOrderVo
detailVo.setOrderId(storeOrderVo.getOrderId());
detailVo.setOrderCode(storeOrderVo.getOrderCode());
detailVo.setStatus(storeOrderVo.getStatus());
detailVo.setPriceActual(storeOrderVo.getPriceActual());
detailVo.setCreatedAt(storeOrderVo.getCreatedAt());
detailVo.setPayTime(storeOrderVo.getPayTime());
// 来自 GoblinOrderSkuVo
detailVo.setSpuId(skuVo.getSpuId());
detailVo.setSpuName(skuVo.getSpuName());
detailVo.setSkuId(skuVo.getSkuId());
detailVo.setSkuName(skuVo.getSkuName());
detailVo.setSkuImage(skuVo.getSkuImage());
detailVo.setQuantity(skuVo.getNum());
// 来自 GoblinSqbOrderVo
if (sqbOrderVo != null) {
detailVo.setSqbStatus(sqbOrderVo.getStatus());
detailVo.setPerformancesId(sqbOrderVo.getPerformancesId());
detailVo.setSqbAcquiringSn(sqbOrderVo.getSqbAcquiringSn());
detailVo.setCouponSn(sqbOrderVo.getCouponSn());
detailVo.setCouponQrCode(sqbOrderVo.getCouponQrCode());
detailVo.setCouponExpireTime(sqbOrderVo.getCouponExpireTime());
detailVo.setCouponUsedStatus(sqbOrderVo.getCouponUsedStatus());
}
return detailVo;
}
// private String getOrderIdFromParams(Map<String, Object> params) {
// String orderId = (String) params.get("orderId");
// if (orderId == null) orderId = (String) params.get("acquiringSn");
// return orderId;
// }
/**
* 构建收钱吧请求唯一ID,规则:AppCode(4位)+ id,总长不超过40位。
*
* @param id 业务唯一标识(如雪花ID)
* @return 不超过40位的请求ID字符串
*/
private String buildRequestId(String id) {
String appCode = sqbBiz.getSqbConfig().getAppCode();
if (appCode == null) appCode = "";
String raw = appCode + id;
return raw.length() > 40 ? raw.substring(0, 40) : raw;
}
/**
* 构建收钱吧订单标题,不超过32位。
*
* @param name 商品名称
* @return 不超过32位的标题字符串
*/
private String buildTitle(String name) {
if (name == null || name.isEmpty()) return "商品支付";
return name.length() > 32 ? name.substring(0, 32) : name;
}
private void syncOrderStatus(String orderId, int status) {
GoblinStoreOrderVo storeOrderVo = goblinRedisUtils.getGoblinOrder(orderId);
......
package com.liquidnet.service.order.utils;
import com.liquidnet.common.cache.redis.util.RedisUtil;
import com.liquidnet.commons.lang.util.CollectionUtil;
import com.liquidnet.service.base.constant.RedisKeyExpireConst;
import com.liquidnet.service.goblin.constant.GoblinRedisConst;
import com.liquidnet.service.goblin.dto.vo.GoblinSqbOrderVo;
import com.liquidnet.service.goblin.dto.vo.GoblinSqbPerfGoodsVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* 收钱吧相关 Redis 操作封装
*/
@Slf4j
@Component
public class GoblinSqbRedisUtils {
@Autowired
private RedisUtil redisUtil;
/* ---------------------------------------- 订单操作(TTL 2h) ---------------------------------------- */
public void setSqbOrder(String orderId, GoblinSqbOrderVo vo) {
redisUtil.set(GoblinRedisConst.SQB_ORDER.concat(orderId), vo, RedisKeyExpireConst.SQB_ORDER_EXPIRE);
}
public GoblinSqbOrderVo getSqbOrder(String orderId) {
return (GoblinSqbOrderVo) redisUtil.get(GoblinRedisConst.SQB_ORDER.concat(orderId));
}
public void delSqbOrder(String orderId) {
redisUtil.del(GoblinRedisConst.SQB_ORDER.concat(orderId));
}
/* ---------------------------------------- 演出关联商品缓存(TTL 5min) ---------------------------------------- */
public void setPerfGoods(String performancesId, List<GoblinSqbPerfGoodsVo> list) {
redisUtil.set(GoblinRedisConst.SQB_PERFORMANCE_GOODS.concat(performancesId), list, RedisKeyExpireConst.SQB_PERFORMANCE_GOODS_EXPIRE);
}
public List<GoblinSqbPerfGoodsVo> getPerfGoods(String performancesId) {
return (List<GoblinSqbPerfGoodsVo>) redisUtil.get(GoblinRedisConst.SQB_PERFORMANCE_GOODS.concat(performancesId));
}
public void delPerfGoods(String performancesId) {
redisUtil.del(GoblinRedisConst.SQB_PERFORMANCE_GOODS.concat(performancesId));
}
/* ---------------------------------------- 下单防重锁(TTL 10s) ---------------------------------------- */
/**
* 尝试获取下单防重锁
*
* @param userId 用户ID
* @param skuId SKU ID
* @return true 获取成功,false 已被锁定
*/
public boolean tryOrderLock(String userId, String skuId) {
String key = GoblinRedisConst.SQB_ORDER_LOCK.concat(userId).concat(":").concat(skuId);
return redisUtil.lock(key, 1, RedisKeyExpireConst.SQB_ORDER_LOCK_EXPIRE);
}
/**
* 释放下单防重锁
*
* @param userId 用户ID
* @param skuId SKU ID
*/
public void releaseOrderLock(String userId, String skuId) {
String key = GoblinRedisConst.SQB_ORDER_LOCK.concat(userId).concat(":").concat(skuId);
redisUtil.uLock(key);
}
/**
* 添加用户 收钱吧订单列表
* @param userId
* @param orderId
*/
public void addSqbOrderList(String userId, String orderId) {
String redisKey = GoblinRedisConst.SQB_GOBLIN_ORDER_LIST.concat(userId);
List<String> list = getSqbOrderList(userId);
if (list.size() >= 40) {
list.remove(0);
list.add(orderId);
} else {
list.add(orderId);
}
redisUtil.set(redisKey, list);
}
/**
* 获取 收钱吧订单id列表
* @param uid
* @return
*/
public List<String> getSqbOrderList(String uid) {
String redisKey = GoblinRedisConst.SQB_GOBLIN_ORDER_LIST.concat(uid);
Object obj = redisUtil.get(redisKey);
if (obj == null) {
return CollectionUtil.arrayListString();
} else {
return (List<String>) obj;
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment