|
@@ -1,6 +1,7 @@
|
|
|
package com.payment.platform.module.payment.leshouying.controller.open;
|
|
package com.payment.platform.module.payment.leshouying.controller.open;
|
|
|
|
|
|
|
|
import cn.hutool.core.util.IdUtil;
|
|
import cn.hutool.core.util.IdUtil;
|
|
|
|
|
+import cn.hutool.core.util.StrUtil;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
|
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
|
|
import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
|
|
import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
|
|
@@ -15,6 +16,7 @@ import com.payment.platform.module.payment.leshouying.enums.LsyOrderStatus;
|
|
|
import com.payment.platform.module.payment.leshouying.mapper.LsyOrderMapper;
|
|
import com.payment.platform.module.payment.leshouying.mapper.LsyOrderMapper;
|
|
|
import com.payment.platform.module.payment.leshouying.service.*;
|
|
import com.payment.platform.module.payment.leshouying.service.*;
|
|
|
import com.payment.platform.module.payment.leshouying.util.LsyLogSanitizer;
|
|
import com.payment.platform.module.payment.leshouying.util.LsyLogSanitizer;
|
|
|
|
|
+import com.payment.platform.module.payment.leshouying.util.LsyStrings;
|
|
|
import jakarta.servlet.http.HttpServletRequest;
|
|
import jakarta.servlet.http.HttpServletRequest;
|
|
|
import jakarta.validation.Valid;
|
|
import jakarta.validation.Valid;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
import lombok.RequiredArgsConstructor;
|
|
@@ -69,14 +71,15 @@ public class LeshouyingOpenController {
|
|
|
|
|
|
|
|
LsyOrderEntity order = newOrder(dto.getOutTradeNo(), tenantId,
|
|
LsyOrderEntity order = newOrder(dto.getOutTradeNo(), tenantId,
|
|
|
apiKeyId(), "BARCODE", "000");
|
|
apiKeyId(), "BARCODE", "000");
|
|
|
- order.setEnterpriseId(dto.getEnterpriseId());
|
|
|
|
|
|
|
+ // 归一化:空白 ⇒ NULL。存成 "" 或 " " 的话,这一行永远查不回来
|
|
|
|
|
+ // (requireByTenant 找的是 IS NULL,见 LsyStrings)。
|
|
|
|
|
+ order.setEnterpriseId(LsyStrings.blankToNull(dto.getEnterpriseId()));
|
|
|
order.setTotalAmount(dto.getTotalAmount());
|
|
order.setTotalAmount(dto.getTotalAmount());
|
|
|
order.setOrderBody(dto.getOrderBody());
|
|
order.setOrderBody(dto.getOrderBody());
|
|
|
order.setAttach(dto.getAttach());
|
|
order.setAttach(dto.getAttach());
|
|
|
order.setNotifyUrl(dto.getNotifyUrl());
|
|
order.setNotifyUrl(dto.getNotifyUrl());
|
|
|
|
|
|
|
|
- LsyMerchantEntity merchant = merchantService.requireByEnterprise(
|
|
|
|
|
- tenantId, dto.getEnterpriseId());
|
|
|
|
|
|
|
+ LsyMerchantEntity merchant = requireMerchant(tenantId, dto.getEnterpriseId());
|
|
|
order.setMchNo(merchant.getMchNo());
|
|
order.setMchNo(merchant.getMchNo());
|
|
|
order.setShopNo(merchant.getShopNo());
|
|
order.setShopNo(merchant.getShopNo());
|
|
|
// ★ 落库必须在 mch_no/shopNo 装配之后:V1.8 的 pay_lsy_order.mch_no 是 NOT NULL 且无默认值
|
|
// ★ 落库必须在 mch_no/shopNo 装配之后:V1.8 的 pay_lsy_order.mch_no 是 NOT NULL 且无默认值
|
|
@@ -98,14 +101,14 @@ public class LeshouyingOpenController {
|
|
|
|
|
|
|
|
LsyOrderEntity order = newOrder(dto.getOutTradeNo(), tenantId,
|
|
LsyOrderEntity order = newOrder(dto.getOutTradeNo(), tenantId,
|
|
|
apiKeyId(), "QRCODE", null);
|
|
apiKeyId(), "QRCODE", null);
|
|
|
- order.setEnterpriseId(dto.getEnterpriseId());
|
|
|
|
|
|
|
+ // 归一化:空白 ⇒ NULL(同 barcodePay 的说明)
|
|
|
|
|
+ order.setEnterpriseId(LsyStrings.blankToNull(dto.getEnterpriseId()));
|
|
|
order.setTotalAmount(dto.getTotalAmount());
|
|
order.setTotalAmount(dto.getTotalAmount());
|
|
|
order.setOrderBody(dto.getOrderBody());
|
|
order.setOrderBody(dto.getOrderBody());
|
|
|
order.setAttach(dto.getAttach());
|
|
order.setAttach(dto.getAttach());
|
|
|
order.setNotifyUrl(dto.getNotifyUrl());
|
|
order.setNotifyUrl(dto.getNotifyUrl());
|
|
|
|
|
|
|
|
- LsyMerchantEntity merchant = merchantService.requireByEnterprise(
|
|
|
|
|
- tenantId, dto.getEnterpriseId());
|
|
|
|
|
|
|
+ LsyMerchantEntity merchant = requireMerchant(tenantId, dto.getEnterpriseId());
|
|
|
order.setMchNo(merchant.getMchNo());
|
|
order.setMchNo(merchant.getMchNo());
|
|
|
order.setShopNo(merchant.getShopNo());
|
|
order.setShopNo(merchant.getShopNo());
|
|
|
// ★ 落库必须在 mch_no/shopNo 装配之后:V1.8 的 pay_lsy_order.mch_no 是 NOT NULL 且无默认值
|
|
// ★ 落库必须在 mch_no/shopNo 装配之后:V1.8 的 pay_lsy_order.mch_no 是 NOT NULL 且无默认值
|
|
@@ -125,14 +128,14 @@ public class LeshouyingOpenController {
|
|
|
|
|
|
|
|
LsyOrderEntity order = newOrder(dto.getOutTradeNo(), tenantId,
|
|
LsyOrderEntity order = newOrder(dto.getOutTradeNo(), tenantId,
|
|
|
apiKeyId(), "H5", dto.getPayType());
|
|
apiKeyId(), "H5", dto.getPayType());
|
|
|
- order.setEnterpriseId(dto.getEnterpriseId());
|
|
|
|
|
|
|
+ // 归一化:空白 ⇒ NULL(同 barcodePay 的说明)
|
|
|
|
|
+ order.setEnterpriseId(LsyStrings.blankToNull(dto.getEnterpriseId()));
|
|
|
order.setTotalAmount(dto.getTotalAmount());
|
|
order.setTotalAmount(dto.getTotalAmount());
|
|
|
order.setOrderBody(dto.getOrderBody());
|
|
order.setOrderBody(dto.getOrderBody());
|
|
|
order.setAttach(dto.getAttach());
|
|
order.setAttach(dto.getAttach());
|
|
|
order.setNotifyUrl(dto.getNotifyUrl());
|
|
order.setNotifyUrl(dto.getNotifyUrl());
|
|
|
|
|
|
|
|
- LsyMerchantEntity merchant = merchantService.requireByEnterprise(
|
|
|
|
|
- tenantId, dto.getEnterpriseId());
|
|
|
|
|
|
|
+ LsyMerchantEntity merchant = requireMerchant(tenantId, dto.getEnterpriseId());
|
|
|
order.setMchNo(merchant.getMchNo());
|
|
order.setMchNo(merchant.getMchNo());
|
|
|
order.setShopNo(merchant.getShopNo());
|
|
order.setShopNo(merchant.getShopNo());
|
|
|
// ★ 落库必须在 mch_no/shopNo 装配之后:V1.8 的 pay_lsy_order.mch_no 是 NOT NULL 且无默认值
|
|
// ★ 落库必须在 mch_no/shopNo 装配之后:V1.8 的 pay_lsy_order.mch_no 是 NOT NULL 且无默认值
|
|
@@ -342,11 +345,34 @@ public class LeshouyingOpenController {
|
|
|
return v instanceof Long ? (Long) v : null;
|
|
return v instanceof Long ? (Long) v : null;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 三个下单方法共用的商户映射分流(2026-09-22 去企业化)。
|
|
|
|
|
+ *
|
|
|
|
|
+ * <p>{@code enterpriseId} 空白 ⇒ 租户级({@link LsyMerchantService#requireByTenant});
|
|
|
|
|
+ * 非空 ⇒ 企业级({@link LsyMerchantService#requireByEnterprise})。两条路径**并存**,
|
|
|
|
|
+ * 不是替代 —— 传了 {@code enterpriseId} 的老调用方一字不用改,走的还是原来那条。
|
|
|
|
|
+ *
|
|
|
|
|
+ * <p><b>判空用 {@code StrUtil.isBlank} 而不是 {@code == null}:</b>报文里给一个
|
|
|
|
|
+ * {@code "enterprise_id": ""} 或 {@code " "} 与不传这个键,在业务上是同一个意思
|
|
|
|
|
+ * (「不绑企业」)。若只判 null,空白串会落进企业级分支,
|
|
|
|
|
+ * 而 requireByEnterprise 转头就抛 400「enterprise_id 不能为空」——
|
|
|
|
|
+ * 同样是「不绑企业」的两种写法,一种能用一种报错。
|
|
|
|
|
+ *
|
|
|
|
|
+ * <p>★ 明确**不**做「先查租户级、查不到再退回企业级」的兜底链:
|
|
|
|
|
+ * 那会让一次漏配商户映射(本该 404 的配置错误)静默降级成「用了另一个企业的商户号收款」。
|
|
|
|
|
+ * 选哪条路由请求体里的一个字段唯一决定,不清楚就报错。
|
|
|
|
|
+ */
|
|
|
|
|
+ private LsyMerchantEntity requireMerchant(Long tenantId, String enterpriseId) {
|
|
|
|
|
+ return StrUtil.isBlank(enterpriseId)
|
|
|
|
|
+ ? merchantService.requireByTenant(tenantId)
|
|
|
|
|
+ : merchantService.requireByEnterprise(tenantId, enterpriseId);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 只**构造**订单实体,**不落库**。
|
|
* 只**构造**订单实体,**不落库**。
|
|
|
* ★ 落库由调用方在全部字段装配完毕后显式 {@code orderMapper.insert(order)} ——
|
|
* ★ 落库由调用方在全部字段装配完毕后显式 {@code orderMapper.insert(order)} ——
|
|
|
* 因为 {@code pay_lsy_order.mch_no} 是 {@code NOT NULL} 且无默认值(V1.8 建表语句),
|
|
* 因为 {@code pay_lsy_order.mch_no} 是 {@code NOT NULL} 且无默认值(V1.8 建表语句),
|
|
|
- * 而 mch_no 要先查商户(requireByEnterprise)才能拿到。
|
|
|
|
|
|
|
+ * 而 mch_no 要先查商户(见 {@link #requireMerchant})才能拿到。
|
|
|
*/
|
|
*/
|
|
|
private LsyOrderEntity newOrder(String outTradeNo, Long tenantId, Long apiKeyId,
|
|
private LsyOrderEntity newOrder(String outTradeNo, Long tenantId, Long apiKeyId,
|
|
|
String scene, String payType) {
|
|
String scene, String payType) {
|