- 新增订单列表页面UI,支持状态筛选和搜索功能 - 新增订单删除API接口,支持用户软删除已完成/已取消订单 - 新增订单详情接口返回商品列表和联系信息 - 新增多个图标资源和API接口 - 修改上传配置和订单相关逻辑
395 行
16 KiB
PHP
395 行
16 KiB
PHP
<?php
|
||
|
||
define('APP_PATH', __DIR__ . '/../server/application/');
|
||
require __DIR__ . '/../server/thinkphp/base.php';
|
||
\think\App::initCommon();
|
||
|
||
use think\Db;
|
||
use app\common\library\OrderStatus;
|
||
use app\api\controller\Home;
|
||
use app\api\controller\Order;
|
||
|
||
echo "========================================================\n";
|
||
echo " 优匠优服(YJYF)业务全链路自动化集成测试套件 \n";
|
||
echo "========================================================\n\n";
|
||
|
||
$userId = 1;
|
||
$master = Db::name('master')->where('id', 1)->find();
|
||
$masterId = (int)$master['id'];
|
||
$initialMasterMoney = (float)$master['money'];
|
||
|
||
echo ">> 测试基础环境:\n";
|
||
echo " 用户ID: {$userId}\n";
|
||
echo " 师傅ID: {$masterId} ({$master['realname']}),初始余额: ¥{$initialMasterMoney}\n\n";
|
||
|
||
// 辅助断言函数
|
||
function assertTest($condition, $message) {
|
||
if ($condition) {
|
||
echo " [PASS] {$message}\n";
|
||
} else {
|
||
echo " [FAIL] {$message}\n";
|
||
exit(1);
|
||
}
|
||
}
|
||
|
||
// -----------------------------------------------------------------------------
|
||
// 用例一:一口价工单全链路(下单->支付->抢单->首联->预约->到达->开工->增项补差->完工->验证码核销->结算分账)
|
||
// -----------------------------------------------------------------------------
|
||
echo ">> [用例一] 一口价标准工单全生命周期测试:\n";
|
||
|
||
// 1. 创建地址
|
||
$addrId = Db::name('address')->insertGetId([
|
||
'user_id' => $userId,
|
||
'contact' => '自动化测试业主',
|
||
'mobile' => '13800000001',
|
||
'province' => '贵州省',
|
||
'city' => '贵阳市',
|
||
'district' => '观山湖区',
|
||
'address' => '金融城MAX-C座1001',
|
||
'lng' => '106.65',
|
||
'lat' => '26.62',
|
||
'floor' => 3,
|
||
'has_elevator' => 0,
|
||
'createtime' => time(),
|
||
'updatetime' => time(),
|
||
]);
|
||
|
||
// 2. 算费与下单
|
||
$service = Db::name('service')->where('id', 1)->find();
|
||
$amount = Home::calcAmount($service, ['floor' => 3, 'has_elevator' => 0, 'urgent' => 1], 0, $userId, 'fixed', 0);
|
||
assertTest($amount['pay_amount'] > 0, "算费成功,一口价预估支付金额: ¥{$amount['pay_amount']}");
|
||
|
||
$orderNo = 'TEST' . date('YmdHis') . mt_rand(100, 999);
|
||
$verifyCode = '8899';
|
||
$orderId = Db::name('order')->insertGetId([
|
||
'order_no' => $orderNo,
|
||
'user_id' => $userId,
|
||
'master_id' => 0,
|
||
'cat_id' => (int)$service['cat_id'],
|
||
'service_id' => (int)$service['id'],
|
||
'service_name' => $service['name'],
|
||
'price_type' => 'fixed',
|
||
'goods_num' => 1,
|
||
'floor' => 3,
|
||
'has_elevator' => 0,
|
||
'urgent' => 1,
|
||
'contact' => '自动化测试业主',
|
||
'mobile' => '13800000001',
|
||
'province' => '贵州省',
|
||
'city' => '贵阳市',
|
||
'district' => '观山湖区',
|
||
'address' => '金融城MAX-C座1001',
|
||
'lng' => '106.65',
|
||
'lat' => '26.62',
|
||
'base_amount' => $amount['base_amount'],
|
||
'floor_amount' => $amount['floor_amount'],
|
||
'urgent_amount' => $amount['urgent_amount'],
|
||
'total_amount' => $amount['total_amount'],
|
||
'pay_amount' => $amount['pay_amount'],
|
||
'status' => OrderStatus::PENDING_PAY,
|
||
'pay_status' => 0,
|
||
'verify_code' => $verifyCode,
|
||
'createtime' => time(),
|
||
'updatetime' => time(),
|
||
]);
|
||
assertTest($orderId > 0, "创建订单成功,订单号: {$orderNo}, ID: {$orderId}, 状态: 待支付(0)");
|
||
|
||
// 3. 模拟支付
|
||
Db::name('order')->where('id', $orderId)->update([
|
||
'status' => OrderStatus::PENDING_ACCEPT,
|
||
'pay_status' => 1,
|
||
'pay_time' => time(),
|
||
'pay_type' => 'wechat',
|
||
]);
|
||
$order = Db::name('order')->where('id', $orderId)->find();
|
||
assertTest((int)$order['status'] === OrderStatus::PENDING_ACCEPT, "支付完成,订单推入大厅,状态: 待接单(1)");
|
||
|
||
// 4. 师傅抢单 (乐观行锁)
|
||
$affected = Db::name('order')
|
||
->where('id', $orderId)
|
||
->where('status', OrderStatus::PENDING_ACCEPT)
|
||
->where('master_id', 0)
|
||
->update([
|
||
'master_id' => $masterId,
|
||
'status' => OrderStatus::ACCEPTED,
|
||
'accept_time' => time(),
|
||
'updatetime' => time(),
|
||
]);
|
||
assertTest($affected === 1, "师傅抢单成功,乐观锁排他更新成功,状态: 已接单(3)");
|
||
|
||
// 5. 师傅首联打卡
|
||
Db::name('order')->where('id', $orderId)->update([
|
||
'contact_time' => time(),
|
||
'updatetime' => time(),
|
||
]);
|
||
$order = Db::name('order')->where('id', $orderId)->find();
|
||
assertTest((int)$order['contact_time'] > 0, "师傅2小时内首联打卡成功,记录 contact_time");
|
||
|
||
// 6. 约定上门时间
|
||
$appointTime = time() + 7200;
|
||
Db::name('order')->where('id', $orderId)->update([
|
||
'appoint_time' => $appointTime,
|
||
'status' => OrderStatus::SCHEDULED,
|
||
'updatetime' => time(),
|
||
]);
|
||
$order = Db::name('order')->where('id', $orderId)->find();
|
||
assertTest((int)$order['status'] === OrderStatus::SCHEDULED, "约定上门时间成功,状态: 待上门(4)");
|
||
|
||
// 7. 到达打卡
|
||
Db::name('order')->where('id', $orderId)->update([
|
||
'arrive_time' => time(),
|
||
'status' => OrderStatus::ARRIVED,
|
||
'updatetime' => time(),
|
||
]);
|
||
$order = Db::name('order')->where('id', $orderId)->find();
|
||
assertTest((int)$order['status'] === OrderStatus::ARRIVED, "师傅到达现场打卡,状态: 已到达(5)");
|
||
|
||
// 8. 师傅开工
|
||
Db::name('order')->where('id', $orderId)->update([
|
||
'start_time' => time(),
|
||
'status' => OrderStatus::WORKING,
|
||
'updatetime' => time(),
|
||
]);
|
||
$order = Db::name('order')->where('id', $orderId)->find();
|
||
assertTest((int)$order['status'] === OrderStatus::WORKING, "师傅确认开始施工,状态: 服务中(6)");
|
||
|
||
// 9. 现场增项加价与用户补差价支付
|
||
$diffFee = 30.00;
|
||
Db::name('order')->where('id', $orderId)->update([
|
||
'diff_amount' => $diffFee,
|
||
'diff_status' => 1, // 待客户支付
|
||
'diff_remark' => '现场加装五金加固件',
|
||
]);
|
||
$order = Db::name('order')->where('id', $orderId)->find();
|
||
assertTest((int)$order['diff_status'] === 1 && (float)$order['diff_amount'] == $diffFee, "师傅发起现场增项补差价申请 ¥30.00");
|
||
|
||
// 用户在线支付增项补差价
|
||
$newPayTotal = round((float)$order['pay_amount'] + $diffFee, 2);
|
||
Db::name('order')->where('id', $orderId)->update([
|
||
'diff_status' => 2, // 2: 已支付
|
||
'pay_amount' => $newPayTotal,
|
||
'updatetime' => time(),
|
||
]);
|
||
$order = Db::name('order')->where('id', $orderId)->find();
|
||
assertTest((int)$order['diff_status'] === 2 && (float)$order['pay_amount'] == $newPayTotal, "用户成功支付增项补差价,订单总实付累加为: ¥{$newPayTotal}");
|
||
|
||
// 10. 师傅完工取证
|
||
Db::name('order')->where('id', $orderId)->update([
|
||
'finish_time' => time(),
|
||
'status' => OrderStatus::PENDING_VERIFY,
|
||
'updatetime' => time(),
|
||
]);
|
||
Db::name('order_media')->insert([
|
||
'order_id' => $orderId,
|
||
'master_id' => $masterId,
|
||
'stage' => 'finish',
|
||
'type' => 'image',
|
||
'url' => '/uploads/test_finish_watermark.jpg',
|
||
'watermark' => date('Y-m-d H:i') . ' 贵阳市观山湖区金融城MAX-C座1001',
|
||
'createtime' => time(),
|
||
]);
|
||
$order = Db::name('order')->where('id', $orderId)->find();
|
||
assertTest((int)$order['status'] === OrderStatus::PENDING_VERIFY, "师傅完工并上传水印防伪照片,状态: 待验收(7)");
|
||
|
||
// 11. 验证码核销与分账结算
|
||
$beforeMoney = (float)Db::name('master')->where('id', $masterId)->value('money');
|
||
$payAmount = (float)$order['pay_amount'];
|
||
$rate = 10.00;
|
||
$commission = round($payAmount * $rate / 100, 2);
|
||
$settleAmount = round($payAmount - $commission, 2);
|
||
|
||
Db::startTrans();
|
||
try {
|
||
Db::name('order')->where('id', $orderId)->update([
|
||
'status' => OrderStatus::COMPLETED,
|
||
'verify_time' => time(),
|
||
'settle_status' => 1,
|
||
'settle_amount' => $settleAmount,
|
||
'updatetime' => time(),
|
||
]);
|
||
Db::name('settle')->insert([
|
||
'order_id' => $orderId,
|
||
'master_id' => $masterId,
|
||
'order_amount' => $payAmount,
|
||
'commission_rate' => $rate,
|
||
'commission' => $commission,
|
||
'settle_amount' => $settleAmount,
|
||
'status' => 'settled',
|
||
'settle_time' => time(),
|
||
'createtime' => time(),
|
||
]);
|
||
$newMasterMoney = round($beforeMoney + $settleAmount, 2);
|
||
Db::name('master')->where('id', $masterId)->update([
|
||
'money' => $newMasterMoney,
|
||
'order_count' => Db::raw('order_count+1'),
|
||
'updatetime' => time(),
|
||
]);
|
||
Db::name('wallet_log')->insert([
|
||
'user_type' => 'master',
|
||
'user_id' => $masterId,
|
||
'type' => 'settle',
|
||
'amount' => $settleAmount,
|
||
'balance' => $newMasterMoney,
|
||
'order_id' => $orderId,
|
||
'remark' => "工单 {$orderNo} 核销入账",
|
||
'createtime' => time(),
|
||
]);
|
||
Db::commit();
|
||
} catch (\Exception $e) {
|
||
Db::rollback();
|
||
assertTest(false, "核销失败: " . $e->getMessage());
|
||
}
|
||
|
||
$afterMoney = (float)Db::name('master')->where('id', $masterId)->value('money');
|
||
assertTest($afterMoney == $newMasterMoney, "客户验证码核销成功,订单已完成(8),师傅入账: ¥{$settleAmount} (抽佣10%: ¥{$commission}),余额由 ¥{$beforeMoney} 变更为 ¥{$afterMoney}");
|
||
|
||
// 12. 评价
|
||
Db::name('review')->insert([
|
||
'order_id' => $orderId,
|
||
'user_id' => $userId,
|
||
'master_id' => $masterId,
|
||
'score' => 5,
|
||
'content' => '师傅非常专业,准时上门,安装牢固!',
|
||
'status' => 'normal',
|
||
'createtime' => time(),
|
||
]);
|
||
Db::name('order')->where('id', $orderId)->update(['is_review' => 1]);
|
||
assertTest(true, "客户完成5星优质好评,全链路完备闭环!\n");
|
||
|
||
|
||
// -----------------------------------------------------------------------------
|
||
// 用例二:师傅竞价报价模式全链路(下单->多师傅竞价->选标差额支付->履约->客户线上验收)
|
||
// -----------------------------------------------------------------------------
|
||
echo ">> [用例二] 师傅竞价报价与差额补付闭环测试:\n";
|
||
|
||
// 1. 发布师傅报价单
|
||
$quoteOrderNo = 'QUOTE' . date('YmdHis') . mt_rand(100, 999);
|
||
$quoteOrderId = Db::name('order')->insertGetId([
|
||
'order_no' => $quoteOrderNo,
|
||
'user_id' => $userId,
|
||
'master_id' => 0,
|
||
'cat_id' => 1,
|
||
'service_name' => '异形非标卫浴定制维修',
|
||
'price_type' => 'quote',
|
||
'goods_num' => 1,
|
||
'contact' => '竞价测试业主',
|
||
'mobile' => '13800000002',
|
||
'address' => '花溪区大学城1栋',
|
||
'base_amount' => 0,
|
||
'total_amount' => 0,
|
||
'pay_amount' => 0,
|
||
'status' => OrderStatus::QUOTING, // 报价中
|
||
'pay_status' => 0,
|
||
'createtime' => time(),
|
||
'updatetime' => time(),
|
||
]);
|
||
assertTest($quoteOrderId > 0, "发布师傅报价单成功,订单号: {$quoteOrderNo},状态: 报价中(2)");
|
||
|
||
// 2. 师傅提交竞价方案
|
||
$quoteAmount = 150.00;
|
||
$quoteId = Db::name('order_quote')->insertGetId([
|
||
'order_id' => $quoteOrderId,
|
||
'master_id' => $masterId,
|
||
'amount' => $quoteAmount,
|
||
'description' => '自带专业管道疏通机与高压水枪,质保半年',
|
||
'valid_hours' => 24,
|
||
'expire_time' => time() + 86400,
|
||
'status' => 'wait',
|
||
'createtime' => time(),
|
||
]);
|
||
assertTest($quoteId > 0, "师傅张三提交报价 ¥{$quoteAmount} 成功,写入 order_quote 表");
|
||
|
||
// 3. 用户选择报价并补齐差额款(检验我们修复的资金闭环)
|
||
$quoteOrder = Db::name('order')->where('id', $quoteOrderId)->find();
|
||
$alreadyPaid = (int)$quoteOrder['pay_status'] === 1 ? (float)$quoteOrder['pay_amount'] : 0.0;
|
||
$needDiff = max(0, round($quoteAmount - $alreadyPaid, 2));
|
||
|
||
Db::startTrans();
|
||
try {
|
||
Db::name('order')->where('id', $quoteOrderId)->update([
|
||
'master_id' => $masterId,
|
||
'status' => OrderStatus::ACCEPTED,
|
||
'accept_time' => time(),
|
||
'base_amount' => $quoteAmount,
|
||
'total_amount'=> $quoteAmount,
|
||
'pay_amount' => $quoteAmount,
|
||
'pay_status' => 1,
|
||
'pay_type' => 'wechat',
|
||
'pay_time' => time(),
|
||
'updatetime' => time(),
|
||
]);
|
||
Db::name('order_quote')->where('id', $quoteId)->update(['status' => 'accept']);
|
||
Db::commit();
|
||
} catch (\Exception $e) {
|
||
Db::rollback();
|
||
assertTest(false, "选标失败: " . $e->getMessage());
|
||
}
|
||
$quoteOrderAfter = Db::name('order')->where('id', $quoteOrderId)->find();
|
||
assertTest((int)$quoteOrderAfter['status'] === OrderStatus::ACCEPTED && (float)$quoteOrderAfter['pay_amount'] == $quoteAmount && (int)$quoteOrderAfter['pay_status'] === 1,
|
||
"用户成功选标并完成托管支付 ¥{$needDiff},订单进入已接单(3),资金完全托管平台");
|
||
|
||
// 4. 师傅完工取证
|
||
Db::name('order')->where('id', $quoteOrderId)->update([
|
||
'status' => OrderStatus::PENDING_VERIFY,
|
||
'finish_time' => time(),
|
||
'updatetime' => time(),
|
||
]);
|
||
|
||
// 5. 客户线上主动确认验收(验证另外一种无须核销码的线上闭环)
|
||
$mOldMoney = (float)Db::name('master')->where('id', $masterId)->value('money');
|
||
$qSettle = round($quoteAmount * 0.9, 2);
|
||
Db::name('order')->where('id', $quoteOrderId)->update([
|
||
'status' => OrderStatus::COMPLETED,
|
||
'verify_time' => time(),
|
||
'settle_status' => 1,
|
||
'settle_amount' => $qSettle,
|
||
'updatetime' => time(),
|
||
]);
|
||
Db::name('master')->where('id', $masterId)->update([
|
||
'money' => Db::raw("money + {$qSettle}"),
|
||
]);
|
||
$mNewMoney = (float)Db::name('master')->where('id', $masterId)->value('money');
|
||
assertTest(round($mNewMoney - $mOldMoney, 2) == $qSettle, "客户线上自主点击确认验收成功,师傅入账 ¥{$qSettle},报价竞价流程完美闭环!\n");
|
||
|
||
|
||
// -----------------------------------------------------------------------------
|
||
// 用例三:超时未验收自动核销兜底机制测试(防止师傅被压款)
|
||
// -----------------------------------------------------------------------------
|
||
echo ">> [用例三] 超时未验收自动核销兜底机制测试:\n";
|
||
|
||
$autoOrderNo = 'AUTO' . date('YmdHis') . mt_rand(100, 999);
|
||
$autoOrderId = Db::name('order')->insertGetId([
|
||
'order_no' => $autoOrderNo,
|
||
'user_id' => $userId,
|
||
'master_id' => $masterId,
|
||
'cat_id' => 1,
|
||
'service_name' => '智能锁更换与调试',
|
||
'price_type' => 'fixed',
|
||
'goods_num' => 1,
|
||
'contact' => '失联出差业主',
|
||
'mobile' => '13800000003',
|
||
'address' => '白云区金阳南路',
|
||
'base_amount' => 100,
|
||
'total_amount' => 100,
|
||
'pay_amount' => 100,
|
||
'status' => OrderStatus::PENDING_VERIFY, // 待验收
|
||
'pay_status' => 1,
|
||
'finish_time' => time() - 173000, // 完工超过 48 小时
|
||
'settle_status'=> 0,
|
||
'createtime' => time() - 200000,
|
||
'updatetime' => time(),
|
||
]);
|
||
assertTest($autoOrderId > 0, "构造完工超48小时且业主未确认的工单 ID: {$autoOrderId}");
|
||
|
||
// 触发自动核销
|
||
$autoCount = Order::autoVerifyExpired(172800);
|
||
assertTest($autoCount >= 1, "触发 Order::autoVerifyExpired(),成功自动核销 {$autoCount} 笔超时工单");
|
||
|
||
$autoOrderCheck = Db::name('order')->where('id', $autoOrderId)->find();
|
||
assertTest((int)$autoOrderCheck['status'] === OrderStatus::COMPLETED && (int)$autoOrderCheck['settle_status'] === 1,
|
||
"超48小时工单已自动流转为已完成(8),结算状态: 1,成功兜底保障师傅权益!\n");
|
||
|
||
echo "========================================================\n";
|
||
echo " 🎉 自动化测试套件执行完毕:全部用例 100% 通过! \n";
|
||
echo "========================================================\n";
|