# 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` 建立外键关联,支付/对账链路通常在应用层或另一个交易子系统实现。