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

Commit 926390cc authored by wangyifan's avatar wangyifan

收钱吧最新接口对接

parent a75fcf55
package com.liquidnet.service.goblin.param.shouqianba.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")
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")
private String sn;
@ApiModelProperty(required = true, value = "订单密码")
private String signature;
}
}
...@@ -12,6 +12,9 @@ public class CashierQueryRequest { ...@@ -12,6 +12,9 @@ public class CashierQueryRequest {
@ApiModelProperty(required = true, value = "应用id", example = "202507xxxxxxx") @ApiModelProperty(required = true, value = "应用id", example = "202507xxxxxxx")
private String appid; private String appid;
@ApiModelProperty(required = true, value = "商户信息")
private CommonRequest.Seller seller;
@ApiModelProperty(required = true, value = "支付模式代码", example = "4") @ApiModelProperty(required = true, value = "支付模式代码", example = "4")
private Integer paymentMode; private Integer paymentMode;
...@@ -19,41 +22,25 @@ public class CashierQueryRequest { ...@@ -19,41 +22,25 @@ public class CashierQueryRequest {
private PaymentEnv paymentEnv; private PaymentEnv paymentEnv;
@ApiModelProperty(required = false, value = "付款人信息") @ApiModelProperty(required = false, value = "付款人信息")
private Payer payer; private CommonRequest.Payer payer;
@ApiModelProperty(required = true, value = "收单信息") @ApiModelProperty(required = true, value = "收单信息")
private AcquiringInfo acquiringInfo; private CommonRequest.Acquiring acquiringInfo;
@Data @Data
@ApiModel(value = "支付环境信息") @ApiModel(value = "支付环境信息")
public static class PaymentEnv { public static class PaymentEnv {
@ApiModelProperty(required = false, value = "ip地址") @ApiModelProperty(required = false, value = "ip地址 最大40位")
private String ip; private String ip;
@ApiModelProperty(required = true, value = "支付客户端", example = "wechat") @ApiModelProperty(required = true, value = "支付客户端 最大32位", example = "wechat")
private String client; private String client;
@ApiModelProperty(required = false, value = "设备号") @ApiModelProperty(required = false, value = "设备号 最大64位")
private String device; private String device;
@ApiModelProperty(required = false, value = "版本号", example = "1.4") @ApiModelProperty(required = false, value = "版本号", example = "1.4")
private String version; private String version;
} }
@Data
@ApiModel(value = "付款人信息")
public static class Payer {
@ApiModelProperty(required = true, value = "付款人Id")
private String userId;
}
@Data
@ApiModel(value = "收单信息")
public static class AcquiringInfo {
@ApiModelProperty(required = true, value = "收单号")
private String acquiringSn;
@ApiModelProperty(required = true, value = "收单签名")
private String signature;
}
} }
package com.liquidnet.service.goblin.param.shouqianba.request;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class CommonRequest {
@Data
@ApiModel(value = "商城信息")
public static class Mall{
@ApiModelProperty(required = true, value = "商城ID")
private String mallSn;
@ApiModelProperty(required = true, value = "商城密码")
private String signature;
}
@Data
@ApiModel(value = "卖家信息/商户信息")
public static class Seller {
@ApiModelProperty(required = true, value = "商户ID")
private String merchantId;
@ApiModelProperty(required = true, value = "商户userID")
private String merchantUserId;
@ApiModelProperty(required = true, value = "角色 固定值(super_admin)")
private String role;
}
@Data
@ApiModel("买家信息")
public static class Buyer{
@ApiModelProperty(required = true, value = "买家ID(用户唯一标识)")
private String buyerId;
}
@Data
@ApiModel("付款人信息")
public static class Payer{
@ApiModelProperty(required = true, value = "付款人ID")
private String userId;
}
@ApiModel(value = "收单信息")
@Data
public static class Acquiring{
@ApiModelProperty(value = "收单号")
private String acquiringSn;
@ApiModelProperty(value = "收单密钥")
private String signature;
}
}
...@@ -15,7 +15,7 @@ public class CouponQueryRequest { ...@@ -15,7 +15,7 @@ public class CouponQueryRequest {
private OrderInfo orderID; private OrderInfo orderID;
@ApiModelProperty(required = true, value = "卖家信息", example = "4") @ApiModelProperty(required = true, value = "卖家信息", example = "4")
private Seller seller; private CommonRequest.Seller seller;
@Data @Data
@ApiModel(value = "订单信息") @ApiModel(value = "订单信息")
...@@ -28,16 +28,5 @@ public class CouponQueryRequest { ...@@ -28,16 +28,5 @@ public class CouponQueryRequest {
} }
@Data
@ApiModel(value = "卖家信息")
public static class Seller {
@ApiModelProperty(required = true, value = "商户ID")
private String merchantId;
@ApiModelProperty(required = true, value = "商户userID")
private String merchantUserId;
@ApiModelProperty(required = true, value = "角色")
private String role;
}
} }
...@@ -15,7 +15,7 @@ public class CouponRefundRequest { ...@@ -15,7 +15,7 @@ public class CouponRefundRequest {
private String appid; private String appid;
@ApiModelProperty(required = true, value = "卖家信息") @ApiModelProperty(required = true, value = "卖家信息")
private SellerInfo seller; private CommonRequest.Seller seller;
@ApiModelProperty(required = true, value = "订单信息") @ApiModelProperty(required = true, value = "订单信息")
private OrderInfo orderID; private OrderInfo orderID;
...@@ -29,23 +29,6 @@ public class CouponRefundRequest { ...@@ -29,23 +29,6 @@ public class CouponRefundRequest {
@ApiModelProperty(required = true, value = "退款来源(固定值:EXTERN)") @ApiModelProperty(required = true, value = "退款来源(固定值:EXTERN)")
private String requestSource; private String requestSource;
@ApiModelProperty(required = false, value = "拓展参数(自定义信息)")
private Map<String, Object> bizExtended;
@Data
@ApiModel(value = "卖家信息")
public static class SellerInfo {
@ApiModelProperty(required = true, value = "商户Id(固定值)")
private String merchantId;
@ApiModelProperty(required = true, value = "商户userId(固定值)")
private String merchantUserId;
@ApiModelProperty(required = true, value = "角色(固定值:super_admin)")
private String role;
}
@Data @Data
@ApiModel(value = "订单信息") @ApiModel(value = "订单信息")
public static class OrderInfo { public static class OrderInfo {
......
...@@ -14,11 +14,14 @@ public class CreateWechatPrepayOrderRequest { ...@@ -14,11 +14,14 @@ public class CreateWechatPrepayOrderRequest {
@ApiModelProperty(required = true, value = "应用id", example = "202507xxxxxxx") @ApiModelProperty(required = true, value = "应用id", example = "202507xxxxxxx")
private String appid; private String appid;
@ApiModelProperty(required = true, value = "商户信息")
private CommonRequest.Seller seller;
@ApiModelProperty(required = true, value = "收单号") @ApiModelProperty(required = true, value = "收单号")
private String acquiringSn; private String acquiringSn;
@ApiModelProperty(required = true, value = "收单签名") @ApiModelProperty(required = true, value = "收单签名")
private Object signature; private String signature;
@ApiModelProperty(required = true, value = "支付工具") @ApiModelProperty(required = true, value = "支付工具")
private List<UsingPayTool> usingPayTools; private List<UsingPayTool> usingPayTools;
......
...@@ -24,42 +24,21 @@ public class OrderCreateRequest implements Serializable { ...@@ -24,42 +24,21 @@ public class OrderCreateRequest implements Serializable {
private String appid; private String appid;
@ApiModelProperty(required = true, value = "商城信息") @ApiModelProperty(required = true, value = "商城信息")
private MallInfo mallID; private CommonRequest.Mall mallID;
@ApiModelProperty(required = true, value = "商户信息")
private CommonRequest.Seller seller;
@ApiModelProperty(required = true, value = "结算项ID") @ApiModelProperty(required = true, value = "结算项ID")
private String checkoutItemsId; private String checkoutItemsId;
@ApiModelProperty(required = true, value = "买家信息") @ApiModelProperty(required = true, value = "买家信息")
private Buyer buyer; private CommonRequest.Buyer buyer;
@ApiModelProperty(required = true, value = "请求ID") @ApiModelProperty(required = true, value = "请求ID 不超过40位")
private String requestId; private String requestId;
@ApiModelProperty(required = true, value = "场景信息") @ApiModelProperty(required = true, value = "标题 不超过32")
private List<Scene> scenes; private String subject;
@ApiModelProperty(required = true, value = "自定义场景信息")
private List<Scene> extBizScenes;
@EqualsAndHashCode(callSuper = true)
@Data
@ApiModel(value = "商城信息")
public static class MallInfo extends SettlementCreateRequest.MallInfo{
}
@EqualsAndHashCode(callSuper = true)
@Data
@ApiModel("买家信息")
public static class Buyer extends SettlementCreateRequest.Buyer{
}
@ApiModel(value = "场景信息")
public static class Scene{
@ApiModelProperty(value = "模块编号")
private String moduleSn;
@ApiModelProperty(value = "场景数据")
private String content;
}
} }
...@@ -23,10 +23,13 @@ public class SettlementCreateRequest implements Serializable { ...@@ -23,10 +23,13 @@ public class SettlementCreateRequest implements Serializable {
private String appid; private String appid;
@ApiModelProperty(required = true, value = "商城信息") @ApiModelProperty(required = true, value = "商城信息")
private MallInfo mallID; private CommonRequest.Mall mallID;
@ApiModelProperty(required = true, value = "商户信息")
private CommonRequest.Seller seller;
@ApiModelProperty(required = true, value = "买家信息") @ApiModelProperty(required = true, value = "买家信息")
private Buyer buyer; private CommonRequest.Buyer buyer;
@ApiModelProperty(required = false, value = "结算明细组(结算条目列表)") @ApiModelProperty(required = false, value = "结算明细组(结算条目列表)")
private List<CheckoutItem> checkoutItems; private List<CheckoutItem> checkoutItems;
...@@ -35,27 +38,6 @@ public class SettlementCreateRequest implements Serializable { ...@@ -35,27 +38,6 @@ public class SettlementCreateRequest implements Serializable {
private Long amount; private Long amount;
@Data
@ApiModel(value = "商城信息")
public static class MallInfo{
@ApiModelProperty(required = true, value = "商城ID")
private String mallSn;
@ApiModelProperty(required = true, value = "商城密码")
private String signature;
}
@Data
@ApiModel("买家信息")
public static class Buyer{
@ApiModelProperty(required = true, value = "买家ID(用户唯一标识)")
private String buyerId;
}
@Data @Data
@ApiModel(value = "结算明细条目") @ApiModel(value = "结算明细条目")
public static class CheckoutItem{ public static class CheckoutItem{
...@@ -73,7 +55,7 @@ public class SettlementCreateRequest implements Serializable { ...@@ -73,7 +55,7 @@ public class SettlementCreateRequest implements Serializable {
private String quantity; private String quantity;
@ApiModelProperty(required = true, value = "商品类型(0 正常商品 1 自定义商品)") @ApiModelProperty(required = true, value = "商品类型(0 正常商品 1 自定义商品)")
private String type; private Byte type;
@ApiModelProperty(required = true, value = "商品标题") @ApiModelProperty(required = true, value = "商品标题")
private String title; private String title;
......
package com.liquidnet.service.goblin.param.shouqianba.response;
import com.liquidnet.service.goblin.param.shouqianba.response.data.AcquiringCreateData;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "创建收单响应参数")
@Data
public class AcquiringCreateResponse extends BaseResponse<AcquiringCreateData> {
}
package com.liquidnet.service.goblin.param.shouqianba.response.data;
import com.liquidnet.service.goblin.param.shouqianba.request.CommonRequest;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
@ApiModel(value = "创建收单Data")
public class AcquiringCreateData extends CommonRequest.Acquiring {
}
package com.liquidnet.service.goblin.param.shouqianba.response.data; package com.liquidnet.service.goblin.param.shouqianba.response.data;
import com.liquidnet.service.goblin.param.shouqianba.request.CommonRequest;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
...@@ -16,16 +17,8 @@ public class OrderCreateData { ...@@ -16,16 +17,8 @@ public class OrderCreateData {
private String orderSignature; private String orderSignature;
@ApiModelProperty(value = "收单信息)") @ApiModelProperty(value = "收单信息)")
private Acquiring acquiring; private CommonRequest.Acquiring acquiring;
@ApiModel(value = "收单信息")
@Data
public static class Acquiring{
@ApiModelProperty(value = "收单号)")
private String acquiringSn;
@ApiModelProperty(value = "收单号)")
private String signature;
}
} }
package com.liquidnet.service.goblin.service; package com.liquidnet.service.goblin.service;
import com.liquidnet.service.goblin.param.shouqianba.request.CashierQueryRequest; import com.liquidnet.service.goblin.param.shouqianba.request.*;
import com.liquidnet.service.goblin.param.shouqianba.request.OrderCreateRequest; import com.liquidnet.service.goblin.param.shouqianba.response.data.*;
import com.liquidnet.service.goblin.param.shouqianba.request.SettlementCreateRequest;
import com.liquidnet.service.goblin.param.shouqianba.response.data.CashierQueryData;
import com.liquidnet.service.goblin.param.shouqianba.response.data.OrderCreateData;
import com.liquidnet.service.goblin.param.shouqianba.response.data.SettlementCreateData;
/** /**
* 收钱吧对接接口定义 * 收钱吧对接接口定义
...@@ -33,10 +29,45 @@ public interface IGoblinShouQianBaService { ...@@ -33,10 +29,45 @@ public interface IGoblinShouQianBaService {
*/ */
OrderCreateData createOrder(OrderCreateRequest request); OrderCreateData createOrder(OrderCreateRequest request);
/**
* 创建收单
* 如果上一步创建收单失败 可以使用这个接口重新创建收单
* @return
*/
AcquiringCreateData createAcquiring(AcquiringCreateRequest request);
/** /**
* 查询收银台 * 查询收银台
* @param request * @param request
* @return * @return
*/ */
CashierQueryData queryCashier(CashierQueryRequest request); CashierQueryData queryCashier(CashierQueryRequest request);
/**
* 创建微信预支付订单
* @param request
* @return
*/
CreateWechatPrepayOrderData createWechatPrepayOrder(CreateWechatPrepayOrderRequest request);
/**
* 查询券码
* @param request
* @return
*/
CouponQueryData queryCoupon(CouponQueryRequest request);
/**
* 券码状态同步
* @param request
* @return
*/
boolean syncCouponStatus(CouponStatusSyncRequest request);
/**
* 券退款
* @param request
* @return
*/
CouponRefundData refundCoupon(CouponRefundRequest request);
} }
...@@ -4,20 +4,22 @@ import com.fasterxml.jackson.core.type.TypeReference; ...@@ -4,20 +4,22 @@ import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.liquidnet.commons.lang.util.HttpUtil; import com.liquidnet.commons.lang.util.HttpUtil;
import com.liquidnet.commons.lang.util.MD5Utils; import com.liquidnet.commons.lang.util.MD5Utils;
import com.liquidnet.service.goblin.param.shouqianba.request.CashierQueryRequest; import com.liquidnet.service.goblin.param.shouqianba.request.*;
import com.liquidnet.service.goblin.param.shouqianba.request.OrderCreateRequest;
import com.liquidnet.service.goblin.param.shouqianba.request.SettlementCreateRequest;
import com.liquidnet.service.goblin.param.shouqianba.response.OrderCreateResponse; import com.liquidnet.service.goblin.param.shouqianba.response.OrderCreateResponse;
import com.liquidnet.service.goblin.param.shouqianba.response.SettlementCreateResponse; import com.liquidnet.service.goblin.param.shouqianba.response.SettlementCreateResponse;
import com.liquidnet.service.goblin.param.shouqianba.response.data.CashierQueryData; import com.liquidnet.service.goblin.param.shouqianba.response.data.*;
import com.liquidnet.service.goblin.param.shouqianba.response.data.OrderCreateData;
import com.liquidnet.service.goblin.param.shouqianba.response.data.SettlementCreateData;
import com.liquidnet.service.goblin.service.IGoblinShouQianBaService; import com.liquidnet.service.goblin.service.IGoblinShouQianBaService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap; import org.springframework.util.MultiValueMap;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.TreeMap; import java.util.TreeMap;
/** /**
...@@ -36,6 +38,8 @@ public class GoblinShouQianBaServiceImpl implements IGoblinShouQianBaService { ...@@ -36,6 +38,8 @@ public class GoblinShouQianBaServiceImpl implements IGoblinShouQianBaService {
public static final String BASE_API = "https://api.shouqianba.com"; public static final String BASE_API = "https://api.shouqianba.com";
private static final String APPID = "test_appid"; private static final String APPID = "test_appid";
private static final String APPKEY = "test_appkey"; private static final String APPKEY = "test_appkey";
// TODO: 收钱吧公钥,建议改为配置
private static final String SHOUQIANBA_PUB_KEY = "test_pub_key";
/** /**
* 创建结算明细 * 创建结算明细
...@@ -82,7 +86,7 @@ public class GoblinShouQianBaServiceImpl implements IGoblinShouQianBaService { ...@@ -82,7 +86,7 @@ public class GoblinShouQianBaServiceImpl implements IGoblinShouQianBaService {
@Override @Override
public OrderCreateData createOrder(OrderCreateRequest request) { public OrderCreateData createOrder(OrderCreateRequest request) {
final String url = BASE_API + "/optimus/core/mall/createPreOrder"; final String url = BASE_API + "/optimus/core/order/placeOrder";
log.info("[收钱吧] 创建订单, 请求URL: {}, 请求参数: {}", url, request); log.info("[收钱吧] 创建订单, 请求URL: {}, 请求参数: {}", url, request);
try { try {
...@@ -117,12 +121,37 @@ public class GoblinShouQianBaServiceImpl implements IGoblinShouQianBaService { ...@@ -117,12 +121,37 @@ public class GoblinShouQianBaServiceImpl implements IGoblinShouQianBaService {
} }
} }
@Override
public AcquiringCreateData createAcquiring(AcquiringCreateRequest request) {
return null;
}
@Override @Override
public CashierQueryData queryCashier(CashierQueryRequest request) { public CashierQueryData queryCashier(CashierQueryRequest request) {
return null; return null;
} }
@Override
public CreateWechatPrepayOrderData createWechatPrepayOrder(CreateWechatPrepayOrderRequest request) {
return null;
}
@Override
public CouponQueryData queryCoupon(CouponQueryRequest request) {
return null;
}
@Override
public boolean syncCouponStatus(CouponStatusSyncRequest request) {
return false;
}
@Override
public CouponRefundData refundCoupon(CouponRefundRequest request) {
return null;
}
private String getSign(String bodyJsonStr) { private String getSign(String bodyJsonStr) {
try { try {
// 签名算法: sign = MD5( CONCAT( body + appkey ) ) // 签名算法: sign = MD5( CONCAT( body + appkey ) )
...@@ -136,4 +165,40 @@ public class GoblinShouQianBaServiceImpl implements IGoblinShouQianBaService { ...@@ -136,4 +165,40 @@ public class GoblinShouQianBaServiceImpl implements IGoblinShouQianBaService {
return ""; return "";
} }
} }
/**
* 收钱吧回调推送验签
*
* @param signature 收钱吧推送来的签名 (signature)
* @param eventId 事件ID (eventId)
* @param timestamp 时间戳 (timestamp)
* @param nonce 随机数 (nonce)
* @param content 业务数据报文 (content)
* @return 验签是否通过
*/
public boolean verifySignature(String signature, String eventId, String timestamp, String nonce, String content) {
// 签名原串 = eventId + timestamp + nonce + content
String plaintext = eventId + timestamp + nonce + content;
return verifySignatureSHA256WithRSA(plaintext, signature, SHOUQIANBA_PUB_KEY);
}
public 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) {
try {
X509EncodedKeySpec bobPubKeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(pubKey));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(bobPubKeySpec);
byte[] signed = Base64.getDecoder().decode(inputSignature);
Signature signature = Signature.getInstance("SHA256WithRSA");
signature.initVerify(publicKey);
signature.update(plaintextByte);
return signature.verify(signed);
} catch (Exception e) {
log.error("[收钱吧] 验签异常, signature={}, pubKey={}", inputSignature, pubKey, e);
return false;
}
}
} }
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