seed_mini_devices_demo.php 4.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. <?php
  2. declare(strict_types=1);
  3. require dirname(__DIR__) . '/vendor/autoload.php';
  4. \Dotenv\Dotenv::createUnsafeMutable(dirname(__DIR__))->load();
  5. \support\App::loadAllConfig(['route']);
  6. date_default_timezone_set('Asia/Shanghai');
  7. use app\miniapi\auth\TestPhoneIdentityProvider;
  8. use plugin\saiadmin\app\model\water\WaterModel;
  9. use plugin\saiadmin\app\model\water\WaterEnterprise;
  10. use plugin\saiadmin\app\model\water\WaterSku;
  11. use plugin\saiadmin\app\model\water\WaterAccount;
  12. use plugin\saiadmin\app\model\water\WaterDevice;
  13. use plugin\saiadmin\app\model\water\WaterDeviceUsage;
  14. use plugin\saiadmin\app\model\water\WaterLedger;
  15. use plugin\saiadmin\app\service\alerts\ReplenishmentPolicy;
  16. const MINI_DEVICE_DEMO = 'TEST-MINI-DEVICE-49-20261007';
  17. if (!TestPhoneIdentityProvider::enabled()) {
  18. throw new RuntimeException('Requires local test environment');
  19. }
  20. $apply = in_array('--apply', $argv, true);
  21. $result = WaterModel::transaction(function () use ($apply): array {
  22. $enterprise = WaterEnterprise::query()->where('id', 49)->lockForUpdate()->first();
  23. if (!$enterprise || $enterprise->name !== '【测试0910】科技园配送测试') {
  24. throw new RuntimeException('Expected named test enterprise 49');
  25. }
  26. $sku = WaterSku::query()->where('name', '山泉水(测试)')->where('status', 1)->first();
  27. if (!$sku) {
  28. throw new RuntimeException('Missing active test water specification');
  29. }
  30. $record = WaterLedger::query()->where('kind', 'demo_seed')->where('reference', MINI_DEVICE_DEMO)->first();
  31. if ($record) {
  32. return ['applied' => true, 'replayed' => true, 'note' => $record->note];
  33. }
  34. if (!$apply) {
  35. return ['mode' => 'inspect', 'enterprise_id' => 49, 'sku_id' => (int) $sku->id, 'devices' => 3, 'usage_days' => 7];
  36. }
  37. if (WaterDevice::query()->where('sn', 'like', MINI_DEVICE_DEMO . '%')->exists()) {
  38. throw new RuntimeException('Demo serial numbers already exist without batch record');
  39. }
  40. $originalPeople = $enterprise->employee_count;
  41. $policy = (new ReplenishmentPolicy())->settings();
  42. if ($enterprise->employee_count === null || (int) $enterprise->employee_count === 0) {
  43. $enterprise->employee_count = max(1, (int) round(7 * $policy['days_per_barrel'] / 12));
  44. $enterprise->save();
  45. }
  46. $accountKey = ['enterprise_id' => 49, 'sku_id' => (int) $sku->id];
  47. $existingAccount = WaterAccount::query()->where($accountKey)->first();
  48. $account = $existingAccount ?? WaterAccount::query()->create($accountKey + [
  49. 'entitlement' => 64, 'frozen' => 0, 'full_qty' => 7, 'empty_qty' => 2,
  50. 'threshold_qty' => 3, 'daily_liters' => null, 'updated_at' => date('Y-m-d H:i:s'),
  51. ]);
  52. $samples = [
  53. ['会议区智能饮水机', 18.6, [9.2, 14.0, 11.1, 17.3, 14.8, 18.6, 13.0]],
  54. ['前台智能饮水机', 12.4, [6.4, 9.5, 8.2, 11.6, 10.4, 14.0, 12.4]],
  55. ['茶水间智能饮水机', 23.8, [15.2, 17.6, 16.0, 20.3, 18.9, 25.4, 23.8]],
  56. ];
  57. $deviceIds = [];
  58. $now = new DateTimeImmutable();
  59. foreach ($samples as $index => [$name, $today, $history]) {
  60. $device = WaterDevice::query()->create([
  61. 'sn' => MINI_DEVICE_DEMO . '-' . ($index + 1), 'enterprise_id' => 49,
  62. 'sku_id' => (int) $sku->id, 'name' => '【测试】' . $name, 'firmware' => 'mini-demo',
  63. 'last_seen' => $now->format('Y-m-d H:i:s'), 'today_liters' => $today,
  64. 'telemetry_date' => $now->format('Y-m-d'), 'fault' => '',
  65. 'created_at' => $now->format('Y-m-d H:i:s'), 'updated_at' => $now->format('Y-m-d H:i:s'),
  66. ]);
  67. $deviceIds[] = (int) $device->id;
  68. foreach ($history as $dayIndex => $liters) {
  69. $day = $now->modify('-' . (6 - $dayIndex) . ' days')->format('Y-m-d');
  70. WaterDeviceUsage::query()->create([
  71. 'device_id' => (int) $device->id, 'day' => $day,
  72. 'liters' => $dayIndex === 6 ? $today : $liters,
  73. 'reported_at' => $dayIndex === 6 ? $now->format('Y-m-d H:i:s') : $day . ' 17:00:00',
  74. ]);
  75. }
  76. }
  77. $manifest = [
  78. 'device_ids' => $deviceIds, 'account_id' => (int) $account->id,
  79. 'account_created' => $existingAccount === null,
  80. 'original_employee_count' => $originalPeople,
  81. 'demo_employee_count' => (int) $enterprise->employee_count,
  82. 'note' => 'Only simulated telemetry and demo stock; no purchase, payment or automatic delivery executed.',
  83. ];
  84. WaterLedger::query()->create([
  85. 'enterprise_id' => 49, 'sku_id' => (int) $sku->id,
  86. 'kind' => 'demo_seed', 'reference' => MINI_DEVICE_DEMO, 'quantity' => 0,
  87. 'created_by' => 1, 'note' => json_encode($manifest, JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR),
  88. 'created_at' => $now->format('Y-m-d H:i:s'),
  89. ]);
  90. return ['applied' => true, 'replayed' => false, 'usage_rows' => 21] + $manifest;
  91. });
  92. echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . PHP_EOL;