vr-shopxo-plugin/docs/08_SHOPXO_REQUIREMENTS_MAPP...

173 lines
6.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# vr-shopxo-plugin 需求对照分析
> ShopXO 插件机制 vs VR 演唱会票务需求
> 基于 shopxo-plugin-dev.md 整理
---
## 一、票务核心功能 vs ShopXO 机制
### 1. 商品模型(票 = item_type='ticket'
ShopXO 原生商品表 `item``item_type` 字段扩展能力,但票务的特殊性在于:
- 票有时间场次session普通商品无此概念
- 票需要观演人信息,普通商品无此字段
- 票需要 QR 电子票,普通商品无此交付物
**结论**:票务插件需创建独立表 `vr_events` + `vr_sessions` + `vr_tickets`,与 ShopXO `items` 表平行存在,通过 `item_id` 关联。
### 2. 库存扣减(防超卖)
ShopXO 原生库存扣减SELECT → UPDATE 两步,非原子操作,有超卖风险。
**VR 票务方案**:在支付回调 `api/notify` 中,使用 Postgres 风格 SQLShopXO 是 MySQL需换为 MySQL 原子写法):
```sql
-- MySQL 原子扣库存FOR UPDATE SKIP LOCKED 等效写法)
START TRANSACTION;
SELECT stock FROM vr_sessions WHERE id=? AND stock>=? FOR UPDATE;
-- 如果库存足够
UPDATE vr_sessions SET stock=stock-? WHERE id=?;
INSERT INTO vr_tickets (...) VALUES (...);
COMMIT;
```
**关键**:必须在支付回调的 API 控制器中完成,不能依赖 ShopXO 原有订单流程。
### 3. 微信支付回调
ShopXO 支持支付插件机制(`extend/payment/`),但票务插件需要自己的支付回调路由:
```
POST /plugins/api?pluginsname=vr_ticket&pluginscontrol=api&pluginsaction=notify
```
ShopXO 原生支付回调由支付插件处理,票务插件的回调是:**用户付款成功 → 票务插件生成电子票**。
**注意**ShopXO 的微信支付插件本身已处理微信支付回调,我们需要在 `Event.php` 中监听支付成功事件或在回调路由中自己调用微信API验证。
### 4. 观演人信息
ShopXO 订单扩展字段能力有限,建议:
- 创建 `vr_attendees` 表(姓名、手机、证件号)
- 在订单 `paid` 状态的 webhook 或手动触发时写入
- 通过订单扩展字段 `extension`JSON关联 `vr_attendees`
### 5. QR 电子票
ShopXO 附件上传/管理能力完善,但 QR 生成需自己实现:
- PHP QR Code`phpqrcode/phpqrcode` Composer 包
- 存储:`vr_tickets.qr_data` 存 QR 内容AES_EncryptQR 图片可 CDN 化
### 6. B 端扫码核销
ShopXO 后台有门店核销机制(多门店插件),但票务核销是独立场景:
- 插件后台:`admin/verify` 控制器
- 扫码枪:调用微信扫一扫或直接输入 QR code
- 核销状态更新:`vr_tickets.status = 'used'`
---
## 二、ShopXO 原有功能借用分析
| 票务需求 | ShopXO 原生能力 | 插件扩展方式 | 优先级 |
|---------|---------------|------------|--------|
| 商品展示 | ✅ items 表 | 创建 vr_events 场次表 | P0 |
| 会员体系 | ✅ 完善 | 不需开发 | P0 |
| 钱包/余额 | ✅ 完善 | 不需开发 | P0 |
| 优惠券 | ✅ 完善 | 不需开发 | P0 |
| 微信支付 | ✅ 支付插件 | 直接用(不需改) | P0 |
| 订单管理 | ✅ orders 表 | 扩展 extension 字段 | P0 |
| 库存扣减 | ⚠️ 非原子 | 支付回调自己写 | P0 |
| 场次/SKU | ❌ 无 | 独立表 vr_sessions | P0 |
| 观演人信息 | ❌ 无 | 独立表 vr_attendees | P0 |
| QR 电子票 | ❌ 无 | phpqrcode + 插件表 | P0 |
| B端核销 | ❌ 无 | 插件后台 admin 页面 | P1 |
| 多场馆 | ❌ 无 | vr_events 已有场馆字段 | P2 |
| 周边商品 | ✅ items 原生 | 不需插件 | P0 |
---
## 三、插件架构设计
### 数据库 E-R 图
```
vr_events (场次)
└── vr_sessions (场次时间/库存) 1:N
└── vr_tickets (电子票) 1:N
└── vr_attendees (观演人) N:1
items (ShopXO原生) ←── item_id ──→ vr_events (通过 item_id 关联)
orders (ShopXO原生) ←─ extension ──→ vr_attendees (JSON关联)
```
### 插件目录
```
app/plugins/vr_ticket/
├── config.json # 插件配置(钩子:支付回调)
├── admin/
│ ├── controller/
│ │ ├── Event.php # 场次管理 CRUD
│ │ ├── Ticket.php # 电子票管理
│ │ └── Verify.php # 核销管理
│ └── view/
│ ├── event/ # 场次管理视图
│ ├── ticket/
│ └── verify/ # 核销页面
├── index/
│ ├── controller/
│ │ ├── Index.php # 前台插件首页
│ │ └── Ticket.php # 我的票/QR展示
│ └── view/
│ ├── ticket/
│ └── my_tickets.blade.php
├── api/
│ └── controller/
│ └── Notify.php # ★ 支付回调(最关键)
├── service/
│ └── BaseService.php
├── Event.php # 生命周期事件
├── common.php
└── hook/
└── OrderPaid.php # 订单支付成功钩子(可选)
```
### 支付回调流程
```
微信支付回调 → /plugins/api?pluginsname=vr_ticket&pluginscontrol=api&pluginsaction=notify
├─ 1. 验证签名微信API
├─ 2. 查询 ShopXO orders 表确认支付状态
├─ 3. 读取订单 extension 中的 vr_session_id + vr_attendees
├─ 4. 原子扣库存vr_sessions
├─ 5. 生成 vr_ticketsAES_Encrypt QR content
├─ 6. 写入 vr_attendees 记录
└─ 7. 更新 orders.extension票ID列表
```
---
## 四、已知限制与绕过方案
| 限制 | 影响 | 绕过方案 |
|------|------|---------|
| ShopXO 订单流程不可扩展 | 无法在原生下单流程中插入观演人表单 | 独立购票页,支付后写入观演人 |
| 支付回调由支付插件处理 | 票务插件无法直接拦截微信回调 | 支付插件 → Event.PaySuccess → 票务钩子 |
| 插件不能 Hook 订单状态变更 | 无法监听 paid→fulfilled | 支付回调中直接处理,或定时轮询 |
| DIY 拖拽装修不可代码化 | 票务展示页无法 AI 生成 | 票务页面全部走插件视图,不走 DIY |
| MySQL 非 Postgres | 无 FOR UPDATE SKIP LOCKED | START TRANSACTION + SELECT ... FOR UPDATE |
---
## 五、下一步行动
1. **先确认支付插件的 PaySuccess 事件** — 从 `extend/payment/` 源码确认是否触发 Event.PaySuccess
2. **创建插件骨架** — config.json + BaseService + Event.php
3. **设计数据库迁移脚本** — vr_events, vr_sessions, vr_tickets, vr_attendees
4. **实现支付回调** — api/Notify.php核心链路
---