seed_water_withdrawal_demo.php 6.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. <?php
  2. /** Seed four labelled withdrawal display fixtures once; never creates balances or payouts. */
  3. declare(strict_types=1);
  4. require dirname(__DIR__).'/vendor/autoload.php';
  5. \Dotenv\Dotenv::createUnsafeMutable(dirname(__DIR__))->load();
  6. \support\App::loadAllConfig(['route']);
  7. date_default_timezone_set('Asia/Shanghai');
  8. use plugin\saiadmin\app\model\water\{WaterModel,WaterWithdrawalDemo,WaterOperator,WaterOrder,WaterAccount,WaterSku,WaterDelivery,WaterAgent,WaterLedger};
  9. use plugin\saiadmin\app\service\WaterFinanceDashboard;
  10. const WITHDRAWAL_DEMO_BATCH = 'TEST-WATER-WITHDRAWAL-20260917';
  11. function ensure(bool $ok, string $message): void { if (!$ok) throw new RuntimeException($message); }
  12. function protectedData(): array {
  13. $hashes = [];
  14. foreach ([WaterOrder::class, WaterAccount::class, WaterSku::class, WaterDelivery::class, WaterAgent::class] as $model) {
  15. $hashes[$model] = hash('sha256', serialize($model::query()->orderBy('id')->get()->toArray()));
  16. }
  17. return $hashes;
  18. }
  19. $samples = [
  20. ['【提现测试】星澜商务', '代理佣金', '模拟微信账户', 576000],
  21. ['【提现测试】青禾推广用户', '推广奖励', '模拟微信账户', 86000],
  22. ['【提现测试】云帆企业服务', '代理佣金', '模拟银行账户', 328000],
  23. ['【提现测试】森屿商贸', '代理佣金', '模拟银行账户', 246000],
  24. ];
  25. $result = ['applied' => false, 'planned' => 4, 'amount_cents' => 1236000, 'batch' => WITHDRAWAL_DEMO_BATCH];
  26. if (in_array('--apply', $argv, true)) {
  27. $result = WaterModel::transaction(function () use ($samples): array {
  28. ensure((bool)WaterOperator::query()->where('id', 1)->lockForUpdate()->first(), '缺少操作账号');
  29. $existing = WaterWithdrawalDemo::query()->where('batch', WITHDRAWAL_DEMO_BATCH)->orderBy('id')->get()->toArray();
  30. if ($existing) {
  31. ensure(count($existing) === 4, '测试批次不完整,请核对,禁止自动覆盖');
  32. return ['applied' => true, 'replayed' => true, 'created_ids' => array_column($existing, 'id')];
  33. }
  34. $before = protectedData();
  35. $service = new WaterFinanceDashboard();
  36. $beforeDashboard = $service->dashboard(['month' => '2026-09']);
  37. $ids = [];
  38. foreach ($samples as $index => [$name, $kind, $channel, $cents]) {
  39. $ids[] = WaterWithdrawalDemo::query()->create([
  40. 'batch' => WITHDRAWAL_DEMO_BATCH, 'reference' => WITHDRAWAL_DEMO_BATCH.'-'.($index + 1),
  41. 'applicant_name' => $name, 'kind_label' => $kind, 'channel_label' => $channel,
  42. 'amount_cents' => $cents, 'status' => 'pending', 'created_at' => '2026-09-17 00:00:00',
  43. ])->id;
  44. }
  45. $afterDashboard = $service->dashboard(['month' => '2026-09']);
  46. ensure($before === protectedData(), '现有业务数据发生变化');
  47. foreach (['summary', 'trend', 'list', 'withdrawals', 'capabilities'] as $key) {
  48. ensure($beforeDashboard[$key] === $afterDashboard[$key], '真实财务口径发生变化:'.$key);
  49. }
  50. ensure($afterDashboard['withdrawal_demo']['total'] - $beforeDashboard['withdrawal_demo']['total'] === 4, '测试申请数量不正确');
  51. ensure($afterDashboard['withdrawal_demo']['amount_cents'] - $beforeDashboard['withdrawal_demo']['amount_cents'] === 1236000, '测试申请金额不正确');
  52. WaterLedger::query()->create(['kind' => 'demo_seed', 'reference' => WITHDRAWAL_DEMO_BATCH,
  53. 'created_by' => 1, 'enterprise_id' => 0, 'sku_id' => 0, 'quantity' => 0,
  54. 'note' => '提现展示测试4笔,合计12360元;无真实余额、无实际打款;IDs='.implode(',', $ids),
  55. 'created_at' => date('Y-m-d H:i:s')]);
  56. return ['applied' => true, 'replayed' => false, 'created_ids' => $ids];
  57. });
  58. $service = new WaterFinanceDashboard();
  59. $all = $service->dashboard(['month' => '2026-09']);
  60. $demo = $service->dashboard(['month' => '2026-09', 'source' => 'demo']);
  61. ensure($all['withdrawal_demo'] === $demo['withdrawal_demo'], '测试范围不一致');
  62. ensure($service->dashboard(['month' => '2026-09', 'source' => 'regular'])['withdrawal_demo']['total'] === 0, '排除测试时不应显示申请');
  63. ensure($service->dashboard(['month' => '2026-08'])['withdrawal_demo']['total'] === 0, '测试申请不应跨月');
  64. ensure($service->dashboard(['month' => '2026-09', 'keyword' => 'no-match', 'page' => 99])['withdrawal_demo'] === $all['withdrawal_demo'], '流水搜索和分页不应改变申请');
  65. $before = new WaterFinanceDashboard(new DateTimeImmutable('2026-09-16 23:59:59'));
  66. ensure($before->dashboard(['month' => '2026-09'])['withdrawal_demo']['total'] === 0, '不应显示未来申请');
  67. ensure($all['summary']['pending_withdrawal_cents'] === null && !$all['capabilities']['withdrawals'], '不可启用真实提现');
  68. foreach ($all['withdrawal_demo']['list'] as $row) ensure($row['is_demo'] === true && $row['status_label'] === '待审核(测试)', '测试标记缺失');
  69. $result['withdrawal_demo'] = $all['withdrawal_demo'];
  70. $result['checks'] = 'source/month/time filters, receipt independence, fixture labels and disabled payout capability passed';
  71. }
  72. if (in_array('--http', $argv, true)) {
  73. $token = \Tinywan\Jwt\JwtToken::generateToken(['id' => 1, 'username' => 'admin', 'plat' => 'saiadmin', 'type' => 'web',
  74. 'client' => WITHDRAWAL_DEMO_BATCH, 'access_exp' => 120, 'refresh_exp' => 120])['access_token'];
  75. $cases = [['month' => '2026-09'], ['month' => '2026-09', 'source' => 'demo'], ['month' => '2026-09', 'source' => 'regular'], ['month' => '2026-08']];
  76. foreach ($cases as $filters) {
  77. $ch = curl_init('http://127.0.0.1:8787/core/water/finance/dashboard?'.http_build_query($filters));
  78. curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 15, CURLOPT_HTTPHEADER => ['Authorization: Bearer '.$token]]);
  79. $raw = curl_exec($ch); $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch);
  80. $body = json_decode((string)$raw, true);
  81. ensure($status === 200 && ($body['code'] ?? 0) === 200, 'HTTP看板失败');
  82. ensure(($body['data']['withdrawal_demo'] ?? null) === (new WaterFinanceDashboard())->dashboard($filters)['withdrawal_demo'], 'HTTP测试申请与服务结果不一致');
  83. }
  84. $result['http_read_checks'] = count($cases);
  85. }
  86. echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT).PHP_EOL;