load(); \support\App::loadAllConfig(['route']); date_default_timezone_set('Asia/Shanghai'); use support\Db; use plugin\saiadmin\app\model\water\WaterModel; $batch='TEST-WATER-SHENZHEN-MAP-20260910'; $apply=in_array('--apply',$argv,true); $targets=[9=>'【测试0910】云泉科技',10=>'【测试0910】智配办公',11=>'【测试0910】清泉产业园']; // 2026-09-10 在项目高德 Geocoder 中检索并核对,GCJ-02 坐标。 $origin=['origin_address'=>'深圳市南山区南油第四工业区4栋(测试出发点)','origin_longitude'=>113.924140,'origin_latitude'=>22.522806]; $destination=['address'=>'深圳市南山区海德一道中洲控股中心(地图测试,请勿实际配送)','region'=>'深圳市南山区', 'longitude'=>113.935124,'latitude'=>22.516070]; $replayed=false; if ($apply) { $replayed=WaterModel::transaction(function () use ($batch,$targets,$origin,$destination) { // 和正常库存操作一致,先锁定目标商品,避免与派单/签收交错。 $skuIds=\plugin\saiadmin\app\model\water\WaterDelivery::query()->whereIn('id',array_keys($targets))->pluck('sku_id')->all(); \plugin\saiadmin\app\model\water\WaterSku::query()->whereIn('id',$skuIds)->orderBy('id')->lock(true)->get(); if (\plugin\saiadmin\app\model\water\WaterLedger::query()->where(['kind'=>'demo_seed','reference'=>$batch])->first()?->toArray()) return true; $invariants=[]; foreach (['sa_water_sku','sa_water_account','sa_water_order'] as $table) $invariants[$table]=WaterModel::forKind(substr($table,9))->orderBy('id')->get()->toArray(); $saved=[]; foreach ($targets as $id=>$name) { $task=\plugin\saiadmin\app\model\water\WaterDelivery::query()->where('id',$id)->lock(true)->first()?->toArray(); if (!$task) throw new RuntimeException('指定测试配送不存在:'.$id); $enterprise=\plugin\saiadmin\app\model\water\WaterEnterprise::query()->where('id',$task['enterprise_id'])->lock(true)->first()?->toArray(); if (!$enterprise || $enterprise['name']!==$name) throw new RuntimeException('测试企业不匹配,停止避免覆盖其他数据'); $saved[]=['task'=>$task,'enterprise'=>$enterprise]; $now=date('Y-m-d H:i:s'); \plugin\saiadmin\app\model\water\WaterDelivery::query()->where('id',$id)->update($origin+$destination+['updated_at'=>$now]); \plugin\saiadmin\app\model\water\WaterEnterprise::query()->where('id',$enterprise['id'])->update($destination+['updated_at'=>$now]); $after=\plugin\saiadmin\app\model\water\WaterDelivery::query()->where('id',$id)->first()?->toArray(); foreach (['status','quantity','driver','driver_phone','driver_id','route_id','stop_order','scheduled_date','deadline_at','active_key','completed_at','empty_returned'] as $field) { if ($after[$field]!==$task[$field]) throw new RuntimeException('非位置字段意外改变:'.$field); } } foreach ($invariants as $table=>$rows) { if (WaterModel::forKind(substr($table,9))->orderBy('id')->get()->toArray()!==$rows) throw new RuntimeException('库存、权益或收款发生意外变化:'.$table); } // 记录本批操作,并在运行目录保存旧测试位置快照供追溯。 \plugin\saiadmin\app\model\water\WaterLedger::query()->insert(['kind'=>'demo_seed','reference'=>$batch,'quantity'=>0,'created_by'=>1,'created_at'=>date('Y-m-d H:i:s'), 'note'=>'深圳地图测试坐标:南油第四工业区4栋 → 南山中洲控股中心;任务9/10/11,保留原状态及数量']); $auditPath=runtime_path().'/water-shenzhen-map-before.json'; if (is_file($auditPath)) throw new RuntimeException('回退快照已存在,停止避免覆盖'); if (file_put_contents($auditPath,json_encode($saved,JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT))===false) throw new RuntimeException('无法保存原测试位置快照'); return false; }); } echo json_encode(['mode'=>$apply?'applied':'inspect','replayed'=>$replayed,'origin'=>$origin,'destination'=>$destination, 'deliveries'=>\plugin\saiadmin\app\model\water\WaterDelivery::query()->whereIn('id',array_keys($targets))->selectRaw('id,status,quantity,address,region,longitude,latitude,origin_address,origin_longitude,origin_latitude')->orderBy('id')->get()->toArray()],JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT).PHP_EOL;