|
|
@@ -0,0 +1,101 @@
|
|
|
+# 夜市摊位抽成设计
|
|
|
+
|
|
|
+## 背景
|
|
|
+
|
|
|
+现有抽成模式:平台从商家(userType=1)每笔交易中按 `commission` 比例收取佣金,收入入商家个人钱包。
|
|
|
+
|
|
|
+新增夜市层级后,交易主体变为摊位(PosStore, isStall=1),摊位归属夜市(InfoUser, userType=3)管理。摊位可能有多个摊位主,钱包是门店维度的,不是个人维度的。
|
|
|
+
|
|
|
+## 业务规则
|
|
|
+
|
|
|
+- 平台从摊位每笔交易中收取佣金,比例由所属夜市统一设定
|
|
|
+- 夜市不参与交易抽成,只线下收取摊位费
|
|
|
+- 抽成比例存在夜市用户的 `commission` 字段上,下属所有摊位统一使用
|
|
|
+- 资金流向:交易额 - 平台抽成 = 摊位到手,平台直接扣除
|
|
|
+- 摊位收入进入摊位门店钱包(UserWallet.storeId 关联),不进摊位主个人钱包
|
|
|
+
|
|
|
+## 技术设计
|
|
|
+
|
|
|
+### 改动范围
|
|
|
+
|
|
|
+| 改动 | 文件 |
|
|
|
+|------|------|
|
|
|
+| 抽成判断逻辑 | `PosOrderController.setSanghuBilling()` |
|
|
|
+| 摊位钱包更新 | `WalletService` 新增摊位钱包操作方法 |
|
|
|
+| 账单关联摊位 | `UserBilling` 新增 `storeId` 字段 |
|
|
|
+| 数据库 | `user_billing` 表新增 `store_id` 列 |
|
|
|
+
|
|
|
+### 1. 抽成判断逻辑
|
|
|
+
|
|
|
+修改 `PosOrderController.setSanghuBilling()`:
|
|
|
+
|
|
|
+```
|
|
|
+PosStore store = posStoreService.getById(posOrder.getMdId())
|
|
|
+if (store.getIsStall() == 1 && store.getNightMarketId() != null) {
|
|
|
+ // 摊位订单:用夜市的抽成比例
|
|
|
+ InfoUser nightMarket = infoUserService.getById(store.getNightMarketId())
|
|
|
+ fcbili = nightMarket.getCommission() == null ? 0.00 : nightMarket.getCommission()
|
|
|
+} else {
|
|
|
+ // 普通商家:保持原逻辑
|
|
|
+ InfoUser user = infoUserService.getById(posOrder.getShId())
|
|
|
+ fcbili = user.getCommission() == null ? 0.00 : user.getCommission()
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+后续计算不变:`chouc = fenc * fcbili`,`shfc = fenc - chouc`。
|
|
|
+
|
|
|
+### 2. 账单记录
|
|
|
+
|
|
|
+`user_billing` 表新增 `store_id` 列(BIGINT, NULL, 默认NULL)。
|
|
|
+
|
|
|
+摊位订单账单记录:
|
|
|
+
|
|
|
+| 字段 | 值 | 说明 |
|
|
|
+|------|-----|------|
|
|
|
+| userId | shId(夜市ID) | 标识交易归属哪个夜市 |
|
|
|
+| mdId | 摊位门店ID | 标识哪个摊位的交易 |
|
|
|
+| storeId | 摊位门店ID | 关联摊位钱包(新增字段) |
|
|
|
+| amount | shfc | 摊位到手金额 |
|
|
|
+| divvy | chouc | 平台抽成金额 |
|
|
|
+| divvyRate | fcbili | 抽成比例 |
|
|
|
+
|
|
|
+普通商家订单不受影响,`storeId` 为 NULL。
|
|
|
+
|
|
|
+### 3. 钱包更新
|
|
|
+
|
|
|
+`WalletService` 新增摊位钱包操作方法 `addStallBalance(Long storeId, BigDecimal amount, UserBilling billing)`:
|
|
|
+
|
|
|
+```
|
|
|
+1. 通过 storeId 查找 UserWallet(WHERE store_id = ?)
|
|
|
+2. 加分布式锁
|
|
|
+3. 乐观锁更新钱包余额(与现有 addBalance 逻辑相同)
|
|
|
+4. 创建账单记录(billing.storeId 已设置)
|
|
|
+```
|
|
|
+
|
|
|
+`setSanghuBilling()` 中的调用变更:
|
|
|
+
|
|
|
+```
|
|
|
+if (isStall) {
|
|
|
+ billing.setStoreId(store.getId())
|
|
|
+ walletService.addStallBalance(store.getId(), amount, billing)
|
|
|
+} else {
|
|
|
+ walletService.addBalance(userId, amount, billing) // 原逻辑不变
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 4. 数据模型
|
|
|
+
|
|
|
+仅一个数据库变更:
|
|
|
+
|
|
|
+```sql
|
|
|
+ALTER TABLE user_billing ADD COLUMN store_id BIGINT DEFAULT NULL COMMENT '关联摊位ID,非摊位账单为NULL';
|
|
|
+```
|
|
|
+
|
|
|
+复用现有字段:
|
|
|
+
|
|
|
+| 字段 | 所在实体 | 用途 |
|
|
|
+|------|---------|------|
|
|
|
+| commission | InfoUser (夜市) | 夜市设定的平台抽成比例 |
|
|
|
+| isStall | PosStore | 判断是否为摊位(1=摊位) |
|
|
|
+| nightMarketId | PosStore | 摊位关联的夜市用户ID |
|
|
|
+| storeId | UserWallet | 摊位钱包关联的门店ID(已有) |
|