319 lines
7.4 KiB
Markdown
319 lines
7.4 KiB
Markdown
# 处方订单最小金额验证优化
|
||
|
||
## 需求说明
|
||
|
||
在创建处方订单时,如果关联的支付单总金额小于配置的最小金额(`PRESCRIPTION_ORDER_LINK_PAY_MIN_AMOUNT`),则不允许创建订单。
|
||
|
||
## 配置说明
|
||
|
||
**配置文件**:`server/.env`
|
||
|
||
```env
|
||
PRESCRIPTION_ORDER_LINK_PAY_MIN_AMOUNT="100"
|
||
```
|
||
|
||
**说明**:
|
||
- 单位:元(人民币)
|
||
- 默认值:0(不校验)
|
||
- 当前配置:100元
|
||
|
||
## 验证规则
|
||
|
||
### 修改前(原逻辑)
|
||
|
||
```
|
||
1. 订单金额 >= 最小金额 ✓
|
||
2. 每个关联支付单金额 >= 最小金额 ✓
|
||
```
|
||
|
||
**问题**:
|
||
- 要求每个支付单都必须 >= 100元
|
||
- 不允许多个小额支付单组合(如 60元 + 50元 = 110元)
|
||
|
||
### 修改后(新逻辑)
|
||
|
||
```
|
||
1. 订单金额 >= 最小金额 ✓
|
||
2. 必须关联至少一个支付单 ✓
|
||
3. 关联支付单总金额 >= 最小金额 ✓
|
||
```
|
||
|
||
**优势**:
|
||
- 允许多个小额支付单组合
|
||
- 更灵活的支付方式
|
||
- 总金额达标即可
|
||
|
||
## 代码修改
|
||
|
||
**文件**:`server/app/adminapi/logic/tcm/PrescriptionOrderLogic.php`
|
||
|
||
**方法**:`assertDepositAndLinkPayRules()`
|
||
|
||
### 修改内容
|
||
|
||
```php
|
||
public static function assertDepositAndLinkPayRules(float $orderAmount, array $payOrderIds): ?string
|
||
{
|
||
$min = self::depositMinAmount();
|
||
if ($min <= 0) {
|
||
return null;
|
||
}
|
||
|
||
// 1. 检查订单金额
|
||
if ($orderAmount < $min) {
|
||
return '订单金额须大于等于定金门槛 ¥' . $min . '(当前 ¥' . $orderAmount . ')';
|
||
}
|
||
|
||
// 2. 检查是否关联支付单
|
||
if ($payOrderIds === []) {
|
||
return '未关联支付单,关联支付单总金额须大于等于定金门槛 ¥' . $min;
|
||
}
|
||
|
||
// 3. 检查关联支付单的总金额
|
||
$rows = Order::whereIn('id', $payOrderIds)->whereNull('delete_time')->column('amount', 'id');
|
||
$totalAmount = 0.0;
|
||
foreach ($payOrderIds as $pid) {
|
||
$pid = (int) $pid;
|
||
if ($pid <= 0) {
|
||
continue;
|
||
}
|
||
$amt = round((float) ($rows[$pid] ?? 0), 2);
|
||
$totalAmount += $amt;
|
||
}
|
||
|
||
if ($totalAmount < $min) {
|
||
return '关联支付单总金额须大于等于定金门槛 ¥' . $min . '(当前总金额 ¥' . $totalAmount . ')';
|
||
}
|
||
|
||
return null;
|
||
}
|
||
```
|
||
|
||
## 验证场景
|
||
|
||
### 场景1:订单金额不足
|
||
|
||
**配置**:最小金额 = 100元
|
||
|
||
**输入**:
|
||
- 订单金额:80元
|
||
- 关联支付单:[100元]
|
||
|
||
**结果**:❌ 失败
|
||
**错误信息**:订单金额须大于等于定金门槛 ¥100(当前 ¥80)
|
||
|
||
---
|
||
|
||
### 场景2:未关联支付单
|
||
|
||
**配置**:最小金额 = 100元
|
||
|
||
**输入**:
|
||
- 订单金额:150元
|
||
- 关联支付单:[]
|
||
|
||
**结果**:❌ 失败
|
||
**错误信息**:未关联支付单,关联支付单总金额须大于等于定金门槛 ¥100
|
||
|
||
---
|
||
|
||
### 场景3:关联支付单总金额不足
|
||
|
||
**配置**:最小金额 = 100元
|
||
|
||
**输入**:
|
||
- 订单金额:150元
|
||
- 关联支付单:[30元, 40元, 20元]
|
||
- 总金额:90元
|
||
|
||
**结果**:❌ 失败
|
||
**错误信息**:关联支付单总金额须大于等于定金门槛 ¥100(当前总金额 ¥90)
|
||
|
||
---
|
||
|
||
### 场景4:多个小额支付单组合达标
|
||
|
||
**配置**:最小金额 = 100元
|
||
|
||
**输入**:
|
||
- 订单金额:150元
|
||
- 关联支付单:[60元, 50元]
|
||
- 总金额:110元
|
||
|
||
**结果**:✅ 成功
|
||
**说明**:虽然单个支付单都小于100元,但总金额达标
|
||
|
||
---
|
||
|
||
### 场景5:单个大额支付单
|
||
|
||
**配置**:最小金额 = 100元
|
||
|
||
**输入**:
|
||
- 订单金额:150元
|
||
- 关联支付单:[120元]
|
||
- 总金额:120元
|
||
|
||
**结果**:✅ 成功
|
||
|
||
---
|
||
|
||
### 场景6:配置为0(不校验)
|
||
|
||
**配置**:最小金额 = 0元
|
||
|
||
**输入**:
|
||
- 订单金额:10元
|
||
- 关联支付单:[]
|
||
|
||
**结果**:✅ 成功
|
||
**说明**:最小金额为0时,不进行任何校验
|
||
|
||
---
|
||
|
||
### 场景7:多个支付单,总金额刚好达标
|
||
|
||
**配置**:最小金额 = 100元
|
||
|
||
**输入**:
|
||
- 订单金额:150元
|
||
- 关联支付单:[30元, 30元, 40元]
|
||
- 总金额:100元
|
||
|
||
**结果**:✅ 成功
|
||
**说明**:总金额刚好等于最小金额,符合"大于等于"的要求
|
||
|
||
## 前端提示优化
|
||
|
||
**文件**:`admin/src/views/consumer/prescription/order_list.vue`
|
||
|
||
**当前提示**:
|
||
```
|
||
支付单审核时可对照此处关联的收款记录。
|
||
列表仅展示金额大于等于定金门槛的收款单(门槛为 0 时展示全部)。
|
||
```
|
||
|
||
**建议修改为**:
|
||
```
|
||
支付单审核时可对照此处关联的收款记录。
|
||
关联支付单总金额须大于等于定金门槛(当前门槛:¥100)。
|
||
列表仅展示金额大于等于定金门槛的收款单(门槛为 0 时展示全部)。
|
||
```
|
||
|
||
## 配置管理
|
||
|
||
### 查看当前配置
|
||
|
||
```bash
|
||
# 查看 .env 文件
|
||
cat server/.env | grep PRESCRIPTION_ORDER_LINK_PAY_MIN_AMOUNT
|
||
```
|
||
|
||
### 修改配置
|
||
|
||
```bash
|
||
# 编辑 .env 文件
|
||
vim server/.env
|
||
|
||
# 修改为 200 元
|
||
PRESCRIPTION_ORDER_LINK_PAY_MIN_AMOUNT="200"
|
||
|
||
# 修改为 0(不校验)
|
||
PRESCRIPTION_ORDER_LINK_PAY_MIN_AMOUNT="0"
|
||
```
|
||
|
||
### 配置生效
|
||
|
||
修改 `.env` 文件后,配置会立即生效,无需重启服务。
|
||
|
||
## 业务逻辑说明
|
||
|
||
### 为什么需要最小金额限制?
|
||
|
||
1. **定金机制**:确保客户已支付足够的定金
|
||
2. **风险控制**:避免小额订单的履约风险
|
||
3. **业务规范**:统一订单金额标准
|
||
|
||
### 为什么改为总金额验证?
|
||
|
||
1. **灵活性**:允许客户分多次支付
|
||
2. **用户体验**:不强制单次支付大额
|
||
3. **实际需求**:多次小额支付也能达到定金要求
|
||
|
||
### 为什么必须关联支付单?
|
||
|
||
1. **资金确认**:确保订单有对应的收款记录
|
||
2. **审核依据**:支付单审核时需要对照
|
||
3. **财务管理**:便于对账和统计
|
||
|
||
## 测试建议
|
||
|
||
### 1. 单元测试
|
||
|
||
```php
|
||
// 测试订单金额不足
|
||
$result = PrescriptionOrderLogic::assertDepositAndLinkPayRules(80, [1]);
|
||
assert($result !== null);
|
||
|
||
// 测试未关联支付单
|
||
$result = PrescriptionOrderLogic::assertDepositAndLinkPayRules(150, []);
|
||
assert($result !== null);
|
||
|
||
// 测试总金额不足
|
||
$result = PrescriptionOrderLogic::assertDepositAndLinkPayRules(150, [1, 2]); // 假设总金额 < 100
|
||
assert($result !== null);
|
||
|
||
// 测试总金额达标
|
||
$result = PrescriptionOrderLogic::assertDepositAndLinkPayRules(150, [3, 4]); // 假设总金额 >= 100
|
||
assert($result === null);
|
||
```
|
||
|
||
### 2. 集成测试
|
||
|
||
1. 创建多个小额支付单(如 60元、50元)
|
||
2. 创建订单,关联这些支付单
|
||
3. 验证是否能成功创建
|
||
4. 验证错误提示是否正确
|
||
|
||
### 3. 边界测试
|
||
|
||
- 总金额刚好等于最小金额(100元)
|
||
- 总金额略小于最小金额(99.99元)
|
||
- 总金额略大于最小金额(100.01元)
|
||
- 最小金额为0
|
||
- 最小金额为负数(应该按0处理)
|
||
|
||
## 相关文件
|
||
|
||
### 配置文件
|
||
- `server/.env` - 环境配置
|
||
- `server/config/prescription_order.php` - 订单配置
|
||
|
||
### 后端文件
|
||
- `server/app/adminapi/logic/tcm/PrescriptionOrderLogic.php` - 订单逻辑
|
||
- `server/app/adminapi/validate/tcm/PrescriptionOrderValidate.php` - 订单验证
|
||
|
||
### 前端文件
|
||
- `admin/src/views/consumer/prescription/order_list.vue` - 订单列表页面
|
||
|
||
## 总结
|
||
|
||
✅ 修改验证逻辑:从"每个支付单"改为"支付单总金额"
|
||
✅ 添加必须关联支付单的验证
|
||
✅ 优化错误提示信息,显示当前总金额
|
||
✅ 支持多个小额支付单组合
|
||
✅ 保持订单金额验证不变
|
||
✅ 配置为0时不进行校验
|
||
|
||
**优势**:
|
||
- 更灵活的支付方式
|
||
- 更好的用户体验
|
||
- 更清晰的错误提示
|
||
- 更符合实际业务需求
|
||
|
||
**下一步**:
|
||
1. 测试各种场景
|
||
2. 更新前端提示文字
|
||
3. 编写单元测试
|
||
4. 更新用户文档
|