拉卡拉分账调试修正
This commit is contained in:
parent
48c5ca7905
commit
0dd8de1de9
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
* Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
|
||||
* Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
|
||||
* Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
|
||||
* Vestibulum commodo. Ut rhoncus gravida arcu.
|
||||
*/
|
||||
|
||||
package com.suisung.mall.common.modules.lakala;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
@TableName("shop_message_template")
|
||||
@ApiModel(value = "拉卡拉分账商户", description = "拉卡拉分账商户表")
|
||||
public class LklLedgerMember implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long id;
|
||||
private String order_no;
|
||||
private String org_code;
|
||||
private String mer_inner_no;
|
||||
private String mer_cup_no;
|
||||
private String contact_mobile;
|
||||
private String split_lowest_ratio;
|
||||
private String split_entrust_file_name;
|
||||
private String split_entrust_file_path;
|
||||
private String split_range;
|
||||
private String sep_fund_source;
|
||||
private String ele_contract_no;
|
||||
private String split_launch_mode;
|
||||
private String settle_type;
|
||||
private String split_rule_source;
|
||||
private String ret_url;
|
||||
private String apply_id;
|
||||
private String audit_status;
|
||||
private String audit_status_text;
|
||||
private String remark;
|
||||
private String version;
|
||||
private Date created_at;
|
||||
private Date updated_at;
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
* Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
|
||||
* Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
|
||||
* Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
|
||||
* Vestibulum commodo. Ut rhoncus gravida arcu.
|
||||
*/
|
||||
|
||||
package com.suisung.mall.common.modules.lakala;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
@TableName("shop_message_template")
|
||||
@ApiModel(value = "拉卡拉分账商户与接收方绑定关系", description = "拉卡拉分账商户与接收方绑定表")
|
||||
public class LklLedgerMerReceiverBind implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long id;
|
||||
private String order_no;
|
||||
private String org_code;
|
||||
private String mer_inner_no;
|
||||
private String mer_cup_no;
|
||||
private String receiver_no;
|
||||
private String entrust_file_name;
|
||||
private String entrust_file_path;
|
||||
private String ret_url;
|
||||
private String apply_id;
|
||||
private String audit_status;
|
||||
private String audit_status_text;
|
||||
private String remark;
|
||||
private String version;
|
||||
private Date created_at;
|
||||
private Date updated_at;
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
* Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
|
||||
* Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
|
||||
* Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
|
||||
* Vestibulum commodo. Ut rhoncus gravida arcu.
|
||||
*/
|
||||
|
||||
package com.suisung.mall.common.modules.lakala;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
@TableName("shop_message_template")
|
||||
@ApiModel(value = "拉卡拉分账接收方", description = "拉卡拉分账接收方表")
|
||||
public class LklLedgerReceiver implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long id;
|
||||
private String order_no;
|
||||
private String org_code;
|
||||
private String rec_org_code;
|
||||
private String rec_org_name;
|
||||
private String receiver_name;
|
||||
private String contact_mobile;
|
||||
private String license_no;
|
||||
private String license_name;
|
||||
private String legal_person_name;
|
||||
private String legal_person_certificate_type;
|
||||
private String legal_person_certificate_no;
|
||||
private String acct_no;
|
||||
private String acct_name;
|
||||
private String acct_type_code;
|
||||
private String acct_certificate_type;
|
||||
private String acct_certificate_no;
|
||||
private String acct_open_bank_code;
|
||||
private String acct_open_bank_name;
|
||||
private String acct_clear_bank_code;
|
||||
private String attach_list;
|
||||
private String attach_type;
|
||||
private String attach_name;
|
||||
private String attach_store_path;
|
||||
private String settle_type;
|
||||
private String version;
|
||||
private Date created_at;
|
||||
private Date updated_at;
|
||||
}
|
||||
@ -16,6 +16,7 @@ import java.security.SecureRandom;
|
||||
import java.text.MessageFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@ -73,6 +74,35 @@ public final class StringUtils extends org.apache.commons.lang3.StringUtils {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成拉卡拉的订单号
|
||||
* 规则:14位年月日时(24小时制)分秒+8位的随机数(不重复)如:2021020112000012345678
|
||||
*
|
||||
* @param randomLen
|
||||
* @return
|
||||
*/
|
||||
public static String genLklOrderNo(int randomLen) {
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault());
|
||||
return format.format(new Date()) + genRandomNumber(randomLen);
|
||||
}
|
||||
|
||||
public static String genRandomNumber(int n) {
|
||||
if (n <= 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
// 生成首位,范围是 1 - 9,确保随机数是 n 位而不是 n - 1 位
|
||||
sb.append(ThreadLocalRandom.current().nextInt(1, 10));
|
||||
|
||||
for (int i = 1; i < n; i++) {
|
||||
// 生成后续位,范围是 0 - 9
|
||||
sb.append(ThreadLocalRandom.current().nextInt(0, 10));
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串格式化
|
||||
* <p>
|
||||
@ -323,6 +353,60 @@ public final class StringUtils extends org.apache.commons.lang3.StringUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 驼峰命名转下划线命名
|
||||
*
|
||||
* @param camelCase 驼峰命名的字符串
|
||||
* @return 下划线命名的字符串
|
||||
*/
|
||||
public static String camelToSnake(String camelCase) {
|
||||
// 处理输入为 null 或空字符串的情况
|
||||
if (camelCase == null || camelCase.isEmpty()) {
|
||||
return camelCase;
|
||||
}
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (int i = 0; i < camelCase.length(); i++) {
|
||||
char c = camelCase.charAt(i);
|
||||
// 如果是大写字母且不是字符串的第一个字符,则在前面添加下划线
|
||||
if (Character.isUpperCase(c) && i > 0) {
|
||||
result.append("_");
|
||||
}
|
||||
// 将字符转换为小写并添加到结果中
|
||||
result.append(Character.toLowerCase(c));
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 下划线命名转驼峰命名
|
||||
*
|
||||
* @param snakeCase 下划线命名的字符串
|
||||
* @return 驼峰命名的字符串
|
||||
*/
|
||||
public static String snakeToCamel(String snakeCase) {
|
||||
// 处理输入为 null 或空字符串的情况
|
||||
if (snakeCase == null || snakeCase.isEmpty()) {
|
||||
return snakeCase;
|
||||
}
|
||||
StringBuilder result = new StringBuilder();
|
||||
boolean capitalizeNext = false;
|
||||
for (char c : snakeCase.toCharArray()) {
|
||||
if (c == '_') {
|
||||
// 遇到下划线,标记下一个字符要大写
|
||||
capitalizeNext = true;
|
||||
} else {
|
||||
if (capitalizeNext) {
|
||||
// 将字符转换为大写并添加到结果中
|
||||
result.append(Character.toUpperCase(c));
|
||||
capitalizeNext = false;
|
||||
} else {
|
||||
result.append(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 生成的随机数类型
|
||||
|
||||
@ -58,13 +58,13 @@ public class IndexController extends BaseControllerImpl {
|
||||
@Autowired
|
||||
private PayUserResourceService payUserResourceService;
|
||||
@Autowired
|
||||
private LakalaService lakalaService;
|
||||
private LakalaPayService lakalaPayService;
|
||||
|
||||
@ApiOperation(value = "测试接口", notes = "测试接口")
|
||||
@RequestMapping(value = "/test/case", method = RequestMethod.POST)
|
||||
public JSONObject testCase(HttpServletRequest request, HttpServletResponse response,
|
||||
@RequestBody JSONObject objectJSON){
|
||||
return lakalaService.transPreOrder(request,response, (String) objectJSON.get("orderId"));
|
||||
return lakalaPayService.transPreOrder(request,response, (String) objectJSON.get("orderId"));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取支付密码", notes = "获取支付密码")
|
||||
|
||||
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
* Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
|
||||
* Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
|
||||
* Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
|
||||
* Vestibulum commodo. Ut rhoncus gravida arcu.
|
||||
*/
|
||||
|
||||
package com.suisung.mall.pay.controller.mobile;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.suisung.mall.common.api.CommonResult;
|
||||
import com.suisung.mall.common.service.impl.BaseControllerImpl;
|
||||
import com.suisung.mall.pay.service.LakalaPayService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@Api(tags = "拉卡拉相关接口 - 前端控制器")
|
||||
@RestController
|
||||
@RequestMapping("/mobile/pay/lakala")
|
||||
public class LakalaController extends BaseControllerImpl {
|
||||
|
||||
@Autowired
|
||||
private LakalaPayService lakalaPayService;
|
||||
|
||||
@ApiOperation(value = "商户分账业务开通申请", notes = "商户分账业务开通申请")
|
||||
@RequestMapping(value = "/ledger/applyLedgerMer", method = RequestMethod.POST)
|
||||
public CommonResult ledgerApplyLedgerMer(@RequestBody JSONObject paramsJSON) {
|
||||
return lakalaPayService.ledgerApplyLedgerMer(paramsJSON);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "商户分账业务开通申请异步回调回调", notes = "商户分账业务开通申请异步回调回调")
|
||||
@RequestMapping(value = "/ledger/applyLedgerMerNotify", method = RequestMethod.POST)
|
||||
public CommonResult ledgerApplyLedgerMerNotify(@RequestBody JSONObject paramsJSON) {
|
||||
return lakalaPayService.ledgerApplyLedgerMer(paramsJSON);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "分账接收方创建申请", notes = "分账接收方创建申请")
|
||||
@RequestMapping(value = "/ledger/applyLedgerReceiver", method = RequestMethod.POST)
|
||||
public CommonResult applyLedgerReceiver(@RequestBody JSONObject paramsJSON) {
|
||||
return lakalaPayService.ledgerApplyLedgerMer(paramsJSON);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "分账关系绑定申请", notes = "分账关系绑定申请")
|
||||
@RequestMapping(value = "/ledger/applyBind", method = RequestMethod.POST)
|
||||
public CommonResult applyBind(@RequestBody JSONObject paramsJSON) {
|
||||
return lakalaPayService.ledgerApplyLedgerMer(paramsJSON);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "分账关系绑定申请异步回调通知", notes = "分账关系绑定申请异步回调通知")
|
||||
@RequestMapping(value = "/ledger/applyBindNotify", method = RequestMethod.POST)
|
||||
public CommonResult applyBindNotify(@RequestBody JSONObject paramsJSON) {
|
||||
return lakalaPayService.ledgerApplyLedgerMer(paramsJSON);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
* Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
|
||||
* Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
|
||||
* Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
|
||||
* Vestibulum commodo. Ut rhoncus gravida arcu.
|
||||
*/
|
||||
|
||||
package com.suisung.mall.pay.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.suisung.mall.common.modules.lakala.LklLedgerMember;
|
||||
import com.suisung.mall.common.modules.pay.PayBaseRechargeLevel;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
|
||||
@Repository
|
||||
public interface LklLedgerMemberMapper extends BaseMapper<LklLedgerMember> {
|
||||
}
|
||||
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
* Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
|
||||
* Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
|
||||
* Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
|
||||
* Vestibulum commodo. Ut rhoncus gravida arcu.
|
||||
*/
|
||||
|
||||
package com.suisung.mall.pay.service;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.suisung.mall.common.api.CommonResult;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
public interface LakalaPayService {
|
||||
|
||||
Boolean initLKLSDK();
|
||||
|
||||
JSONObject transPreOrder(HttpServletRequest request, HttpServletResponse response, String orderId);
|
||||
|
||||
/**
|
||||
* 拉卡拉预下单
|
||||
* 参考:https://o.lakala.com/#/home/document/detail?id=110
|
||||
*
|
||||
* @param merchantNo 商户号
|
||||
* @param termNo 终端号
|
||||
* @param xcxAppId 小程序appid
|
||||
* @param openId openid
|
||||
* @param orderId 订单号
|
||||
* @param subject 订单标题
|
||||
* @param totalAmount 订单金额
|
||||
* @param notifyURL 回调地址
|
||||
* @param requestIP 请求ip
|
||||
* @param remark 备注
|
||||
* @return
|
||||
*/
|
||||
JSONObject transPreOrder(String merchantNo, String termNo, String xcxAppId, String openId, String orderId, String subject, String totalAmount, String notifyURL, String requestIP, String remark);
|
||||
|
||||
/**
|
||||
* 聚合扫码-交易查询
|
||||
*
|
||||
* @param storeId
|
||||
* @param orderId
|
||||
* @return
|
||||
*/
|
||||
JSONObject tradeQuery(Integer storeId, String orderId);
|
||||
|
||||
/**
|
||||
* 聚合扫码-退款交易
|
||||
* 主被扫交易发生后,因商家或消费者原因需要退款时,商家调用此接口退还消费者支付款项。
|
||||
* 注意: 1、调用退款接口时请保证商户/账户余额大于等于本次退款金额
|
||||
*
|
||||
* @param storeId
|
||||
* @param out_trade_no
|
||||
* @param origin_trade_no // 原拉卡拉交易流水号
|
||||
* @param refund_amount 单位分,整数数字型字符
|
||||
* @param refund_reason
|
||||
* @param requestIP
|
||||
* @return
|
||||
*/
|
||||
JSONObject refund(Integer storeId, String out_trade_no, String origin_trade_no, String refund_amount, String refund_reason, String requestIP);
|
||||
|
||||
/**
|
||||
* 账户余额查询
|
||||
* 参考:https://o.lakala.com/#/home/document/detail?id=364
|
||||
*
|
||||
* @param orgNo bmcp机构号
|
||||
* @param merchantNo 商户号 或 receiveNo 或 商户用户编号
|
||||
* @param payNo 账号(若该参数上送,则payType将无效)
|
||||
* @param payType 账号类型(01:收款账户,02:付款账户,03:分账商户账户,04:分账接收方账户,05:充值代付账户,06:结算代付账户)- 未上送则默认为01
|
||||
* @return
|
||||
*/
|
||||
JSONObject ewalletBalanceQuery(String orgNo, String merchantNo, String payNo, String payType);
|
||||
|
||||
/**
|
||||
* 文件上传
|
||||
* 参考:https://o.lakala.com/#/home/document/detail?id=90
|
||||
* @param orderNo
|
||||
* @param attType
|
||||
* @param attExtName
|
||||
* @param attContext
|
||||
* @return
|
||||
*/
|
||||
JSONObject uploadFile(String orderNo, String attType, String attExtName, String attContext);
|
||||
|
||||
|
||||
/**
|
||||
* 商户分账业务开通申请
|
||||
* 参考:https://o.lakala.com/#/home/document/detail?id=379
|
||||
* @param paramsJSON
|
||||
* @return
|
||||
*/
|
||||
CommonResult ledgerApplyLedgerMer(JSONObject paramsJSON);
|
||||
}
|
||||
@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
* Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
|
||||
* Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
|
||||
* Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
|
||||
* Vestibulum commodo. Ut rhoncus gravida arcu.
|
||||
*/
|
||||
|
||||
package com.suisung.mall.pay.service;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.suisung.mall.common.pojo.res.PayAccRespFieldsRes;
|
||||
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
|
||||
import org.springframework.data.util.Pair;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
public interface LakalaService {
|
||||
|
||||
Boolean initLKLSDK();
|
||||
|
||||
JSONObject transPreOrder(HttpServletRequest request, HttpServletResponse response, String orderId);
|
||||
|
||||
/**
|
||||
* 拉卡拉预下单
|
||||
*
|
||||
* @param merchantNo 商户号
|
||||
* @param termNo 终端号
|
||||
* @param xcxAppId 小程序appid
|
||||
* @param openId openid
|
||||
* @param orderId 订单号
|
||||
* @param subject 订单标题
|
||||
* @param totalAmount 订单金额
|
||||
* @param notifyURL 回调地址
|
||||
* @param requestIP 请求ip
|
||||
* @param remark 备注
|
||||
* @return
|
||||
*/
|
||||
JSONObject transPreOrder(String merchantNo, String termNo, String xcxAppId, String openId, String orderId, String subject, String totalAmount, String notifyURL, String requestIP, String remark);
|
||||
|
||||
/**
|
||||
* 拉卡拉查询商户号和终端号
|
||||
*
|
||||
* @param storeId 店铺 id
|
||||
* @return
|
||||
*/
|
||||
Pair<String, String> getLklMerchantNoAndTermNo(String storeId);
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
* Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
|
||||
* Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
|
||||
* Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
|
||||
* Vestibulum commodo. Ut rhoncus gravida arcu.
|
||||
*/
|
||||
|
||||
package com.suisung.mall.pay.service;
|
||||
|
||||
import com.suisung.mall.common.modules.lakala.LklLedgerMember;
|
||||
import com.suisung.mall.core.web.service.IBaseService;
|
||||
|
||||
public interface LklLedgerMemberService extends IBaseService<LklLedgerMember> {
|
||||
}
|
||||
@ -0,0 +1,447 @@
|
||||
/*
|
||||
* Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
* Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
|
||||
* Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
|
||||
* Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
|
||||
* Vestibulum commodo. Ut rhoncus gravida arcu.
|
||||
*/
|
||||
|
||||
package com.suisung.mall.pay.service.impl;
|
||||
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.ijpay.core.kit.IpKit;
|
||||
import com.lkl.laop.sdk.LKLSDK;
|
||||
import com.lkl.laop.sdk.exception.SDKException;
|
||||
import com.lkl.laop.sdk.request.*;
|
||||
import com.lkl.laop.sdk.request.model.V3LabsTradeLocationInfo;
|
||||
import com.lkl.laop.sdk.request.model.V3LabsTradePreorderWechatBus;
|
||||
import com.suisung.mall.common.api.CommonResult;
|
||||
import com.suisung.mall.common.exception.ApiException;
|
||||
import com.suisung.mall.common.feignService.ShopService;
|
||||
import com.suisung.mall.common.modules.lakala.LklLedgerMember;
|
||||
import com.suisung.mall.common.modules.store.ShopStoreBase;
|
||||
import com.suisung.mall.common.utils.I18nUtil;
|
||||
import com.suisung.mall.common.utils.StringUtils;
|
||||
import com.suisung.mall.pay.service.LakalaPayService;
|
||||
import com.suisung.mall.pay.service.LklLedgerMemberService;
|
||||
import com.suisung.mall.pay.utils.LakalaUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class LakalaPayServiceImpl implements LakalaPayService {
|
||||
private static final boolean init = false;
|
||||
//### 可选的两个参数,不同的店铺商家,可以数据库里配置不同的商户号和终端号
|
||||
@Value("${lakala.merchant_no}")
|
||||
public String merchantNo; // 拉卡拉分配的商户号
|
||||
@Value("${lakala.term_no}")
|
||||
public String termNo; // 拉卡拉分配的终端号码
|
||||
@Value("${lakala.server_url}")
|
||||
private String serverUrl; //服务地址
|
||||
@Value("${lakala.app_id}")
|
||||
private String appId; // 拉卡拉appId
|
||||
@Value("${lakala.serial_no}")
|
||||
private String serialNo; // 你的证书序列号
|
||||
@Value("${lakala.api_pri_key_path}")
|
||||
private String priKeyPath; //商户私钥信息地址
|
||||
@Value("${lakala.lkl_platform_cer_path}")
|
||||
private String lklCerPath; //拉卡拉支付平台证书地址
|
||||
@Value("${lakala.lkl_platform_cer_path}")
|
||||
private String lklNotifyCerPath; //拉卡拉支付平台证书地址2(用于拉卡拉通知验签)
|
||||
@Value("${lakala.org_code}")
|
||||
private String orgCode;
|
||||
@Value("${project.domain}")
|
||||
private String projectDomain;
|
||||
|
||||
|
||||
@Lazy
|
||||
@Autowired
|
||||
private ShopService shopService;
|
||||
|
||||
@Autowired
|
||||
private LklLedgerMemberService lklLedgerMemberService;
|
||||
|
||||
/**
|
||||
* 初始化 拉卡拉SDK
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Boolean initLKLSDK() {
|
||||
if (!init) {
|
||||
return LakalaUtil.initLKLSDK(appId, serialNo, priKeyPath, lklCerPath, lklNotifyCerPath, serverUrl);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public cn.hutool.json.JSONObject transPreOrder(HttpServletRequest request, HttpServletResponse response, String orderId) {
|
||||
// 1. 配置初始化
|
||||
initLKLSDK();
|
||||
|
||||
//2. 装配数据
|
||||
/*** 微信主扫场景示例 */
|
||||
V3LabsTransPreorderRequest v3LabsTransPreorderWechatReq = new V3LabsTransPreorderRequest();
|
||||
v3LabsTransPreorderWechatReq.setMerchantNo(merchantNo);
|
||||
v3LabsTransPreorderWechatReq.setTermNo(termNo);
|
||||
v3LabsTransPreorderWechatReq.setOutTradeNo(orderId);
|
||||
v3LabsTransPreorderWechatReq.setSubject("油麦菜5斤装特惠");
|
||||
v3LabsTransPreorderWechatReq.setAccountType("WECHAT");
|
||||
v3LabsTransPreorderWechatReq.setTransType("51");
|
||||
v3LabsTransPreorderWechatReq.setTotalAmount("1");
|
||||
v3LabsTransPreorderWechatReq.setNotifyUrl("http://mall.gpxscs.cn/notify");
|
||||
v3LabsTransPreorderWechatReq.setRemark("测试预下单备注");
|
||||
|
||||
//地址位置信息
|
||||
V3LabsTradeLocationInfo v3LabsTradePreorderLocationInfo1 = new V3LabsTradeLocationInfo(IpKit.getRealIp(request));
|
||||
v3LabsTransPreorderWechatReq.setLocationInfo(v3LabsTradePreorderLocationInfo1);
|
||||
|
||||
//微信主扫场景下acc_busi_fields域内容
|
||||
V3LabsTradePreorderWechatBus wechatBus = new V3LabsTradePreorderWechatBus();
|
||||
wechatBus.setSubAppid("wx5a73f844dac0da5c"); // 小程序appId
|
||||
wechatBus.setUserId("oDVKR7T0qxg6O8tqIL9SgY6LXqqQ"); // 微信 openId
|
||||
wechatBus.setDeviceInfo("WEB"); // 终端设备号(门店号或收银设备ID),注意:PC网页或JSAPI支付请传”WEB”
|
||||
v3LabsTransPreorderWechatReq.setAccBusiFields(wechatBus);
|
||||
|
||||
try {
|
||||
//3. 发送请求
|
||||
String responseStr = LKLSDK.httpPost(v3LabsTransPreorderWechatReq);
|
||||
|
||||
//4. 响应
|
||||
return JSONUtil.parseObj(responseStr);
|
||||
} catch (SDKException e) {
|
||||
LakalaPayServiceImpl.log.error("transPreOrder error", e);
|
||||
throw new ApiException(I18nUtil._("获取公众号绑定信息失败!"), e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 拉卡拉预下单
|
||||
* 参考:https://o.lakala.com/#/home/document/detail?id=110
|
||||
*
|
||||
* @param merchantNo 商户号
|
||||
* @param termNo 终端号
|
||||
* @param xcxAppId 小程序appid
|
||||
* @param openId openid
|
||||
* @param orderId 订单号
|
||||
* @param subject 订单标题
|
||||
* @param totalAmount 订单金额
|
||||
* @param notifyURL 回调地址
|
||||
* @param requestIP 请求ip
|
||||
* @param remark 备注
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public JSONObject transPreOrder(String merchantNo, String termNo, String xcxAppId, String openId, String orderId, String subject, String totalAmount, String notifyURL, String requestIP, String remark) {
|
||||
// 1. 配置初始化
|
||||
initLKLSDK();
|
||||
|
||||
if (StrUtil.isBlank(merchantNo)) {
|
||||
merchantNo = this.merchantNo;
|
||||
}
|
||||
if (StrUtil.isBlank(termNo)) {
|
||||
termNo = this.termNo;
|
||||
}
|
||||
|
||||
//2. 装配数据
|
||||
/*** 微信主扫场景示例 */
|
||||
V3LabsTransPreorderRequest v3LabsTransPreorderWechatReq = new V3LabsTransPreorderRequest();
|
||||
v3LabsTransPreorderWechatReq.setMerchantNo(merchantNo);
|
||||
v3LabsTransPreorderWechatReq.setTermNo(termNo);
|
||||
v3LabsTransPreorderWechatReq.setOutTradeNo(orderId);
|
||||
v3LabsTransPreorderWechatReq.setSubject(subject);
|
||||
//微信:WECHAT 支付宝:ALIPAY 银联:UQRCODEPAY 翼支付: BESTPAY 苏宁易付宝: SUNING 拉卡拉支付账户:LKLACC 网联小钱包:NUCSPAY 京东钱包:JD
|
||||
v3LabsTransPreorderWechatReq.setAccountType("WECHAT");
|
||||
// 41:NATIVE((ALIPAY,云闪付支持,京东白条分期)51:JSAPI(微信公众号支付,支付宝服务窗支付,银联JS支付,翼支付JS支付、拉卡拉钱包支付)71:微信小程序支付 61:APP支付(微信APP支付)
|
||||
v3LabsTransPreorderWechatReq.setTransType("51");
|
||||
v3LabsTransPreorderWechatReq.setTotalAmount(totalAmount);
|
||||
v3LabsTransPreorderWechatReq.setSettleType("1"); //“0”或者空,常规结算方式,如需接拉卡拉分账通需传“1”,商户未开通分账之前切记不用上送此参数。;
|
||||
v3LabsTransPreorderWechatReq.setNotifyUrl(notifyURL);
|
||||
v3LabsTransPreorderWechatReq.setRemark(remark);
|
||||
|
||||
//地址位置信息
|
||||
V3LabsTradeLocationInfo v3LabsTradePreorderLocationInfo = new V3LabsTradeLocationInfo(requestIP);
|
||||
v3LabsTransPreorderWechatReq.setLocationInfo(v3LabsTradePreorderLocationInfo);
|
||||
|
||||
//微信主扫场景下 acc_busi_fields 域内容
|
||||
V3LabsTradePreorderWechatBus wechatBus = new V3LabsTradePreorderWechatBus();
|
||||
wechatBus.setSubAppid(xcxAppId); // 小程序appId
|
||||
wechatBus.setUserId(openId); // 微信 openId
|
||||
wechatBus.setDeviceInfo("WEB"); // 终端设备号(门店号或收银设备ID),注意:PC网页或JSAPI支付请传”WEB”
|
||||
v3LabsTransPreorderWechatReq.setAccBusiFields(wechatBus);
|
||||
|
||||
try {
|
||||
log.info("拉卡拉预下单请求参数:{}", JSONUtil.toJsonStr(v3LabsTransPreorderWechatReq));
|
||||
|
||||
//3. 发送请求
|
||||
String responseStr = LKLSDK.httpPost(v3LabsTransPreorderWechatReq);
|
||||
log.info("拉卡拉预下单响应数据:{}", responseStr);
|
||||
if (StrUtil.isBlank(responseStr)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr);
|
||||
|
||||
// || !lakalaRespJSON.getStr("code").equals("BBS00000")
|
||||
|
||||
//4. 响应
|
||||
return lakalaRespJSON;
|
||||
} catch (SDKException e) {
|
||||
log.error("拉卡拉支付出错:", e);
|
||||
throw new ApiException(I18nUtil._("支付失败!"), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 聚合扫码-交易查询
|
||||
*
|
||||
* @param storeId
|
||||
* @param orderId
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public JSONObject tradeQuery(Integer storeId, String orderId) {
|
||||
if (ObjectUtil.isEmpty(storeId) || StrUtil.isBlank(orderId)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 1. 配置初始化
|
||||
initLKLSDK();
|
||||
|
||||
// 这里获取店铺的拉卡拉的商户号和终端号码
|
||||
ShopStoreBase shopStoreBase = shopService.getLklMerchantNoAndTermNo(storeId);
|
||||
if (shopStoreBase == null || StrUtil.isBlank(shopStoreBase.getLkl_merchant_no()) || StrUtil.isBlank(shopStoreBase.getLkl_term_no())) {
|
||||
log.error("缺少参数,拉卡拉交易查询失败!");
|
||||
return null;
|
||||
}
|
||||
|
||||
//2. 装配数据
|
||||
V3LabsQueryTradequeryRequest v3LabsQueryTradequeryRequest = new V3LabsQueryTradequeryRequest();
|
||||
v3LabsQueryTradequeryRequest.setMerchantNo(shopStoreBase.getLkl_merchant_no());
|
||||
v3LabsQueryTradequeryRequest.setTermNo(shopStoreBase.getLkl_term_no());
|
||||
v3LabsQueryTradequeryRequest.setOutTradeNo(orderId);
|
||||
|
||||
try {
|
||||
//3. 发送请求
|
||||
String responseStr = LKLSDK.httpPost(v3LabsQueryTradequeryRequest);
|
||||
|
||||
JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr);
|
||||
// || !lakalaRespJSON.getStr("code").equals("BBS00000")
|
||||
|
||||
return lakalaRespJSON;
|
||||
} catch (SDKException e) {
|
||||
log.error("交易查询失败:", e);
|
||||
throw new ApiException(I18nUtil._("交易查询失败!"), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 聚合扫码-退款交易
|
||||
* 主被扫交易发生后,因商家或消费者原因需要退款时,商家调用此接口退还消费者支付款项。
|
||||
* 注意: 1、调用退款接口时请保证商户/账户余额大于等于本次退款金额
|
||||
*
|
||||
* @param storeId
|
||||
* @param out_trade_no
|
||||
* @param origin_trade_no // 原拉卡拉交易流水号
|
||||
* @param refund_amount 单位分,整数数字型字符
|
||||
* @param refund_reason
|
||||
* @param requestIP
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public JSONObject refund(Integer storeId, String out_trade_no, String origin_trade_no, String refund_amount, String refund_reason, String requestIP) {
|
||||
if (ObjectUtil.isEmpty(storeId) || StrUtil.isBlank(out_trade_no) || StrUtil.isBlank(refund_amount) || StrUtil.isBlank(origin_trade_no) || StrUtil.isBlank(requestIP)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 1. 配置初始化
|
||||
initLKLSDK();
|
||||
|
||||
|
||||
// 这里获取店铺的拉卡拉的商户号和终端号码
|
||||
ShopStoreBase shopStoreBase = shopService.getLklMerchantNoAndTermNo(storeId);
|
||||
if (shopStoreBase == null || StrUtil.isBlank(shopStoreBase.getLkl_merchant_no()) || StrUtil.isBlank(shopStoreBase.getLkl_term_no())) {
|
||||
log.error("缺少参数,退款交易失败!");
|
||||
return null;
|
||||
}
|
||||
|
||||
//2. 装配数据
|
||||
V3LabsRelationIdmrefundRequest req = new V3LabsRelationIdmrefundRequest();
|
||||
req.setOutRefundOrderNo(out_trade_no);
|
||||
req.setMerchantNo(shopStoreBase.getLkl_merchant_no());
|
||||
req.setTermNo(shopStoreBase.getLkl_term_no());
|
||||
req.setRefundAmount(refund_amount);
|
||||
req.setRefundReason(refund_reason);
|
||||
req.setOriginTradeNo(origin_trade_no);
|
||||
|
||||
V3LabsTradeLocationInfo v3LabsTradeLocationInfo = new V3LabsTradeLocationInfo(requestIP, null, "");
|
||||
req.setLocationInfo(v3LabsTradeLocationInfo);
|
||||
|
||||
try {
|
||||
//3. 发送请求
|
||||
String responseStr = LKLSDK.httpPost(req);
|
||||
|
||||
JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr);
|
||||
|
||||
return lakalaRespJSON;
|
||||
} catch (SDKException e) {
|
||||
log.error("退款交易失败:", e);
|
||||
throw new ApiException(I18nUtil._("退款交易!"), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 账户余额查询
|
||||
* 参考:https://o.lakala.com/#/home/document/detail?id=364
|
||||
*
|
||||
* @param orgNo bmcp机构号 测试 “1”
|
||||
* @param merchantNo 商户号 或 receiveNo 或 商户用户编号
|
||||
* @param payNo 账号(若该参数上送,则payType将无效)
|
||||
* @param payType 账号类型(01:收款账户,02:付款账户,03:分账商户账户,04:分账接收方账户,05:充值代付账户,06:结算代付账户)- 未上送则默认为01
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public JSONObject ewalletBalanceQuery(String orgNo, String merchantNo, String payNo, String payType) {
|
||||
if (StrUtil.isBlank(orgNo) || StrUtil.isBlank(merchantNo) || (StrUtil.isBlank(payNo) && StrUtil.isBlank(payType))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 1. 配置初始化
|
||||
initLKLSDK();
|
||||
|
||||
|
||||
//2. 装配数据
|
||||
V2LaepIndustryEwalletBalanceQueryRequest req = new V2LaepIndustryEwalletBalanceQueryRequest();
|
||||
req.setOrgNo(orgNo);
|
||||
req.setMerchantNo(merchantNo);
|
||||
req.setPayNo(payNo);
|
||||
req.setPayType(payType);
|
||||
|
||||
try {
|
||||
//3. 发送请求
|
||||
String responseStr = LKLSDK.httpPost(req);
|
||||
|
||||
JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr);
|
||||
|
||||
return lakalaRespJSON;
|
||||
} catch (SDKException e) {
|
||||
log.error("账户余额查询失败:", e);
|
||||
throw new ApiException(I18nUtil._("账户余额查询!"), e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件上传
|
||||
* 参考:https://o.lakala.com/#/home/document/detail?id=90
|
||||
*
|
||||
* @param orderNo
|
||||
* @param attType
|
||||
* @param attExtName
|
||||
* @param attContext
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public JSONObject uploadFile(String orderNo, String attType, String attExtName, String attContext) {
|
||||
// 1. 配置初始化
|
||||
initLKLSDK();
|
||||
|
||||
//2. 装配数据
|
||||
V2MmsOpenApiUploadFileRequest req = new V2MmsOpenApiUploadFileRequest();
|
||||
req.setVersion("1.0");
|
||||
req.setOrderNo(orderNo);
|
||||
req.setOrgCode(orgCode);
|
||||
req.setAttType(attType);
|
||||
req.setAttExtName(attExtName);
|
||||
req.setAttContext(attContext);
|
||||
|
||||
try {
|
||||
//3. 发送请求
|
||||
String responseStr = LKLSDK.httpPost(req);
|
||||
|
||||
JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr);
|
||||
if (lakalaRespJSON == null || !lakalaRespJSON.getStr("retCode").equals("000000") || !lakalaRespJSON.getStr("cmdRetCode").equals("GLOBAL_SUCCESS")) {
|
||||
throw new ApiException(I18nUtil._(lakalaRespJSON.getStr("retMsg")));
|
||||
}
|
||||
|
||||
return (JSONObject) lakalaRespJSON.get("respData");
|
||||
} catch (SDKException e) {
|
||||
log.error("文件上传失败:", e);
|
||||
throw new ApiException(I18nUtil._("文件上传失败!"), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult ledgerApplyLedgerMer(JSONObject paramsJSON) {
|
||||
// 1. 配置初始化
|
||||
initLKLSDK();
|
||||
|
||||
//2. 装配数据
|
||||
V2MmsOpenApiLedgerApplyLedgerMerRequest req = new V2MmsOpenApiLedgerApplyLedgerMerRequest();
|
||||
req.setVersion("2.0");
|
||||
String orderNo = StringUtils.genLklOrderNo(8);
|
||||
req.setOrderNo(orderNo);
|
||||
req.setOrgCode(orgCode);
|
||||
req.setMerInnerNo(paramsJSON.getStr("merInnerNo"));
|
||||
req.setMerCupNo(paramsJSON.getStr("merCupNo"));
|
||||
req.setContactMobile(paramsJSON.getStr("contactMobile"));
|
||||
req.setSplitLowestRatio(new BigDecimal(paramsJSON.getStr("splitLowestRatio")));
|
||||
req.setSplitEntrustFileName(paramsJSON.getStr("splitEntrustFileName"));
|
||||
|
||||
|
||||
|
||||
// 文件上传到拉卡拉服务器
|
||||
JSONObject fileUploadResp = uploadFile(orderNo, "SPLIT_ENTRUST_FILE", "png", paramsJSON.getStr("splitEntrustFile"));
|
||||
if (fileUploadResp != null || StrUtil.isNotBlank(fileUploadResp.getStr("attFileId"))) {
|
||||
req.setSplitEntrustFilePath(fileUploadResp.getStr("attFileId"));
|
||||
}
|
||||
// req.setSplitEntrustFilePath("G1/M00/06/64/CrFdEmBQc-aAGc_XAAAiIbS3WIE960.png");
|
||||
|
||||
String retUrl = projectDomain + "/mobile/pay/lakala/ledger/applyLedgerMerNotify";
|
||||
req.setRetUrl(retUrl);
|
||||
|
||||
paramsJSON.set("orderNo", orderNo);
|
||||
paramsJSON.set("version", "2.0");
|
||||
paramsJSON.set("ret_url", retUrl);
|
||||
paramsJSON.set("org_code", orgCode);
|
||||
|
||||
try {
|
||||
|
||||
//3. 发送请求
|
||||
String responseStr = LKLSDK.httpPost(req);
|
||||
|
||||
JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr);
|
||||
if (lakalaRespJSON == null || !lakalaRespJSON.getStr("retCode").equals("000000")) {
|
||||
throw new ApiException(I18nUtil._(lakalaRespJSON.getStr("retMsg")));
|
||||
}
|
||||
|
||||
paramsJSON.set("apply_id", lakalaRespJSON.get("applyId"));
|
||||
|
||||
// 新增数据
|
||||
// 将 JSON 对象的键名转换为下划线命名
|
||||
LklLedgerMember lklLedgerMember = JSONUtil.toBean(StringUtils.camelToSnake(paramsJSON.toString()), LklLedgerMember.class);
|
||||
lklLedgerMemberService.edit(lklLedgerMember);
|
||||
|
||||
return CommonResult.success(null, "提交成功,待审核中!");
|
||||
} catch (SDKException e) {
|
||||
log.error("分账申请失败:", e);
|
||||
throw new ApiException(I18nUtil._("申请失败!"), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -1,198 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
* Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
|
||||
* Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
|
||||
* Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
|
||||
* Vestibulum commodo. Ut rhoncus gravida arcu.
|
||||
*/
|
||||
|
||||
package com.suisung.mall.pay.service.impl;
|
||||
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.ijpay.core.kit.IpKit;
|
||||
import com.lkl.laop.sdk.LKLSDK;
|
||||
import com.lkl.laop.sdk.exception.SDKException;
|
||||
import com.lkl.laop.sdk.request.V3LabsTransPreorderRequest;
|
||||
import com.lkl.laop.sdk.request.model.V3LabsTradeLocationInfo;
|
||||
import com.lkl.laop.sdk.request.model.V3LabsTradePreorderWechatBus;
|
||||
import com.suisung.mall.common.exception.ApiException;
|
||||
import com.suisung.mall.common.utils.I18nUtil;
|
||||
import com.suisung.mall.pay.service.LakalaService;
|
||||
import com.suisung.mall.pay.utils.LakalaUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.util.Pair;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class LakalaServiceImpl implements LakalaService {
|
||||
private static volatile boolean init = false;
|
||||
|
||||
@Value("${lakala.server_url}")
|
||||
private String serverUrl; //服务地址
|
||||
@Value("${lakala.app_id}")
|
||||
private String appId; // 拉卡拉appId
|
||||
@Value("${lakala.serial_no}")
|
||||
private String serialNo; // 你的证书序列号
|
||||
@Value("${lakala.api_pri_key_path}")
|
||||
private String priKeyPath; //商户私钥信息地址
|
||||
@Value("${lakala.lkl_platform_cer_path}")
|
||||
private String lklCerPath; //拉卡拉支付平台证书地址
|
||||
@Value("${lakala.lkl_platform_cer_path}")
|
||||
private String lklNotifyCerPath; //拉卡拉支付平台证书地址2(用于拉卡拉通知验签)
|
||||
|
||||
//### 可选的两个参数,不同的店铺商家,可以数据库里配置不同的商户号和终端号
|
||||
@Value("${lakala.merchant_no}")
|
||||
public String merchantNo; // 拉卡拉分配的商户号
|
||||
@Value("${lakala.term_no}")
|
||||
public String termNo; // 拉卡拉分配的终端号码
|
||||
|
||||
/**
|
||||
* 初始化 拉卡拉SDK
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Boolean initLKLSDK() {
|
||||
if (!init) {
|
||||
return LakalaUtil.initLKLSDK(appId, serialNo, priKeyPath, lklCerPath, lklNotifyCerPath, serverUrl);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public cn.hutool.json.JSONObject transPreOrder(HttpServletRequest request, HttpServletResponse response, String orderId) {
|
||||
// 1. 配置初始化
|
||||
initLKLSDK();
|
||||
|
||||
//2. 装配数据
|
||||
/*** 微信主扫场景示例 */
|
||||
V3LabsTransPreorderRequest v3LabsTransPreorderWechatReq = new V3LabsTransPreorderRequest();
|
||||
v3LabsTransPreorderWechatReq.setMerchantNo(merchantNo);
|
||||
v3LabsTransPreorderWechatReq.setTermNo(termNo);
|
||||
v3LabsTransPreorderWechatReq.setOutTradeNo(orderId);
|
||||
v3LabsTransPreorderWechatReq.setSubject("油麦菜5斤装特惠");
|
||||
v3LabsTransPreorderWechatReq.setAccountType("WECHAT");
|
||||
v3LabsTransPreorderWechatReq.setTransType("51");
|
||||
v3LabsTransPreorderWechatReq.setTotalAmount("1");
|
||||
v3LabsTransPreorderWechatReq.setNotifyUrl("http://mall.gpxscs.cn/notify");
|
||||
v3LabsTransPreorderWechatReq.setRemark("测试预下单备注");
|
||||
|
||||
//地址位置信息
|
||||
V3LabsTradeLocationInfo v3LabsTradePreorderLocationInfo1 = new V3LabsTradeLocationInfo(IpKit.getRealIp(request));
|
||||
v3LabsTransPreorderWechatReq.setLocationInfo(v3LabsTradePreorderLocationInfo1);
|
||||
|
||||
//微信主扫场景下acc_busi_fields域内容
|
||||
V3LabsTradePreorderWechatBus wechatBus = new V3LabsTradePreorderWechatBus();
|
||||
wechatBus.setSubAppid("wx5a73f844dac0da5c"); // 小程序appId
|
||||
wechatBus.setUserId("oDVKR7T0qxg6O8tqIL9SgY6LXqqQ"); // 微信 openId
|
||||
wechatBus.setDeviceInfo("WEB"); // 终端设备号(门店号或收银设备ID),注意:PC网页或JSAPI支付请传”WEB”
|
||||
v3LabsTransPreorderWechatReq.setAccBusiFields(wechatBus);
|
||||
|
||||
try {
|
||||
//3. 发送请求
|
||||
String responseStr = LKLSDK.httpPost(v3LabsTransPreorderWechatReq);
|
||||
|
||||
//4. 响应
|
||||
return JSONUtil.parseObj(responseStr);
|
||||
} catch (SDKException e) {
|
||||
LakalaServiceImpl.log.error("transPreOrder error", e);
|
||||
throw new ApiException(I18nUtil._("获取公众号绑定信息失败!"), e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 拉卡拉预下单
|
||||
*
|
||||
* @param merchantNo 商户号
|
||||
* @param termNo 终端号
|
||||
* @param xcxAppId 小程序appid
|
||||
* @param openId openid
|
||||
* @param orderId 订单号
|
||||
* @param subject 订单标题
|
||||
* @param totalAmount 订单金额
|
||||
* @param notifyURL 回调地址
|
||||
* @param requestIP 请求ip
|
||||
* @param remark 备注
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public JSONObject transPreOrder(String merchantNo, String termNo, String xcxAppId, String openId, String orderId, String subject, String totalAmount, String notifyURL, String requestIP, String remark) {
|
||||
// 1. 配置初始化
|
||||
LakalaUtil.initLKLSDK(appId, serialNo, priKeyPath, lklCerPath, lklNotifyCerPath, serverUrl);
|
||||
|
||||
if (StrUtil.isBlank(merchantNo)) {
|
||||
merchantNo = this.merchantNo;
|
||||
}
|
||||
if (StrUtil.isBlank(termNo)) {
|
||||
termNo = this.termNo;
|
||||
}
|
||||
|
||||
//2. 装配数据
|
||||
/*** 微信主扫场景示例 */
|
||||
V3LabsTransPreorderRequest v3LabsTransPreorderWechatReq = new V3LabsTransPreorderRequest();
|
||||
v3LabsTransPreorderWechatReq.setMerchantNo(merchantNo);
|
||||
v3LabsTransPreorderWechatReq.setTermNo(termNo);
|
||||
v3LabsTransPreorderWechatReq.setOutTradeNo(orderId);
|
||||
v3LabsTransPreorderWechatReq.setSubject(subject);
|
||||
//微信:WECHAT 支付宝:ALIPAY 银联:UQRCODEPAY 翼支付: BESTPAY 苏宁易付宝: SUNING 拉卡拉支付账户:LKLACC 网联小钱包:NUCSPAY 京东钱包:JD
|
||||
v3LabsTransPreorderWechatReq.setAccountType("WECHAT");
|
||||
// 41:NATIVE((ALIPAY,云闪付支持,京东白条分期)51:JSAPI(微信公众号支付,支付宝服务窗支付,银联JS支付,翼支付JS支付、拉卡拉钱包支付)71:微信小程序支付 61:APP支付(微信APP支付)
|
||||
v3LabsTransPreorderWechatReq.setTransType("51");
|
||||
v3LabsTransPreorderWechatReq.setTotalAmount(totalAmount);
|
||||
v3LabsTransPreorderWechatReq.setSettleType("1"); //“0”或者空,常规结算方式,如需接拉卡拉分账通需传“1”,商户未开通分账之前切记不用上送此参数。;
|
||||
v3LabsTransPreorderWechatReq.setNotifyUrl(notifyURL);
|
||||
v3LabsTransPreorderWechatReq.setRemark(remark);
|
||||
|
||||
//地址位置信息
|
||||
V3LabsTradeLocationInfo v3LabsTradePreorderLocationInfo = new V3LabsTradeLocationInfo(requestIP);
|
||||
v3LabsTransPreorderWechatReq.setLocationInfo(v3LabsTradePreorderLocationInfo);
|
||||
|
||||
//微信主扫场景下 acc_busi_fields 域内容
|
||||
V3LabsTradePreorderWechatBus wechatBus = new V3LabsTradePreorderWechatBus();
|
||||
wechatBus.setSubAppid(xcxAppId); // 小程序appId
|
||||
wechatBus.setUserId(openId); // 微信 openId
|
||||
wechatBus.setDeviceInfo("WEB"); // 终端设备号(门店号或收银设备ID),注意:PC网页或JSAPI支付请传”WEB”
|
||||
v3LabsTransPreorderWechatReq.setAccBusiFields(wechatBus);
|
||||
|
||||
try {
|
||||
log.info("拉卡拉预下单请求参数:{}", JSONUtil.toJsonStr(v3LabsTransPreorderWechatReq));
|
||||
|
||||
//3. 发送请求
|
||||
String responseStr = LKLSDK.httpPost(v3LabsTransPreorderWechatReq);
|
||||
log.info("拉卡拉预下单响应数据:{}", responseStr);
|
||||
if (StrUtil.isBlank(responseStr)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
JSONObject res = JSONUtil.parseObj(responseStr);
|
||||
|
||||
//4. 响应
|
||||
return res;
|
||||
} catch (SDKException e) {
|
||||
log.error("拉卡拉支付出错:", e);
|
||||
throw new ApiException(I18nUtil._("支付失败!"), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 拉卡拉查询商户号和终端号
|
||||
*
|
||||
* @param storeId 店铺 id
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Pair<String, String> getLklMerchantNoAndTermNo(String storeId) {
|
||||
return Pair.of("","");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
* Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
|
||||
* Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
|
||||
* Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
|
||||
* Vestibulum commodo. Ut rhoncus gravida arcu.
|
||||
*/
|
||||
|
||||
package com.suisung.mall.pay.service.impl;
|
||||
|
||||
import com.suisung.mall.common.modules.lakala.LklLedgerMember;
|
||||
import com.suisung.mall.common.modules.pay.PayConsumeTrade;
|
||||
import com.suisung.mall.core.web.service.impl.BaseServiceImpl;
|
||||
import com.suisung.mall.pay.mapper.LklLedgerMemberMapper;
|
||||
import com.suisung.mall.pay.mapper.PayConsumeTradeMapper;
|
||||
import com.suisung.mall.pay.service.LklLedgerMemberService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class LklLedgerMemberServiceImpl extends BaseServiceImpl<LklLedgerMemberMapper, LklLedgerMember> implements LklLedgerMemberService {
|
||||
}
|
||||
@ -116,7 +116,7 @@ public class PayUserPayServiceImpl extends BaseServiceImpl<PayUserPayMapper, Pay
|
||||
@Autowired
|
||||
private TransactionDefinition transactionDefinition;
|
||||
@Autowired
|
||||
private LakalaService lakalaService;
|
||||
private LakalaPayService lakalaPayService;
|
||||
|
||||
/**
|
||||
* 获取支付密码
|
||||
@ -257,7 +257,7 @@ public class PayUserPayServiceImpl extends BaseServiceImpl<PayUserPayMapper, Pay
|
||||
trade_row.setTrade_title(I18nUtil._("在线购物"));
|
||||
trade_row.setTrade_desc(I18nUtil._("在线购物"));
|
||||
}
|
||||
// 注:去微信支付(重要)
|
||||
// 注:多渠道支付(重要)
|
||||
executeMultiChannelPayment(request, response, trade_row, payTypeBean);
|
||||
return;
|
||||
} else {
|
||||
@ -589,7 +589,7 @@ public class PayUserPayServiceImpl extends BaseServiceImpl<PayUserPayMapper, Pay
|
||||
String total_fee = StrUtil.toString(NumberUtil.mul(NumberUtil.round(payConsumeTrade.getTrade_payment_amount(), 2), 100).intValue());
|
||||
// 微信支付配置值
|
||||
WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig();
|
||||
logger.info("微信支付配置值:{}", JSONUtil.toJsonStr(wxPayApiConfig));
|
||||
logger.debug("微信支付配置值:{}", JSONUtil.toJsonStr(wxPayApiConfig));
|
||||
|
||||
Map data = new HashMap();
|
||||
data.put("code", 1);
|
||||
@ -609,7 +609,7 @@ public class PayUserPayServiceImpl extends BaseServiceImpl<PayUserPayMapper, Pay
|
||||
String notifyUrl = domain + "/lkl_wxPay_notify_url";
|
||||
|
||||
// 拉卡拉预支付返回参数
|
||||
cn.hutool.json.JSONObject lakalaRespJSON = lakalaService.transPreOrder(shopStoreBase.getLkl_merchant_no(), shopStoreBase.getLkl_term_no(),
|
||||
cn.hutool.json.JSONObject lakalaRespJSON = lakalaPayService.transPreOrder(shopStoreBase.getLkl_merchant_no(), shopStoreBase.getLkl_term_no(),
|
||||
appId, openId, out_trade_no, subject, total_fee,
|
||||
notifyUrl,
|
||||
requestIP, trade_remark);
|
||||
@ -1266,7 +1266,7 @@ public class PayUserPayServiceImpl extends BaseServiceImpl<PayUserPayMapper, Pay
|
||||
public String lklNotifyUrl(HttpServletRequest request) {
|
||||
Map<String, String> params;
|
||||
try {
|
||||
lakalaService.initLKLSDK();
|
||||
lakalaPayService.initLKLSDK();
|
||||
|
||||
// spring-boot 2.x 直接调用读取请求体并验签方法,返回请求体
|
||||
String body = LKLSDK.notificationHandle(request);
|
||||
@ -1296,19 +1296,15 @@ public class PayUserPayServiceImpl extends BaseServiceImpl<PayUserPayMapper, Pay
|
||||
Integer payment_chain_id = 0;
|
||||
String orderSubject = "";
|
||||
Integer userId = 0;
|
||||
// 交易模式 2直接交易:商家直接收款; 1担保交易:平台收款,平台和商家结算。
|
||||
// if (!accountBaseConfigService.getTradeModePlantform()) {
|
||||
//不可以联合支付。
|
||||
|
||||
QueryWrapper<PayConsumeTrade> tradeQueryWrapper = new QueryWrapper<>();
|
||||
tradeQueryWrapper.eq("order_id", order_id);
|
||||
PayConsumeTrade trade_row_tmp = payConsumeTradeService.findOne(tradeQueryWrapper);
|
||||
|
||||
if (trade_row_tmp != null) {
|
||||
payment_store_id = trade_row_tmp.getStore_id();
|
||||
orderSubject = trade_row_tmp.getTrade_title();
|
||||
userId = trade_row_tmp.getBuyer_id();
|
||||
}
|
||||
//}
|
||||
|
||||
QueryWrapper<PayPaymentChannel> channelQueryWrapper = new QueryWrapper<>();
|
||||
channelQueryWrapper.eq("payment_channel_code", "lakala");
|
||||
@ -1351,7 +1347,6 @@ public class PayUserPayServiceImpl extends BaseServiceImpl<PayUserPayMapper, Pay
|
||||
}
|
||||
|
||||
return lklNotifyMsg(true, "执行成功");
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("通知处理发生异常:" + e.getMessage() + ", {}", e);
|
||||
return lklNotifyMsg(false, "通知处理发生异常!");
|
||||
|
||||
@ -109,14 +109,14 @@ logging:
|
||||
springfox: error
|
||||
logstash:
|
||||
host: @logstash.host@
|
||||
project:
|
||||
domain: @project.domain@
|
||||
#拉卡拉支付和分账
|
||||
lakala:
|
||||
#服务地址
|
||||
server_url: https://test.wsmsd.cn/sit
|
||||
#应用Id
|
||||
app_id: OP00000003
|
||||
#商户号
|
||||
merchant_no: 82229007392000A
|
||||
#商户证书序列号
|
||||
serial_no: 00dfba8194c41b84cf
|
||||
#商户证书
|
||||
@ -125,5 +125,9 @@ lakala:
|
||||
api_pri_key_path: payKey/lakala/dev/OP00000003_private_key.pem
|
||||
#拉卡拉平台证书
|
||||
lkl_platform_cer_path: payKey/lakala/dev/lkl_notify_cert_v2.cer
|
||||
# 机构代码
|
||||
org_code: 1
|
||||
#商户号
|
||||
merchant_no: 82229007392000A
|
||||
#终端号
|
||||
term_no: D9296400
|
||||
@ -109,14 +109,16 @@ logging:
|
||||
springfox: error
|
||||
logstash:
|
||||
host: @logstash.host@
|
||||
|
||||
project:
|
||||
domain: @project.domain@
|
||||
|
||||
#拉卡拉支付和分账
|
||||
lakala:
|
||||
#服务地址
|
||||
server_url: https://test.wsmsd.cn/sit
|
||||
#应用Id
|
||||
app_id: OP00000003
|
||||
#商户号
|
||||
merchant_no: 82229007392000A
|
||||
#商户证书序列号
|
||||
serial_no: 00dfba8194c41b84cf
|
||||
#商户证书
|
||||
@ -125,5 +127,9 @@ lakala:
|
||||
api_pri_key_path: payKey/lakala/dev/OP00000003_private_key.pem
|
||||
#拉卡拉平台证书
|
||||
lkl_platform_cer_path: payKey/lakala/dev/lkl_notify_cert_v2.cer
|
||||
# 机构代码
|
||||
org_code: 1
|
||||
#商户号
|
||||
merchant_no: 82229007392000A
|
||||
#终端号
|
||||
term_no: D9296400
|
||||
@ -111,6 +111,8 @@ logging:
|
||||
springfox: error
|
||||
logstash:
|
||||
host: @logstash.host@
|
||||
project:
|
||||
domain: @project.domain@
|
||||
#拉卡拉支付和分账
|
||||
lakala:
|
||||
# 服务地址
|
||||
@ -125,6 +127,8 @@ lakala:
|
||||
api_pri_key_path: payKey/lakala/prod/api_private_key.pem
|
||||
#拉卡拉平台证书
|
||||
lkl_platform_cer_path: payKey/lakala/prod/lkl_platform.cer
|
||||
# 机构代码
|
||||
org_code: 980688
|
||||
#商户号
|
||||
merchant_no: 8226330599900LN
|
||||
#终端号码,M0780629(B2B收银台) M0780798(专业化扫码)
|
||||
|
||||
@ -109,14 +109,14 @@ logging:
|
||||
springfox: error
|
||||
logstash:
|
||||
host: @logstash.host@
|
||||
project:
|
||||
domain: @project.domain@
|
||||
#拉卡拉支付和分账
|
||||
lakala:
|
||||
#服务地址
|
||||
server_url: https://test.wsmsd.cn/sit
|
||||
#应用Id
|
||||
app_id: OP00000003
|
||||
#商户号
|
||||
merchant_no: 82229007392000A
|
||||
#商户证书序列号
|
||||
serial_no: 00dfba8194c41b84cf
|
||||
#商户证书
|
||||
@ -125,5 +125,9 @@ lakala:
|
||||
api_pri_key_path: payKey/lakala/dev/OP00000003_private_key.pem
|
||||
#拉卡拉平台证书
|
||||
lkl_platform_cer_path: payKey/lakala/dev/lkl_notify_cert_v2.cer
|
||||
# 机构代码
|
||||
org_code: 1
|
||||
#商户号
|
||||
merchant_no: 82229007392000A
|
||||
#终端号
|
||||
term_no: D9296400
|
||||
@ -109,14 +109,14 @@ logging:
|
||||
springfox: error
|
||||
logstash:
|
||||
host: @logstash.host@
|
||||
project:
|
||||
domain: @project.domain@
|
||||
#拉卡拉支付和分账
|
||||
lakala:
|
||||
#服务地址
|
||||
server_url: https://test.wsmsd.cn/sit
|
||||
#应用Id
|
||||
app_id: OP00000003
|
||||
#商户号
|
||||
merchant_no: 82229007392000A
|
||||
#商户证书序列号
|
||||
serial_no: 00dfba8194c41b84cf
|
||||
#商户证书
|
||||
@ -125,5 +125,9 @@ lakala:
|
||||
api_pri_key_path: payKey/lakala/dev/OP00000003_private_key.pem
|
||||
#拉卡拉平台证书
|
||||
lkl_platform_cer_path: payKey/lakala/dev/lkl_notify_cert_v2.cer
|
||||
# 机构代码
|
||||
org_code: 1
|
||||
#商户号
|
||||
merchant_no: 82229007392000A
|
||||
#终端号
|
||||
term_no: D9296400
|
||||
8
pom.xml
8
pom.xml
@ -343,6 +343,8 @@
|
||||
<logstash.host>114.132.210.208</logstash.host>
|
||||
<!-- 图片上传配置 -->
|
||||
<upload.filepath>D:/wwwroot/mall/public/static</upload.filepath>
|
||||
<!--项目域名-->
|
||||
<project.domain>https://mall.gpxscs.cn</project.domain>
|
||||
</properties>
|
||||
<activation>
|
||||
<activeByDefault>false</activeByDefault>
|
||||
@ -390,6 +392,8 @@
|
||||
<logstash.host>114.132.210.208</logstash.host>
|
||||
<!-- 图片上传配置 -->
|
||||
<upload.filepath>D:/wwwroot/mall/public/static</upload.filepath>
|
||||
<!--项目域名-->
|
||||
<project.domain>https://mall.gpxscs.cn</project.domain>
|
||||
</properties>
|
||||
<activation>
|
||||
<activeByDefault>false</activeByDefault>
|
||||
@ -437,6 +441,8 @@
|
||||
<logstash.host>10.1.8.3</logstash.host>
|
||||
<!-- 图片上传配置 -->
|
||||
<upload.filepath>/opt/apps/mall/public/static</upload.filepath>
|
||||
<!--项目域名-->
|
||||
<project.domain>https://mall.gpxscs.cn</project.domain>
|
||||
</properties>
|
||||
<activation>
|
||||
<activeByDefault>true</activeByDefault>
|
||||
@ -484,6 +490,8 @@
|
||||
<logstash.host>172.16.0.11</logstash.host>
|
||||
<!-- 图片上传配置 -->
|
||||
<upload.filepath>/opt/apps/mall/public/static</upload.filepath>
|
||||
<!--项目域名-->
|
||||
<project.domain>https://mall.gpxscs.cn</project.domain>
|
||||
</properties>
|
||||
<activation>
|
||||
<activeByDefault>true</activeByDefault>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user