334 lines
7.7 KiB
Markdown
334 lines
7.7 KiB
Markdown
# 07 典型业务流程:落表路径与关键字段
|
||
|
||
本节用“业务步骤 → 涉及表 → 关键字段/约束/触发器”的方式,把核心链路讲清楚,方便新同事快速理解数据如何流动。
|
||
|
||
---
|
||
|
||
## 1. 商品发布与上架流程(商家侧)
|
||
|
||
### 1.1 创建 SPU(商品主表)
|
||
|
||
- **写入表**:`ml_products`
|
||
- **关键字段**:
|
||
- `merchant_id`:商家用户(关联 `ak_users.id`)
|
||
- `category_id/brand_id`
|
||
- `base_price`
|
||
- `status`:初始可为草稿(3)或上架(1)
|
||
- `cid/slug`:对外访问
|
||
|
||
示例(简化):
|
||
|
||
```sql
|
||
insert into public.ml_products(
|
||
merchant_id, category_id, product_code, name, base_price, status
|
||
)
|
||
values (
|
||
'...merchant_uuid...'::uuid,
|
||
'...category_uuid...'::uuid,
|
||
'P20260001',
|
||
'苹果手机',
|
||
4999.00,
|
||
3
|
||
)
|
||
returning id, cid;
|
||
```
|
||
|
||
### 1.2 定义规格项(可选)
|
||
|
||
- **写入表**:`ml_product_specs`
|
||
- **关键字段**:`spec_name`、`spec_values JSONB`
|
||
|
||
示例:
|
||
|
||
```sql
|
||
insert into public.ml_product_specs(product_id, spec_name, spec_values)
|
||
values
|
||
('...product_uuid...'::uuid, '颜色', '["黑","白"]'::jsonb),
|
||
('...product_uuid...'::uuid, '容量', '["128G","256G"]'::jsonb);
|
||
```
|
||
|
||
### 1.3 创建 SKU(库存与具体价格)
|
||
|
||
- **写入表**:`ml_product_skus`
|
||
- **关键字段**:`specifications JSONB`、`price`、`stock`、`status`
|
||
- **数据库规则**:
|
||
- SKU 变更会触发 `update_product_stock()`,自动汇总刷新 `ml_products.total_stock/available_stock`
|
||
|
||
示例:
|
||
|
||
```sql
|
||
insert into public.ml_product_skus(product_id, sku_code, specifications, price, stock)
|
||
values
|
||
(
|
||
'...product_uuid...'::uuid,
|
||
'SKU-001',
|
||
'{"颜色":"黑","容量":"128G"}'::jsonb,
|
||
4999.00,
|
||
10
|
||
);
|
||
|
||
-- 插入 SKU 后,触发器会把商品 total_stock/available_stock 更新为 10
|
||
```
|
||
|
||
### 1.4 上架商品
|
||
|
||
- **更新表**:`ml_products`
|
||
- **关键字段**:`status = 1`、`published_at`(若使用)
|
||
|
||
示例:
|
||
|
||
```sql
|
||
update public.ml_products
|
||
set status = 1, published_at = now()
|
||
where id = '...product_uuid...'::uuid;
|
||
```
|
||
|
||
---
|
||
|
||
## 2. 浏览与收藏(用户侧)
|
||
|
||
### 2.1 浏览记录
|
||
|
||
- **写入表**:`ml_browse_history`
|
||
- **约束**:`UNIQUE(user_id, product_id)`
|
||
- **含义**:倾向记录“最后一次浏览”而不是“浏览流水”。
|
||
|
||
典型写法:
|
||
|
||
- 插入失败后转更新(upsert)
|
||
|
||
```sql
|
||
insert into public.ml_browse_history(user_id, product_id, browse_duration)
|
||
values ('...user_uuid...'::uuid, '...product_uuid...'::uuid, 20)
|
||
on conflict (user_id, product_id)
|
||
do update set browse_duration = excluded.browse_duration, updated_at = now();
|
||
```
|
||
|
||
### 2.2 收藏
|
||
|
||
- **写入表**:`ml_user_favorites`
|
||
- **约束**:`UNIQUE(user_id, target_type, target_id)`
|
||
|
||
```sql
|
||
insert into public.ml_user_favorites(user_id, target_type, target_id)
|
||
values ('...user_uuid...'::uuid, 1, '...product_uuid...'::uuid)
|
||
on conflict do nothing;
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 加购与结算(用户侧)
|
||
|
||
### 3.1 加入购物车
|
||
|
||
- **写入表**:`ml_shopping_cart`
|
||
- **约束**:`UNIQUE(user_id, product_id, sku_id)`
|
||
|
||
常见做法:重复加购时做累加:
|
||
|
||
```sql
|
||
insert into public.ml_shopping_cart(user_id, product_id, sku_id, quantity, selected)
|
||
values ('...user_uuid...'::uuid, '...product_uuid...'::uuid, '...sku_uuid...'::uuid, 1, true)
|
||
on conflict (user_id, product_id, sku_id)
|
||
do update set quantity = public.ml_shopping_cart.quantity + 1, updated_at = now();
|
||
```
|
||
|
||
### 3.2 计算购物车金额
|
||
|
||
- **读取函数**:`public.calculate_cart_total(p_user_id)`
|
||
|
||
```sql
|
||
select public.calculate_cart_total('...user_uuid...'::uuid);
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 下单(创建订单 + 明细快照)
|
||
|
||
### 4.1 订单号生成
|
||
|
||
- **函数**:`public.generate_order_no()`(基于 `ml_order_seq`)
|
||
|
||
```sql
|
||
select public.generate_order_no();
|
||
```
|
||
|
||
### 4.2 创建订单主表(地址快照)
|
||
|
||
- **写入表**:`ml_orders`
|
||
- **关键字段**:
|
||
- `shipping_address JSONB`:下单时把地址“快照化”写进订单
|
||
- `order_status/payment_status/shipping_status`
|
||
|
||
示例(简化):
|
||
|
||
```sql
|
||
insert into public.ml_orders(
|
||
order_no, user_id, merchant_id,
|
||
product_amount, discount_amount, shipping_fee, total_amount,
|
||
shipping_address,
|
||
order_status, payment_status, shipping_status
|
||
)
|
||
values (
|
||
public.generate_order_no(),
|
||
'...user_uuid...'::uuid,
|
||
'...merchant_uuid...'::uuid,
|
||
4999.00, 0.00, 10.00, 5009.00,
|
||
'{"receiver":"张三","phone":"138...","province":"广东","city":"深圳","district":"南山","detail":"xxx"}'::jsonb,
|
||
1, 1, 1
|
||
)
|
||
returning id;
|
||
```
|
||
|
||
### 4.3 创建订单明细(商品快照)
|
||
|
||
- **写入表**:`ml_order_items`
|
||
- **关键点**:把 `product_name/sku_name/specifications/image_url/price` 等写入明细,防止商品后改影响历史。
|
||
|
||
```sql
|
||
insert into public.ml_order_items(
|
||
order_id, product_id, sku_id,
|
||
product_name, sku_name, specifications, image_url,
|
||
price, quantity, total_amount
|
||
)
|
||
values (
|
||
'...order_uuid...'::uuid,
|
||
'...product_uuid...'::uuid,
|
||
'...sku_uuid...'::uuid,
|
||
'苹果手机',
|
||
'黑/128G',
|
||
'{"颜色":"黑","容量":"128G"}'::jsonb,
|
||
'https://.../1.png',
|
||
4999.00,
|
||
1,
|
||
4999.00
|
||
);
|
||
```
|
||
|
||
> 注意:当前可见 SQL 未体现“扣库存/冻结库存”动作,通常需要在同一事务中由应用层或额外 DB 函数完成(详见 `08_data_consistency_boundaries.md`)。
|
||
|
||
---
|
||
|
||
## 5. 支付、发货、完成(状态流转)
|
||
|
||
### 5.1 支付完成
|
||
|
||
- **更新表**:`ml_orders`
|
||
- **预期**:`order_status: 1 -> 2`,并写 `paid_amount/payment_status`
|
||
- **数据库副作用(complete 脚本)**:触发器 `handle_order_status_change()` 自动写 `paid_at`
|
||
|
||
```sql
|
||
update public.ml_orders
|
||
set order_status = 2,
|
||
payment_status = 2,
|
||
paid_amount = total_amount
|
||
where id = '...order_uuid...'::uuid;
|
||
```
|
||
|
||
### 5.2 发货
|
||
|
||
```sql
|
||
update public.ml_orders
|
||
set order_status = 3,
|
||
shipping_status = 2
|
||
where id = '...order_uuid...'::uuid;
|
||
|
||
-- complete 脚本的触发器会在 2->3 时写 shipped_at
|
||
```
|
||
|
||
### 5.3 收货完成
|
||
|
||
```sql
|
||
update public.ml_orders
|
||
set order_status = 4,
|
||
shipping_status = 4
|
||
where id = '...order_uuid...'::uuid;
|
||
|
||
-- complete 脚本触发器在 3->4 时写 delivered_at/completed_at,并累计商品 sale_count
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 评价
|
||
|
||
- **写入表**:`ml_product_reviews`
|
||
- **约束设计**:强绑定 `order_id` 与 `order_item_id`,保证评价来自真实订单。
|
||
|
||
```sql
|
||
insert into public.ml_product_reviews(
|
||
order_id, order_item_id, user_id, product_id, merchant_id,
|
||
rating, content, images
|
||
)
|
||
values (
|
||
'...order_uuid...'::uuid,
|
||
'...order_item_uuid...'::uuid,
|
||
'...user_uuid...'::uuid,
|
||
'...product_uuid...'::uuid,
|
||
'...merchant_uuid...'::uuid,
|
||
5,
|
||
'很好用',
|
||
'["https://.../a.png"]'::jsonb
|
||
);
|
||
```
|
||
|
||
---
|
||
|
||
## 7. 优惠券:发放与使用
|
||
|
||
### 7.1 领券
|
||
|
||
- **写入表**:`ml_user_coupons`
|
||
- **券码**:可使用 `generate_coupon_code()` 生成
|
||
|
||
```sql
|
||
insert into public.ml_user_coupons(user_id, template_id, coupon_code, status, expire_at)
|
||
values (
|
||
'...user_uuid...'::uuid,
|
||
'...template_uuid...'::uuid,
|
||
public.generate_coupon_code(),
|
||
1,
|
||
now() + interval '30 days'
|
||
);
|
||
```
|
||
|
||
### 7.2 用券归因
|
||
|
||
```sql
|
||
update public.ml_user_coupons
|
||
set status = 2,
|
||
used_at = now(),
|
||
order_id = '...order_uuid...'::uuid
|
||
where id = '...user_coupon_uuid...'::uuid
|
||
and status = 1;
|
||
```
|
||
|
||
---
|
||
|
||
## 8. 订阅:开通/续费/到期
|
||
|
||
### 8.1 创建套餐
|
||
|
||
- `ml_subscription_plans`
|
||
|
||
```sql
|
||
insert into public.ml_subscription_plans(plan_code, name, price, billing_period)
|
||
values ('PRO_MONTH', '专业版(月付)', 99.00, 'monthly');
|
||
```
|
||
|
||
### 8.2 用户订阅
|
||
|
||
- `ml_user_subscriptions`
|
||
|
||
```sql
|
||
insert into public.ml_user_subscriptions(user_id, plan_id, status, start_date, next_billing_date)
|
||
values (
|
||
'...user_uuid...'::uuid,
|
||
'...plan_uuid...'::uuid,
|
||
'trial',
|
||
now(),
|
||
now() + interval '30 days'
|
||
);
|
||
```
|
||
|
||
> 说明:订阅模块脚本未与 `ml_orders` 建立外键关联,支付/对账链路通常在应用层或另一个交易子系统实现。
|