Merge branch 'test' into prod

# Conflicts:
#	cash-api/account-server/src/main/java/com/czg/controller/admin/AuthorizationController.java
#	cash-api/order-server/src/main/java/com/czg/controller/DistributionPayController.java
#	cash-service/order-service/src/main/java/com/czg/service/order/service/impl/OrderInfoCustomServiceImpl.java
#	cash-service/order-service/src/main/java/com/czg/service/order/service/impl/PayServiceImpl.java
This commit is contained in:
2026-01-17 09:52:55 +08:00
209 changed files with 11116 additions and 3013 deletions

View File

@@ -50,9 +50,8 @@ public class FastJson2Config implements WebMvcConfigurer {
// 设置支持的媒体类型
List<MediaType> supportedMediaTypes = new ArrayList<>();
supportedMediaTypes.add(MediaType.APPLICATION_JSON);
supportedMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
converter.setSupportedMediaTypes(supportedMediaTypes);
// 将转换器添加到 Spring MVC 的消息转换器列表中
converters.add(0, converter);
converters.addFirst(converter);
}
}

View File

@@ -54,7 +54,7 @@ public class FilteredNacosRegistry extends NacosRegistry {
public void register(URL url) {
// 1. 获取原始注册的方法列表
String originalMethods = url.getParameter("methods");
log.info("【过滤提示】服务 {} 注册方法:{}", url.getServiceInterface(), originalMethods);
// log.info("【过滤提示】服务 {} 注册方法:{}", url.getServiceInterface(), originalMethods);
if (originalMethods != null && !originalMethods.isEmpty()) {
// 2. 过滤黑名单中的方法名
List<String> filteredMethods = Arrays.stream(originalMethods.split(","))
@@ -67,12 +67,12 @@ public class FilteredNacosRegistry extends NacosRegistry {
// 3. 处理过滤后的结果
if (filteredMethods.isEmpty()) {
// 若所有方法都被过滤,直接终止注册(可选:根据业务决定是否保留服务注册)
log.info("【过滤提示】服务 {} 所有方法均被过滤,终止注册", url.getServiceInterface());
// log.info("【过滤提示】服务 {} 所有方法均被过滤,终止注册", url.getServiceInterface());
return;
} else {
// 替换 URL 中的 methods 参数为过滤后的列表
url = url.addParameter("methods", String.join(",", filteredMethods));
log.info("【过滤提示】服务 {} 注册方法:{}", url.getServiceInterface(), filteredMethods);
// log.info("【过滤提示】服务 {} 注册方法:{}", url.getServiceInterface(), filteredMethods);
}
}

View File

@@ -21,12 +21,24 @@ public class RabbitConfig {
@Value("${spring.profiles.active}")
private String activeProfile;
@Bean
@Primary
public DirectExchange directExchange() {
return new DirectExchange(activeProfile + "-" + RabbitConstants.Exchange.CASH_EXCHANGE);
}
//------------------------------------------------------ 商家入驻
@Bean
public Queue entryManagerQueue() {
return new Queue(activeProfile + "-" + RabbitConstants.Queue.SHOP_ENTRY_MANAGER, true, false, false);
}
@Bean
public Binding entryManagerExchange(Queue entryManagerQueue, DirectExchange exchange) {
return BindingBuilder.bind(entryManagerQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.SHOP_ENTRY_MANAGER);
}
//------------------------------------------------------订单打印队列
@Bean
public Queue orderPrintQueue() {
@@ -36,6 +48,7 @@ public class RabbitConfig {
args.put("x-message-ttl", 180000);
return new Queue(activeProfile + "-" + RabbitConstants.Queue.ORDER_PRINT_QUEUE, true, false, false, args);
}
@Bean
public Binding bindingOrderPrintExchange(Queue orderPrintQueue, DirectExchange exchange) {
return BindingBuilder.bind(orderPrintQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.ORDER_PRINT_QUEUE);
@@ -51,6 +64,7 @@ public class RabbitConfig {
// args.put("x-message-ttl", 180000);
return new Queue(activeProfile + "-" + RabbitConstants.Queue.ORDER_MACHINE_PRINT_QUEUE, true, false, false);
}
@Bean
public Binding bindingOrderMachinePrintExchange(Queue orderMachinePrintQueue, DirectExchange exchange) {
return BindingBuilder.bind(orderMachinePrintQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.ORDER_MACHINE_PRINT_QUEUE);
@@ -61,6 +75,7 @@ public class RabbitConfig {
public Queue handoverPrintQueue() {
return new Queue(activeProfile + "-" + RabbitConstants.Queue.ORDER_HANDOVER_PRINT_QUEUE, true, false, false);
}
@Bean
public Binding bindingHandoverPrintExchange(Queue handoverPrintQueue, DirectExchange exchange) {
return BindingBuilder.bind(handoverPrintQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.ORDER_HANDOVER_PRINT_QUEUE);
@@ -69,11 +84,12 @@ public class RabbitConfig {
//------------------------------------------------------叫号 打票
@Bean
public Queue callTablePrintQueue() {
return new Queue(activeProfile + "-" + RabbitConstants.Queue.CALL_TABLE_PRINT_QUEUE, true, false, false);
return new Queue(activeProfile + "-" + RabbitConstants.Queue.CALL_TABLE_QUEUE, true, false, false);
}
@Bean
public Binding bindingCallTablePrintExchange(Queue callTablePrintQueue, DirectExchange exchange) {
return BindingBuilder.bind(callTablePrintQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.CALL_TABLE_PRINT_QUEUE);
return BindingBuilder.bind(callTablePrintQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.CALL_TABLE_QUEUE);
}
//------------------------------------------------------订单取消
@@ -81,9 +97,10 @@ public class RabbitConfig {
public Queue orderCancelQueue() {
return new Queue(activeProfile + "-" + RabbitConstants.Queue.ORDER_CANCEL_QUEUE, true);
}
@Bean
public Binding bindingOrderCancelExchange(Queue orderPrintQueue, DirectExchange exchange) {
return BindingBuilder.bind(orderPrintQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.ORDER_CANCEL_QUEUE);
public Binding bindingOrderCancelExchange(Queue orderCancelQueue, DirectExchange exchange) {
return BindingBuilder.bind(orderCancelQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.ORDER_CANCEL_QUEUE);
}
//------------------------------------------------------ 订单库存更新
@@ -91,6 +108,7 @@ public class RabbitConfig {
public Queue orderStockQueue() {
return new Queue(activeProfile + "-" + RabbitConstants.Queue.ORDER_STOCK_QUEUE, true);
}
@Bean
public Binding bindingOrderStockExchange(Queue orderStockQueue, DirectExchange exchange) {
return BindingBuilder.bind(orderStockQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.ORDER_STOCK_QUEUE);
@@ -102,6 +120,7 @@ public class RabbitConfig {
public Queue productInfoChangeQueue() {
return new Queue(activeProfile + "-" + RabbitConstants.Queue.PRODUCT_INFO_CHANGE_QUEUE, true);
}
@Bean
public Binding bindingProductInfoChange(Queue productInfoChangeQueue, DirectExchange exchange) {
return BindingBuilder.bind(productInfoChangeQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.PRODUCT_INFO_CHANGE_QUEUE);
@@ -112,6 +131,7 @@ public class RabbitConfig {
public Queue orderRefundQueue() {
return new Queue(activeProfile + "-" + RabbitConstants.Queue.ORDER_REFUND_QUEUE, true);
}
@Bean
public Binding bindingOrderRefundExchange(Queue orderRefundQueue, DirectExchange exchange) {
return BindingBuilder.bind(orderRefundQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.ORDER_REFUND_QUEUE);
@@ -119,6 +139,7 @@ public class RabbitConfig {
//------------------------------------------------------ 申请短信模板队列
/**
* 1,2,applySmsTemp 模版审核
* 1,2,sendMarkSms 发送营销短信
@@ -129,16 +150,18 @@ public class RabbitConfig {
public Queue applySmsTemplateQueue() {
return new Queue(activeProfile + "-" + RabbitConstants.Queue.APPLY_SMS_TEMPLATE_QUEUE, true);
}
@Bean
public Binding bindingApplySmsTemplateExchange(Queue applySmsTemplateQueue, DirectExchange exchange) {
return BindingBuilder.bind(applySmsTemplateQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.APPLY_SMS_TEMPLATE_QUEUE);
}
//------------------------------------------------------ 生日礼品短信队列
//------------------------------------------------------ 生日礼品短信队列
@Bean
public Queue birthdayGiftSmsQueue() {
return new Queue(activeProfile + "-" + RabbitConstants.Queue.BIRTHDAY_GIFT_SMS_QUEUE, true);
}
@Bean
public Binding bindingBirthdayGiftSmsExchange(Queue birthdayGiftSmsQueue, DirectExchange exchange) {
return BindingBuilder.bind(birthdayGiftSmsQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.BIRTHDAY_GIFT_SMS_QUEUE);
@@ -149,6 +172,7 @@ public class RabbitConfig {
public Queue orderProductStatusQueue() {
return new Queue(activeProfile + "-" + RabbitConstants.Queue.ORDER_PRODUCT_STATUS_QUEUE, true);
}
@Bean
public Binding bindingOrderProductStatusExchange(Queue orderProductStatusQueue, DirectExchange exchange) {
return BindingBuilder.bind(orderProductStatusQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.ORDER_PRODUCT_STATUS_QUEUE);
@@ -160,6 +184,7 @@ public class RabbitConfig {
public Queue orderDetailStatusQueue() {
return new Queue(activeProfile + "-" + RabbitConstants.Queue.ORDER_DETAIL_STATUS_QUEUE, true);
}
@Bean
public Binding bindingOrderDetailStatusExchange(Queue orderDetailStatusQueue, DirectExchange exchange) {
return BindingBuilder.bind(orderDetailStatusQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.ORDER_DETAIL_STATUS_QUEUE);

View File

@@ -10,13 +10,14 @@ public interface RabbitConstants {
}
class Queue {
public static final String SHOP_ENTRY_MANAGER = "shop.entry.manager";
public static final String ORDER_STOCK_QUEUE = "order.stock.queue";
public static final String ORDER_REFUND_QUEUE = "order.refund.queue";
public static final String ORDER_CANCEL_QUEUE = "order.cancel.queue";
public static final String ORDER_PRINT_QUEUE = "order.print.queue";
public static final String ORDER_MACHINE_PRINT_QUEUE = "order.machine.print.queue";
public static final String ORDER_HANDOVER_PRINT_QUEUE = "order.handover.print.queue";
public static final String CALL_TABLE_PRINT_QUEUE = "call.table.print.queue";
public static final String CALL_TABLE_QUEUE = "call.table.print.queue";
public static final String PRODUCT_INFO_CHANGE_QUEUE = "product.info.change.queue";
/**

View File

@@ -130,6 +130,13 @@ public class RabbitPublisher {
sendMsg(RabbitConstants.Queue.ORDER_PRODUCT_STATUS_QUEUE, qrContent);
}
/**
* 进件
*/
public void sendEntryManagerMsg(String shopId) {
sendMsg(RabbitConstants.Queue.SHOP_ENTRY_MANAGER, shopId);
}
/**
* 订单商品状态消息

View File

@@ -33,6 +33,8 @@ public interface RedisCst {
public static final String EXPIRED_WECHAT = "expired:wechat:";
}
//商家进件
String SHOP_ENTRY = "shop:entry";
String SMS_CODE = "sms:code:";
// 店铺会员动态支付码

View File

@@ -6,14 +6,15 @@ import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* @author GYJoker
@@ -650,4 +651,106 @@ public class RedisService {
}
return JSON.parseArray(jsonStr, type);
}
public static int retryCount = 5;
/**
* 执行任务并保证锁唯一
*
* @param supplier 业务逻辑
* @param lockKey Redis锁的Key
* @return 业务逻辑返回值
*/
public <T> T runFunAndCheckKey(Supplier<T> supplier, String lockKey) {
String lockValue = String.valueOf(System.nanoTime() + Thread.currentThread().threadId());
try {
// 尝试获取锁,超时时间 5 秒,防止死锁
boolean lock = Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, 5, TimeUnit.SECONDS));
int count = 0;
// 初始等待 10ms
int retryDelay = 10;
while (!lock) {
// 最多重试 10 次,大约 10 秒
if (count++ > 50) {
throw new RuntimeException("系统繁忙, 稍后再试");
}
Thread.sleep(retryDelay);
// 指数退避,最大等待 200ms
retryDelay = Math.min(retryDelay * 2, 200);
lock = Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, 5, TimeUnit.SECONDS));
}
// 执行任务
return supplier.get();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("线程被中断", e);
} catch (Exception e) {
log.error("执行出错:{}", e.getMessage(), e);
throw e;
} finally {
// 释放锁(使用 Lua 脚本确保原子性)
unlock(lockKey, lockValue);
}
}
/**
* 使用 Lua 脚本确保释放锁的原子性
*
* @param lockKey 锁的 Key
* @param lockValue 当前线程的锁值
*/
private void unlock(String lockKey, String lockValue) {
String luaScript =
"if redis.call('get', KEYS[1]) == ARGV[1] then " +
"return redis.call('del', KEYS[1]) " +
"else return 0 end";
redisTemplate.execute(new DefaultRedisScript<>(luaScript, Long.class),
Collections.singletonList(lockKey), lockValue);
}
public static <T, R> R runFunAndRetry(
Supplier<R> function,
Function<R, Boolean> check, Consumer<R> errFun) {
R result = function.get();
boolean flag = check.apply(result);
while (flag && retryCount-- > 0) {
result = function.get();
flag = check.apply(result);
}
if (flag) {
errFun.accept(result);
}
return result;
}
/**
* 防抖函数:在指定秒数内相同 Key 的任务只会执行一次
*
* @param key 防抖使用的 Redis Key
* @param seconds 防抖时间(秒)
* @param task 要执行的业务逻辑
* @return true 执行了任务false 在防抖期内被拦截
*/
public boolean debounce(String key, long seconds, Runnable task) {
try {
Boolean success = redisTemplate.opsForValue().setIfAbsent(
key, "1", seconds, TimeUnit.SECONDS
);
if (Boolean.TRUE.equals(success)) {
task.run();
return true;
}
return false;
} catch (Exception e) {
log.error("防抖函数执行失败 key={} err={}", key, e.getMessage(), e);
return false;
}
}
}

View File

@@ -10,7 +10,7 @@
<artifactId>cash-common-service</artifactId>
<packaging>jar</packaging>
<name>global-service</name>
<name>common-service</name>
<url>https://maven.apache.org</url>

View File

@@ -285,4 +285,13 @@ public class ShopInfoEditDTO {
*/
private Integer isCountStick;
/**
* 企业id
*/
private String weworkId;
/**
* 企业接入链接
*/
private String weworkUrl;
}

View File

@@ -0,0 +1,69 @@
package com.czg.account.entity;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.io.Serial;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 悬浮窗配置 实体类。
*
* @author ww
* @since 2025-12-29
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table("tb_quick_menu")
public class QuickMenu implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Id(keyType = KeyType.Auto)
private Integer id;
/**
* 店铺Id
*/
private Long shopId;
/**
* 菜单图标
*/
private String url;
/**
* 菜单Id
*/
@NotNull(message = "关联菜单不能为空")
private Long menuId;
/**
* 排序
*/
private Integer sort;
/**
* 状态 1-启用 0-禁用
*/
private Integer status;
@Column(onInsertValue = "now()")
private LocalDateTime createTime;
@Column(onInsertValue = "now()", onUpdateValue = "now()")
private LocalDateTime updateTime;
}

View File

@@ -135,5 +135,13 @@ public class ShopConfig implements Serializable {
private String dingAppKey;
private String dingAppSecret;
/**
* 企业id
*/
private String weworkId;
/**
* 企业接入链接
*/
private String weworkUrl;
}

View File

@@ -32,7 +32,6 @@ public class ShopInfo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 使用系统用户 sys_user id
*/
@@ -363,4 +362,15 @@ public class ShopInfo implements Serializable {
*/
private BigDecimal amount;
/**
* 企业id
*/
@Column(ignore = true)
private String weworkId;
/**
* 企业接入链接
*/
@Column(ignore = true)
private String weworkUrl;
}

View File

@@ -0,0 +1,14 @@
package com.czg.account.service;
import com.mybatisflex.core.service.IService;
import com.czg.account.entity.QuickMenu;
/**
* 悬浮窗配置 服务层。
*
* @author ww
* @since 2025-12-29
*/
public interface QuickMenuService extends IService<QuickMenu> {
}

View File

@@ -23,8 +23,9 @@ public interface ShopInfoService extends IService<ShopInfo> {
/**
* 检测开关
* @param shopId 店铺id
* @param switchType ShopInfo的某列 开关 目前只支持Integer类型字段
*
* @param shopId 店铺id
* @param switchType ShopInfo的某列 开关 目前只支持Integer类型字段
* @return true:开启 false:关闭
*/
boolean checkSwitch(Long shopId, ShopSwitchTypeEnum switchType) throws ValidateException;

View File

@@ -1,22 +0,0 @@
package com.czg.account.service;
import com.czg.account.dto.merchant.ShopMerchantEditDTO;
import com.czg.account.entity.ShopMerchant;
import com.mybatisflex.core.service.IService;
import java.io.Serializable;
/**
* 第三方商户进件 服务层。
*
* @author Administrator
* @since 2025-02-11
*/
public interface ShopMerchantService extends IService<ShopMerchant> {
ShopMerchant detail(Integer shopId);
Boolean edit(ShopMerchantEditDTO shopMerchantEditDTO);
@Override
ShopMerchant getById(Serializable id);
}

View File

@@ -79,7 +79,27 @@ public interface ParamCodeCst {
* 超掌柜支付回调地址
* <p>支付宝/微信支付完成后,支付平台回调我方系统的地址</p>
*/
public static String PAY_CZG_NOTIFY_URL = "pay_czg_notify_url";
public static String NATIVE_PAY_NOTIFY_URL = "native_pay_notify_url";
public static String NATIVE_REFUND_NOTIFY_URL = "native_refund_notify_url";
/**
* 超掌柜支付域名
* <p>超掌柜支付相关接口的根域名</p>
*/
public static String POLY_DOMAIN = "poly_domain";
public static String POLY_PAY_NOTIFY_URL = "poly_pay_notify_url";
public static String POLY_REFUND_NOTIFY_URL = "poly_refund_notify_url";
/**
* 微信原生回调地址
* <p>微信原生支付接口的回调地址(区别于超掌柜封装的回调)</p>
*/
public static String NATIVE_NOTIFY_URL = "native_notify_url";
/**
* 店铺订单支付BaseUrl
* <p>店铺订单支付页面的基础域名</p>
*/
public static String SHOP_ORDER_PAY_BASE_URL = "shop_order_pay_base_url";
/**
* 排队到号通知
*/
@@ -111,11 +131,6 @@ public interface ParamCodeCst {
*/
public static String SMS_FEE = "sms_fee";
/**
* 店铺订单支付BaseUrl
* <p>店铺订单支付页面的基础域名</p>
*/
public static String SHOP_ORDER_PAY_BASE_URL = "shop_order_pay_base_url";
/**
* 平台名称
@@ -123,30 +138,12 @@ public interface ParamCodeCst {
*/
public static String PLATE_NAME = "plate_name";
/**
* 超掌柜退款回调地址
* <p>支付平台处理退款后,回调我方系统的地址</p>
*/
public static String PAY_CZG_REFUND_NOTIFY_URL = "pay_czg_refund_notify_url";
/**
* 超掌柜支付域名
* <p>超掌柜支付相关接口的根域名</p>
*/
public static String PAY_CZG_DOMAIN = "pay_czg_domain";
/**
* 叫号页面地址
* <p>餐厅叫号系统的前端页面地址</p>
*/
public static String CALL_PAGE_URL = "call_page_url";
/**
* 微信原生回调地址
* <p>微信原生支付接口的回调地址(区别于超掌柜封装的回调)</p>
*/
public static String NATIVE_NOTIFY_URL = "native_notify_url";
/**
* 公众号关注位置
* <p>公众号关注入口的展示位置可选值mine-我的页面、order-订单页面、eat-就餐页面</p>

View File

@@ -43,4 +43,30 @@ public interface SystemConstants {
*/
public static final String CUSTOM = "custom";
}
/**
* 三方支付类型
*/
class PayType {
/**
* 微信支付
*/
public static final String WECHAT = "wechatPay";
/**
* 支付宝支付
*/
public static final String ALIPAY = "alipay";
/**
* 微信小程序支付
*/
public static final String WECHAT_APP_ID = "wxd88fffa983758a30";
/**
* 支付宝小程序支付
*/
public static final String ALIPAY_APP_ID = "2021004145625815";
}
}

View File

@@ -3,6 +3,7 @@ package com.czg.order.dto;
import com.czg.utils.AssertUtil;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
@@ -13,6 +14,7 @@ import java.math.BigDecimal;
* @author ww
*/
@Data
@Accessors(chain = true)
public class LtPayOtherDTO {
/**
* 积分商品id/团购商品id

View File

@@ -24,6 +24,10 @@ public class MkDistributionPayDTO implements Serializable {
private Long shopId;
private String platformType = "DIS";
private Long userId;
/**
* 支付类型
* {@link com.czg.constants.SystemConstants.PayType}
*/
private String payType;
private String returnUrl;
private String buyerRemark;

View File

@@ -28,6 +28,7 @@ public class OrderInfoAddDTO implements Serializable {
* 已出菜 SENT_OUT
* 已上菜 DELIVERED
* 已超时 EXPIRED
* 加急 URGENT
*/
private String subStatus;
//限时折扣部分

View File

@@ -1,267 +0,0 @@
package com.czg.order.dto;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import com.alibaba.fastjson2.annotation.JSONField;
import java.io.Serial;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 订单表 实体类。
*
* @author ww
* @since 2025-02-13
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class OrderInfoDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private Long id;
/**
* 订单编号
* pc 收银机客户端 PC+雪花ID
* wechat 微信小程序 WX+雪花ID
* alipay 支付宝小程序 ALI+雪花ID
* admin-pc PC管理端 WEB+雪花ID
* admin-app APP管理端 APP+雪花ID
*/
private String orderNo;
/**
* 店铺Id
*/
private Long shopId;
/**
* 用户Id user_info表的id
*/
private Long userId;
/**
* 退单金额
*/
private BigDecimal refundAmount;
/**
* 订单原金额 不含折扣价格
*/
private BigDecimal originAmount;
/**
* 抹零金额 减免多少钱
*/
private BigDecimal roundAmount;
/**
* 优惠总金额
*/
private BigDecimal discountAllAmount;
/**
* 订单金额 (扣除各类折扣)
*/
private BigDecimal orderAmount;
/**
* 实际支付金额
*/
private BigDecimal payAmount;
/**
* 积分抵扣金额
*/
private BigDecimal pointsDiscountAmount;
/**
* 使用的积分数量
*/
private Integer pointsNum;
/**
* 商品优惠券抵扣金额
*/
private BigDecimal productCouponDiscountAmount;
/**
* 用户使用的卡券
*/
private String couponInfoList;
/**
* 满减活动抵扣金额
*/
private BigDecimal discountActAmount;
/**
* 折扣金额
*/
private BigDecimal discountAmount;
// /**
// * 折扣比例
// */
// private BigDecimal discountRatio;
/**
* 打包费
*/
private BigDecimal packFee;
/**
* 台桌Id
*/
private String tableCode;
/**
* 台桌名称
*/
private String tableName;
/**
* 订单类型-
* cash收银(除小程序以外 都属于收银)
* miniapp小程序
*/
private String orderType;
/**
* 平台类型 pc 收银机客户端 wechat 微信小程序 alipay 支付宝小程序 admin-pc PC管理端 admin-app APP管理端
*/
private String platformType;
/**
* 用餐模式 堂食 dine-in 外带 take-out 外卖 take-away
*/
private String dineMode;
/**
* 支付模式:
* 后付费 after-pay
* 先付费 before-pay
* 无桌码 no-table
*/
private String payMode;
/**
* 支付类型
* 主扫 main-scan
* 被扫 back-scan
* 微信小程序 wechat-mini
* 支付宝小程序 alipay-mini
* 会员支付 vip-pay
* 现金支付 cash-pay
*/
private String payType;
/**
* 状态: unpaid-待支付;in-production 制作中;wait_out 待取餐;;done-订单完成;refunding-申请退单;refund-退单;part_refund 部分退单;cancelled-取消订单
*/
private String status;
/**
* 折扣信息 json
*/
private String discountInfo;
/**
* 限时折扣信息 json
*/
private String limitRate;
/**
* 是否支持退款1支持退单 0不支持退单
*/
private Integer refundAble;
/**
* 支付时间
*/
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime paidTime;
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
/**
* 支付订单号
* tb_order_payment.id
* tb_shop_user_flow.id
*/
private Long payOrderId;
/**
* 交易日期
*/
private String tradeDay;
/**
* 备注
*/
private String remark;
/**
* 取餐码
*/
private String takeCode;
/**
* 员工id
*/
private Long staffId;
/**
* 当前订单下单次数
*/
private Integer placeNum;
/**
* 用餐人数
*/
private Integer seatNum;
/**
* 餐位费
*/
private BigDecimal seatAmount;
/**
* 退款备注
*/
private String refundRemark;
/**
* 是否使用了霸王餐
*/
private Integer isFreeDine;
/**
* 是否等叫 0 否 1 等叫
*/
private Integer isWaitCall;
/**
* 挂账人id
*/
private Long creditBuyerId;
/**
* 是否回收站 0-否1回收站
*/
private Integer isDel;
private String failMsg;
}

View File

@@ -0,0 +1,40 @@
package com.czg.order.dto;
import com.czg.order.entity.ShopDirectMerchant;
import com.czg.pay.NativeMerchantDTO;
import com.czg.pay.PolyMerchantDTO;
import lombok.Data;
/**
* 支付信息
*
* @author ww
*/
@Data
public class ShopMerchantDTO {
private Long shopId;
/**
* poly 聚合(支付平台) native 原生(wx/ali 原生)
* {@link com.czg.constant.PayChannelCst}
*/
private String channel;
/**
* 聚合支付商户
* native 必填 对应 tb_shop_direct_merchant 的 shopId
*/
private Long relatedId;
/**
* 原生支付参数
*/
private NativeMerchantDTO nativeMerchantDTO;
/**
* 聚合支付参数
*/
private PolyMerchantDTO polyMerchantDTO;
/**
* 店铺绑定的商户信息
*/
private ShopDirectMerchant shopDirectMerchant;
}

View File

@@ -1,6 +1,8 @@
package com.czg.order.entity;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.czg.order.dto.LimitRateDTO;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
@@ -298,8 +300,10 @@ public class OrderInfo implements Serializable {
private Integer isDel;
private String failMsg;
/**
* 打印状态 Json格式
*/
private String printStatus;
public String getRefundRemark() {
@@ -342,4 +346,41 @@ public class OrderInfo implements Serializable {
// 如果需要加上抹零金额,可以取消下面这行注释
// .add(this.getRoundAmount() != null ? this.getRoundAmount() : BigDecimal.ZERO);
}
private JSONArray getPrintStatusAsArray() {
if (StrUtil.isBlank(printStatus)) {
return new JSONArray();
}
try {
return JSONArray.parseArray(printStatus.trim());
} catch (Exception e) {
return new JSONArray();
}
}
public void upPrintStatus(JSONObject printJson, boolean isPrintSuccess) {
String currentDeviceId = printJson.getString("id");
JSONArray oldPrintStatusArray = getPrintStatusAsArray();
// 3. 初始化新的打印状态JSON数组用于存储处理后的结果
JSONArray newPrintStatusArray = new JSONArray();
// 场景1打印成功 - 移除原有数组中与当前设备ID一致的记录保留其余记录
if (oldPrintStatusArray != null && !oldPrintStatusArray.isEmpty()) {
for (int i = 0; i < oldPrintStatusArray.size(); i++) {
JSONObject deviceObj = oldPrintStatusArray.getJSONObject(i);
String deviceId = deviceObj.getString("id");
// 仅保留非当前设备ID的记录
if (currentDeviceId != null && !currentDeviceId.equals(deviceId)) {
newPrintStatusArray.add(deviceObj);
}
}
}
if (!isPrintSuccess) {
newPrintStatusArray.add(printJson);
}
if (!newPrintStatusArray.isEmpty()) {
printStatus = newPrintStatusArray.toJSONString();
} else {
printStatus = "";
}
}
}

View File

@@ -5,6 +5,7 @@ import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@@ -40,6 +41,17 @@ public class OrderPayment implements Serializable {
*/
private Long shopId;
/**
* 支付渠道
* {@link com.czg.constant.PayChannelCst}
*/
private String channel;
/**
* 平台类型
* {@link com.czg.PayCst.Platform}
*/
private String platformType;
/**
* 来源Id 订单Id或充值id
*/
@@ -104,28 +116,67 @@ public class OrderPayment implements Serializable {
public OrderPayment() {
}
public OrderPayment(@NonNull Long shopId,@NonNull Long sourceId, @NotBlank String sourceType,@NotBlank String payType, @NotBlank String orderNo,
String authCode, @NonNull BigDecimal amount) {
this.shopId = shopId;
this.sourceId = sourceId;
this.sourceType = sourceType;
this.payType = payType;
this.orderNo = orderNo;
this.authCode = authCode;
this.amount = amount;
this.payStatus = PayTypeConstants.PayStatus.INIT;
/**
* 订单专用支付
*
* @param sourceId 订单Id
* @param amount 单元 元
* @param authCode 扫码支付时必填 扫描码
*/
public static OrderPayment orderPay(@NonNull Long shopId, @NonNull Long sourceId,
@NotBlank String orderNo, @NonNull BigDecimal amount, String authCode) {
OrderPayment orderPayment = getInstance(shopId, sourceId, PayTypeConstants.SourceType.ORDER, orderNo, amount, authCode, null);
orderPayment.setPayType(PayTypeConstants.PayType.PAY);
orderPayment.setPayStatus(PayTypeConstants.PayStatus.INIT);
return orderPayment;
}
public OrderPayment(@NonNull Long shopId,@NonNull Long sourceId, @NotBlank String sourceType,@NotBlank String payType, @NotBlank String orderNo,
String authCode, @NonNull BigDecimal amount, Long relatedId) {
this.shopId = shopId;
this.sourceId = sourceId;
this.sourceType = sourceType;
this.payType = payType;
this.orderNo = orderNo;
this.authCode = authCode;
this.amount = amount;
this.relatedId = relatedId;
this.payStatus = PayTypeConstants.PayStatus.INIT;
/**
* 初始化支付参数
*
* @param sourceId 充值时为会员Id shopUserID
* 购买时为商品Id
* @param sourceType {@link PayTypeConstants.SourceType} 支付来源
* @param amount 单元 元
* @param authCode 扫码支付时必填 扫描码
* @param relatedId 霸王餐充值为 订单id 会员充值为 活动id 充值并支付时 为 MkShopRechargeDetail
*/
public static OrderPayment pay(@NonNull Long shopId, @NonNull Long sourceId, @NotBlank String sourceType,
@NotBlank String orderNo, @NonNull BigDecimal amount,
String authCode, Long relatedId) {
OrderPayment orderPayment = getInstance(shopId, sourceId, sourceType, orderNo, amount, authCode, relatedId);
orderPayment.setPayType(PayTypeConstants.PayType.PAY);
orderPayment.setPayStatus(PayTypeConstants.PayStatus.INIT);
return orderPayment;
}
public static OrderPayment refund(@NonNull Long shopId, @NonNull Long sourceId, @NotBlank String sourceType,
@NotBlank String orderNo, @NonNull BigDecimal amount, Long relatedId, String platformType) {
OrderPayment orderPayment = getInstance(shopId, sourceId, sourceType, orderNo, amount, null, relatedId);
orderPayment.setPayType(PayTypeConstants.PayType.REFUND);
orderPayment.setPayStatus(PayTypeConstants.PayStatus.INIT);
orderPayment.setPlatformType(platformType);
return orderPayment;
}
public static OrderPayment refundCompensate(@NonNull Long shopId, @NonNull Long sourceId, @NotBlank String sourceType,
@NotBlank String orderNo, @NonNull BigDecimal amount, Long relatedId) {
OrderPayment orderPayment = getInstance(shopId, sourceId, sourceType, orderNo, amount, null, relatedId);
orderPayment.setPayType(PayTypeConstants.PayType.REFUND_COMPENSATE);
orderPayment.setPayStatus(PayTypeConstants.PayStatus.INIT);
return orderPayment;
}
private static OrderPayment getInstance(Long shopId, Long sourceId, String sourceType,
String orderNo, BigDecimal amount, String authCode, Long relatedId) {
OrderPayment orderPayment = new OrderPayment();
orderPayment.shopId = shopId;
orderPayment.sourceId = sourceId;
orderPayment.sourceType = sourceType;
orderPayment.orderNo = orderNo;
orderPayment.authCode = authCode;
orderPayment.amount = amount;
orderPayment.relatedId = relatedId;
return orderPayment;
}
}

View File

@@ -0,0 +1,149 @@
package com.czg.order.entity;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.io.Serial;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 商户进件 实体类。
*
* @author ww
* @since 2026-01-07
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table("tb_shop_direct_merchant")
public class ShopDirectMerchant implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 店铺id
*/
@Id
private Long shopId;
/**
* 店铺名称
*/
@Column(ignore = true)
private String shopName;
/**
* 营业执照编号
*/
private String licenceNo;
/**
* 支付宝账号
*/
private String alipayAccount;
/**
* 商户编号(在当前系统唯一)
*/
private String merchantCode;
/**
* 【必填】
* 商户类型
* 0: 个体商户;
* 1: 企业商户;
* 3: 小微商户 暂不支持
*/
private String userType;
/**
* 【必填】
* 商户简称--企业、个体必填
*/
private String shortName;
/**
* 商户基础信息
*/
private String merchantBaseInfo;
/**
* 法人信息
*/
private String legalPersonInfo;
/**
* 营业执照信息
*/
private String businessLicenceInfo;
/**
* 门店信息
*/
private String storeInfo;
/**
* 结算信息
*/
private String settlementInfo;
@Column(onInsertValue = "now()")
private LocalDateTime createTime;
@Column(onInsertValue = "now()", onUpdateValue = "now()")
private LocalDateTime updateTime;
private String errorMsg;
private String wechatApplyId;
/**
* 微信状态
*/
private String wechatStatus;
/**
* 微信进件错误信息
*/
private String wechatErrorMsg;
/**
* 微信进件签名地址
*/
private String wechatSignUrl;
private String alipayOrderId;
/**
* 支付宝状态
*/
private String alipayStatus;
/**
* 支付宝进件错误信息
*/
private String alipayErrorMsg;
/**
* 支付宝进件签名地址
*/
private String alipaySignUrl;
/**
* 支付宝授信息
*/
private String alipayAuthInfo;
/**
* 微信商户id
*/
private String wechatMerchantId;
/**
* 支付宝商户id
*/
private String alipayMerchantId;
}

View File

@@ -1,4 +1,4 @@
package com.czg.account.entity;
package com.czg.order.entity;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
@@ -18,57 +18,54 @@ import java.time.LocalDateTime;
* @since 2025-02-11
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Table("tb_shop_merchant")
@Table("tb_shop_merchant2")
public class ShopMerchant implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Id
private Long id;
/**
* 店铺id
*/
@Id
private Long shopId;
/**
* 支付系统商户id
* poly 聚合(支付平台) native 原生(wx/ali 原生)
* {@link com.czg.constant.PayChannelCst}
*/
private String storeId;
private String merchantName;
private String channel;
/**
* 商户应用id
* 聚合支付商户
* native 必填 对应 tb_shop_direct_merchant shopId
*/
private String appId;
private Long relatedId;
/**
* 商户token
* 微信appid
*/
private String appSecret;
private String wechatAppId;
/**
* 支付宝appid
*/
private String alipayAppId;
/**
* 微信小程序appid
* 聚合支付参数
*/
private String wechatSmallAppid;
private String polyPayJson;
/**
* 支付宝小程序appid
* 原生支付参数
*/
private String alipaySmallAppid;
/**
* 支付密码
*/
private String payPassword;
private String nativePayJson;
@Column(onInsertValue = "now()")
private LocalDateTime createTime;
@Column(onInsertValue = "now()", onUpdateValue = "now()")
private LocalDateTime updateTime;
}

View File

@@ -12,9 +12,9 @@ import com.czg.order.enums.PayEnums;
import com.czg.order.vo.HistoryOrderPrintVo;
import com.czg.order.vo.HistoryOrderVo;
import com.czg.order.vo.OrderInfoVo;
import com.czg.pay.PayNotifyRespDTO;
import com.czg.resp.CzgResult;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.service.IService;
import jakarta.validation.constraints.NotBlank;
import org.jetbrains.annotations.NotNull;
@@ -44,7 +44,7 @@ public interface OrderInfoCustomService {
CzgResult<Object> mergeOrder(MergeOrderDTO param);
void payCallBackOrder(@NotBlank String orderNo, @NotNull JSONObject resultJson, int retryCount);
void payCallBackOrder(@NotBlank String orderNo, @NotNull PayNotifyRespDTO notifyRespDTO, String channel, int retryCount);
void refundCallBackOrder(@NotBlank String orderNo, @NotNull JSONObject resultJson);

View File

@@ -11,6 +11,8 @@ import com.czg.order.entity.PrintMachineLog;
* @since 2025-03-11
*/
public interface PrintMachineLogService extends IService<PrintMachineLog> {
void save(PrintMachine config, String bizType, String printContent, Object respJson);
void save(Long orderId, PrintMachine config, String bizType, String printContent, String respJson);
void save(PrintMachine config, String bizType, String printContent, String respJson);
}

View File

@@ -0,0 +1,37 @@
package com.czg.order.service;
import com.czg.order.dto.ShopMerchantDTO;
import com.czg.order.entity.ShopDirectMerchant;
import com.czg.order.entity.ShopMerchant;
import com.czg.pay.NativeMerchantDTO;
import com.mybatisflex.core.service.IService;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
/**
* 第三方商户进件 服务层。
*
* @author Administrator
* @since 2025-02-11
*/
public interface ShopMerchantService extends IService<ShopMerchant> {
ShopMerchantDTO detail(Long shopId);
/**
* 进件结果保存/ 支付参数修改
*/
Boolean editEntry(ShopMerchantDTO shopMerchantParam, boolean isUp);
/**
* 已绑定的支付
* 更新商户支付参数
*/
void upMerchant(@NotBlank Long relatedId, @NotNull NativeMerchantDTO nativeMerchantDTO);
ShopMerchant getByShopId(Long shopId);
ShopDirectMerchant getMainMerchant(Long shopId);
}

View File

@@ -42,6 +42,5 @@ public class OrderDetailSmallVO implements Serializable {
private LocalDateTime dishOutTime;
private LocalDateTime foodServeTime;
private Integer isTemporary;
}

View File

@@ -133,6 +133,11 @@ public class OrderInfoVo implements Serializable {
* 备注
*/
private String remark;
/**
* 打印状态 Json格式
* [{"id":"124","name":"111","time":"2025-12-29 11:05:18"},{"id":"111","name":"标签","time":"2025-12-29 11:05:30"}]
*/
private String printStatus;
/**
* 是否使用了霸王餐

View File

@@ -0,0 +1,63 @@
package com.czg.pay;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 支付宝授权信息
* @author yjjie
* @date 2026/1/9 11:31
*/
@Data
@Accessors(chain = true)
public class AlipayAuthInfoDto {
/**
* 授权商户的user_id
*/
@JSONField(name = "user_id")
private String userId;
/**
* 授权商户的open_id
*/
@JSONField(name = "open_id")
private String openId;
/**
* 授权商户的appid
*/
@JSONField(name = "auth_app_id")
private String authAppId;
/**
* 应用授权令牌
*/
@JSONField(name = "app_auth_token")
private String appAuthToken;
/**
* 应用授权令牌有效期
*/
@JSONField(name = "expires_in")
private String expiresIn;
/**
* 刷新令牌
*/
@JSONField(name = "app_refresh_token")
private String appRefreshToken;
/**
* 刷新令牌的有效时间
*/
@JSONField(name = "re_expires_in")
private String reExpiresIn;
/**
* 签约单号
*/
@JSONField(name = "order_no")
private String orderNo;
}

View File

@@ -0,0 +1,133 @@
package com.czg.pay;
import lombok.Data;
import lombok.NonNull;
/**
* @author ww
*/
@Data
public class CzgPayBaseReq {
//必填范围
/**
* 订单标题
*/
private String subject;
/**
* 订单描述 String(256)
*/
private String body;
/**
* 交易金额 分
*/
private Long amount;
/**
* 货币类型 cny
*/
private String currency = "cny";
/**
* 商户订单号 String(30)
* 操作方式+雪花算法
* 收银机客户端 PC+雪花ID
* 微信小程序 WX+雪花ID
* 支付宝小程序 ALI+雪花ID
* PC管理端 WEB+雪花ID
* APP管理端 APP+雪花ID
* <p>
* 退款 re+雪花ID
*/
private String mchOrderNo;
/**
* 异步通知地址 String(128)
* 支付结果异步回调URL,只有传了该值才会发起回调
*/
private String notifyUrl;
/**
* 扩展参数 String(512)
* 商户扩展参数,回调时会原样返回
* * 扩展参数
* * {
* * "pay_type": "order/vip"
* * }
*/
private String extParam;
/**
* 原生支付 不需要 store_id
*/
private String storeId;
/**
* 支付类型
* {@link com.czg.constants.SystemConstants.PayType}
*/
private String payType;
/**
* 用户唯一标识 String(30)
* 微信支付时传入用户的openId
* 支付宝支付和银联支付时传入用户的userId
*/
private String userId;
/**
* 用户IP
* 需要传付款用户客户端IP地址
*/
private String clientIp;
/**
* 子商户 appid ,微信付款支付的时候 需要上送
* isScreen 为 false 的情况下需要传入
*/
private String subAppid;
/**
* 支付条码
*/
private String authCode;
public CzgPayBaseReq() {
}
public CzgPayBaseReq(String mchOrderNo, String detail, Long amount, String payType, String userId, String clientIp) {
this.mchOrderNo = mchOrderNo;
this.subject = detail;
this.body = detail;
this.amount = amount;
this.payType = payType;
this.userId = userId;
this.clientIp = clientIp;
}
public void polyBase(@NonNull String storeId, @NonNull String notifyUrl) {
this.storeId = storeId;
this.notifyUrl = notifyUrl;
}
public static CzgPayBaseReq ltPayReq(@NonNull String mchOrderNo, @NonNull String detail, @NonNull Long amount
, @NonNull String payType, @NonNull String openId, @NonNull String clientIp) {
return new CzgPayBaseReq(mchOrderNo, detail, amount, payType, openId, clientIp);
}
public static CzgPayBaseReq h5PayReq(@NonNull String mchOrderNo, @NonNull String detail, @NonNull Long amount, @NonNull String clientIp) {
return new CzgPayBaseReq(mchOrderNo, detail, amount, null, null, clientIp);
}
public static CzgPayBaseReq jsPayReq(@NonNull String mchOrderNo, @NonNull String detail, @NonNull Long amount
, @NonNull String payType, @NonNull String openId, @NonNull String clientIp) {
return new CzgPayBaseReq(mchOrderNo, detail, amount, payType, openId, clientIp);
}
public static CzgPayBaseReq scanPayReq(@NonNull String mchOrderNo, @NonNull String detail, @NonNull Long amount, @NonNull String clientIp) {
return new CzgPayBaseReq(mchOrderNo, detail, amount, null, null, clientIp);
}
public static CzgPayBaseReq microPay(@NonNull String mchOrderNo, @NonNull String detail, @NonNull Long amount, @NonNull String authCode) {
CzgPayBaseReq stringReq = new CzgPayBaseReq(mchOrderNo, detail, amount, null, null, null);
stringReq.setAuthCode(authCode);
return stringReq;
}
}

View File

@@ -0,0 +1,71 @@
package com.czg.pay;
import lombok.Data;
import lombok.NonNull;
/**
* @author ww
*/
@Data
public class CzgRefundReq {
//必填范围
/**
* 退款订单号
* 商户退款订单号
*/
private String mchRefundNo;
/**
* 退款原因
*/
private String refundReason;
/**
* 退款金额
* 单位为分
*/
private Long refundAmount;
/**
* 原订单总金额 单位 分
*/
private Long orderTotalAmount;
//非必填范围
/**
* 原平台订单号 (二选一)
*/
private String payOrderId;
/**
* 原商户订单号 (二选一)
*/
private String mchOrderNo;
/**
* 扩展参数
* * 扩展参数
* * {
* * "pay_type": "order/vip"
* * }
*/
private String extParam;
/**
* 回调地址
*/
private String notifyUrl;
/**
* 支付平台
*/
private String platform;
/**
* payOrderId和mchOrderNo 二选一 必填
*/
public CzgRefundReq(@NonNull String mchRefundNo, @NonNull String refundReason, @NonNull Long refundAmount,
@NonNull Long orderTotalAmount, String mchOrderNo, String extParam, String platform) {
this.mchRefundNo = mchRefundNo;
this.refundReason = refundReason;
this.refundAmount = refundAmount;
this.orderTotalAmount = orderTotalAmount;
this.mchOrderNo = mchOrderNo;
this.extParam = extParam;
this.platform = platform;
}
}

View File

@@ -0,0 +1,17 @@
package com.czg.pay;
import lombok.Data;
/**
* 原生支付参数
* @author ww
*/
@Data
public class NativeMerchantDTO {
private String wechatMerchantId;
private String alipayMerchantId;
/**
* 支付宝 授权信息解析
*/
private AlipayAuthInfoDto alipayAuthInfo;
}

View File

@@ -0,0 +1,67 @@
package com.czg.pay;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 统一支付回调响应数据
* @author yjjie
* @date 2026/1/15 09:16
*/
@Data
@Accessors(chain = true)
public class PayNotifyRespDTO {
/**
* 商户订单号
*/
private String mchOrderNo;
/**
* 三方订单号
*/
private String thirdOrderNo;
/**
* 订单状态
* INIT - 订单初始化;
* TRADE_AWAIT - 待支付;
* TRADE_SUCCESS - 支付成功;
* TRADE_FAIL -支付失败;
* TRADE_CANCEL -交易取消;
* TRADE_REFUND -已退款;
* REFUND_ING - 退款中;
* TRADE_CLOSE -订单关闭
*/
private String status;
/**
* 支付平台
*/
private String platform;
/**
* 订单金额 分
*/
private Long amount;
/**
* 扩展数据
*/
private String extData;
/**
* 支付成功时间
*/
private String paySuccessTime;
/**
* 错误信息
*/
private String errorMsg;
/**
* 回调原始数据
*/
private String originalData;
}

View File

@@ -1,16 +1,14 @@
package com.czg.account.dto.merchant;
package com.czg.pay;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
/**
* @author Administrator
* 聚合支付参数
* @author ww
*/
@Data
public class ShopMerchantEditDTO {
@NotNull(message = "店铺id不为空")
private Long shopId;
public class PolyMerchantDTO {
@NotEmpty(message = "支付系统商户id不为空")
private String storeId;
@NotEmpty(message = "支付系统商户名称不为空")
@@ -20,12 +18,6 @@ public class ShopMerchantEditDTO {
@NotEmpty(message = "商户秘钥不为空")
private String appSecret;
// 支付密码
@NotEmpty(message = "支付密码不为空")
// @NotEmpty(message = "支付密码不为空")
private String payPassword;
// 微信appid
@NotEmpty(message = "微信appid")
private String wechatSmallAppid;
// 支付宝appid
@NotEmpty(message = "支付宝appid")
private String alipaySmallAppid;
}

View File

@@ -0,0 +1,39 @@
package com.czg.pay;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 查询订单响应参数
* @author yjjie
* @date 2026/1/15 13:56
*/
@Data
@Accessors(chain = true)
public class QueryOrderRespDTO {
/**
* 订单号
*/
private String orderNo;
/**
* 状态
*/
private String status;
/**
* 金额
*/
private Long amount;
/**
* 错误信息
*/
private String errorMsg;
/**
* 原始响应数据
*/
private String originResp;
}

View File

@@ -0,0 +1,59 @@
package com.czg.pay;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 退款相应数据
* @author yjjie
* @date 2026/1/15 11:00
*/
@Data
@Accessors(chain = true)
public class RefundRespDTO {
/**
* 退款状态
* INIT初始化
* ING退款中
* SUCCESS退款成功
* FAIL退款失败
* CLOSE退款关闭
*/
private String status;
/**
* 退款金额
*/
private Long refundAmount;
/**
* 退款时间
*/
private String refundTime;
/**
* 三方退款订单号
*/
private String thirdRefundNo;
/**
* 商户退款订单号
*/
private String merchantRefundNo;
/**
* 退款失败原因
*/
private String errMessage;
/**
* 退款相应原始数据
*/
private String originalData;
/**
* 退款平台
*/
private String platform;
}

View File

@@ -0,0 +1,82 @@
package com.czg.system.entity;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import java.math.BigInteger;
import java.time.LocalDateTime;
import java.io.Serial;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 银行账户信息表 实体类。
*
* @author ww
* @since 2026-01-06
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table("sys_bank_info")
public class SysBankInfo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@Id(keyType = KeyType.Auto)
private BigInteger id;
/**
* 银行名称
*/
private String accountBank;
/**
* 银行数字编码
*/
private Integer accountBankCode;
/**
* 银行别名
*/
private String bankAlias;
/**
* 银行别名编码
*/
private String bankAliasCode;
/**
* 是否需要支行信息
*/
private Boolean needBankBranch;
/**
* 银行英文编码
*/
private String bankCode;
/**
* 创建时间
*/
@Column(onInsertValue = "now()")
private LocalDateTime createTime;
/**
* 更新时间
*/
@Column(onInsertValue = "now()", onUpdateValue = "now()")
private LocalDateTime updateTime;
}

View File

@@ -0,0 +1,81 @@
package com.czg.system.entity;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import java.math.BigInteger;
import java.time.LocalDateTime;
import java.io.Serial;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 类目信息表 实体类。
*
* @author ww
* @since 2026-01-06
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table("sys_category_info")
public class SysCategoryInfo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@Id(keyType = KeyType.Auto)
private BigInteger id;
/**
* 一级类目code
*/
private String firstCategoryCode;
/**
* 一级类目
*/
private String firstCategory;
/**
* 二级类目code
*/
private String secondCategoryCode;
/**
* 二级类目
*/
private String secondCategory;
/**
* 适用商家说明
*/
private String applicableMerchant;
/**
* 特殊资质(为空则无需提供)
*/
private String specialQualification;
/**
* 创建时间
*/
@Column(onInsertValue = "now()")
private LocalDateTime createTime;
/**
* 更新时间
*/
@Column(onInsertValue = "now()", onUpdateValue = "now()")
private LocalDateTime updateTime;
}

View File

@@ -0,0 +1,74 @@
package com.czg.system.entity;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import java.io.Serial;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 行政区表 实体类。
*
* @author ww
* @since 2026-01-06
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table("sys_region")
public class SysRegion implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 区域编码
*/
@Id
private String regionId;
/**
* 上级区域编码
*/
private String parentRegionId;
/**
* 区域级别1=国家2=省3=市4=县
*/
@Id
private Integer regionLevel;
/**
* 区域中文全称
*/
private String regionName;
/**
* 区域拼音
*/
private String regionPinyin;
/**
* 全级别名称(如“中国|北京|北京市|东城区)
*/
private String fullName;
/**
* 微信区域编码
*/
private String wxProvinceCode;
/**
* 子级区域
*/
@Column(ignore = true)
private List<SysRegion> children;
}

View File

@@ -0,0 +1,19 @@
package com.czg.system.service;
import com.czg.BaseQueryParam;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.service.IService;
import com.czg.system.entity.SysBankInfo;
import java.util.List;
/**
* 银行账户信息表 服务层。
*
* @author ww
* @since 2026-01-06
*/
public interface SysBankInfoService extends IService<SysBankInfo> {
Page<SysBankInfo> bankInfoList(BaseQueryParam param, String bankName);
}

View File

@@ -0,0 +1,20 @@
package com.czg.system.service;
import com.czg.system.vo.SysCategoryInfoVO;
import com.mybatisflex.core.service.IService;
import com.czg.system.entity.SysCategoryInfo;
import java.util.List;
import java.util.Map;
/**
* 类目信息表 服务层。
*
* @author ww
* @since 2026-01-06
*/
public interface SysCategoryInfoService extends IService<SysCategoryInfo> {
List<SysCategoryInfoVO> categoryList();
}

View File

@@ -0,0 +1,17 @@
package com.czg.system.service;
import com.mybatisflex.core.service.IService;
import com.czg.system.entity.SysRegion;
import java.util.List;
/**
* 行政区表 服务层。
*
* @author ww
* @since 2026-01-06
*/
public interface SysRegionService extends IService<SysRegion> {
List<SysRegion> regionList();
}

View File

@@ -0,0 +1,40 @@
package com.czg.system.vo;
import com.czg.system.entity.SysCategoryInfo;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigInteger;
import java.time.LocalDateTime;
import java.util.List;
/**
* 类目信息表 实体类。
*
* @author ww
* @since 2026-01-06
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SysCategoryInfoVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 一级类目
*/
private String firstCategory;
private List<SysCategoryInfo> child;
}

View File

@@ -37,6 +37,11 @@
</exclusion>
</exclusions>
</dependency>
<!-- 短信 -->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>dysmsapi20170525</artifactId>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
@@ -45,10 +50,6 @@
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>dysmsapi20170525</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>

View File

@@ -0,0 +1,18 @@
package com.czg.constant;
/**
* 支付渠道常量
* @author ww
*/
public interface PayChannelCst {
/**
* 聚合支付
* 对应 类 PolyPay
*/
String POLY = "poly";
/**
* 原生支付
* 对应 类 NativePay
*/
String NATIVE = "native";
}

View File

@@ -59,4 +59,8 @@ public class CzgResult<T> implements Serializable {
public static <T> CzgResult<T> failure(CzgRespCode respCode) {
return new CzgResult<>(respCode.getCode(), respCode.getMsg(), null);
}
public boolean isSuccess() {
return code == 200;
}
}