cqp преди 2 дни
родител
ревизия
8424df1750

+ 16 - 14
app/Console/Commands/U8Settle.php

@@ -41,7 +41,7 @@ class U8Settle extends Command
         try {
             $this->settle();
         }catch (\Exception $exception){
-            Log::channel('apiLog')->info('异常', ['msg' => $exception->getMessage() . '|' . $exception->getLine()]);
+            Log::channel('u8_daily')->info('单据同步异常', ['msg' => $exception->getMessage() . '|' . $exception->getLine()]);
         }
     }
 
@@ -49,7 +49,7 @@ class U8Settle extends Command
         $service = new U8ThirtyPartyDatabaseServerService();
         $minPeriods = $this->getYjData();
         if(empty($minPeriods['pu_date']) || empty($minPeriods['st_date']) || empty($minPeriods['sa_date'])) {
-            Log::channel('apiLog')->info('月结数据为空', ['msg' => $minPeriods]);
+            Log::channel('u8_daily')->info('月结数据为空', ['msg' => $minPeriods]);
             return;
         }
 
@@ -88,7 +88,8 @@ class U8Settle extends Command
 //                    'detail.cWhCode as warehouseCode',
                     'detail.cInvCode as materialCode',
                     'detail.iQuantity as planQty',
-//                    'detail.cordercode as from_order',
+                    'detail.cDefine23',
+                    'detail.cBatch',
                 ],
                 'limit' => 30,
             ],
@@ -120,7 +121,7 @@ class U8Settle extends Command
                     'detail.AUTOID  as auto_id',
                     'detail.CINVCODE as materialCode',
                     'detail.FQUANTITY as planQty',
-                    'detail.CDEFINE32 as lottar1',
+                    'detail.cDefine23',
                 ],
                 'limit' => 30,
             ],
@@ -143,7 +144,7 @@ class U8Settle extends Command
                 'detail' => 'RdRecords08',
                 'main_key' => 'ID',
                 'key' => 'ID',
-                'whereRaw' => "(dDate >= '{$st}')",
+                'whereRaw' => "(dDate >= '{$st}' and and COALESCE(cMemo, '') <> '接口生成')",
                 'main_field' => ['ID as id','cCode as no','dDate as order_date','dnmaketime as crt_time', 'dnmodifytime as upd_time','cWhCode as warehouseCode','cHandler as reviewer'],
                 'son_field' => [
                     'detail.ID as id',
@@ -164,6 +165,10 @@ class U8Settle extends Command
                     'detail.cInvCode as materialCode',
                     'detail.cWhCode as warehouseCode',
                     'detail.iQuantity as planQty',
+                    'detail.cDefine23',
+                    'detail.cBatch',
+                    'detail.dMDate',
+                    'detail.iMassDate',
                 ],
                 'limit' => 30,
             ],
@@ -172,7 +177,7 @@ class U8Settle extends Command
                 'detail' => 'RdRecords09',
                 'main_key' => 'ID',
                 'key' => 'ID',
-                'whereRaw' => "(dDate >= '{$st}')",
+                'whereRaw' => "(dDate >= '{$st}' and COALESCE(cMemo, '') <> '接口生成')",
                 'main_field' => ['ID as id','cCode as no','dDate as order_date','dnmaketime as crt_time', 'dnmodifytime as upd_time','cWhCode as warehouseCode','cHandler as reviewer'],
                 'son_field' => [
                     'detail.ID as id',
@@ -183,15 +188,15 @@ class U8Settle extends Command
             ],
             SyncTempRecord::type_eight => [
                 //检验单
-                //cvouchtype=null=>采购到货单 1
+                //cvouchtype=QM03=>采购到货单 1  来料报检单
                 //cvouchtype=QM04=>产品检验单 2
                 //cvouchtype=QM14=>退货检验单 3
                 'main' => 'QMCHECKVOUCHER',
-                'detail' => 'QMCHECKVOUCHERS',
+                'detail' => '',
                 'main_key' => 'ID',
                 'key' => '',
-                'whereRaw' => "(DDATE >= '{$st}' and (CVOUCHTYPE = null OR CVOUCHTYPE = 'QM04' OR CVOUCHTYPE = 'QM14'))",
-                'main_field' => ['ID as id','CCHECKCODE as no','DDATE as order_date','DMAKETIME as crt_time', 'DMODIFYTIME as upd_time','CVERIFIER as reviewer', 'CVOUCHTYPE as type', 'CINVCODE as materialCode', 'CBATCH as lot', 'FREGQUANTITY as hg_quantity', 'FDISQUANTITY as hg_not_quantity', 'FCONQUANTIY as rb_quantity'],
+                'whereRaw' => "(DDATE >= '{$st}' and (CVOUCHTYPE = 'QM03' OR CVOUCHTYPE = 'QM04'))",
+                'main_field' => ['ID as id','CCHECKCODE as no','DDATE as order_date','DMAKETIME as crt_time', 'DMODIFYTIME as upd_time','CVERIFIER as reviewer', 'CVOUCHTYPE as type', 'CINVCODE as materialCode', 'CBATCH as lot', 'FREGQUANTITY as hg_quantity', 'FDISQUANTITY as hg_not_quantity', 'FCONQUANTIY as rb_quantity','SOURCECODE as from_order', 'CINSPECTCODE as bj_order'],
                 'son_field' => [],
                 'limit' => 30,
             ],
@@ -222,7 +227,7 @@ class U8Settle extends Command
                 foreach ($items as $item) {
                     if ($name == SyncTempRecord::type_eight){
                         $type_v = 0;
-                        if($item['type'] == null){
+                        if($item['type'] == 'QM03'){
                             $type_v = 1;
                         }elseif ($item['type'] == 'QM04'){
                             $type_v = 2;
@@ -240,9 +245,6 @@ class U8Settle extends Command
                     $bool = $item['reviewer'] ? true : false;
                     if(! $bool) continue;// 没审核跳过
 
-                    //退货单没有来源单据的不推送
-//                    if($name == SyncTempRecord::type_one && $item['type_2'] == 1 && empty($item['details'][0]['from_order'])) continue;
-
                     $opType = null;
                     if (!$snapshot) {
                         $opType = SyncTempRecord::opt_zero;

+ 9 - 6
app/Console/Commands/U8SettleInventory.php

@@ -39,13 +39,16 @@ class U8SettleInventory extends Command
         try {
             $time = time();
             //生成需要增删改的存货数据
+            Log::channel('u8_daily')->info('查询物料是否存在增量更新');
             $this->settle($time);
-            echo '第一步完成------' . PHP_EOL;
+            Log::channel('u8_daily')->info('物料是否存在增量更新:完成&开始组织需要同步的物料数据');
             //处理存货数据
             $this->productInsert($time);
-            echo '第二步完成------' . PHP_EOL;
+            Log::channel('u8_daily')->info('同步物料数据:完成');
+            return 0;
         }catch (\Exception $exception){
-            Log::channel('apiLog')->info('存货异常', ['msg' => $exception->getMessage()]);
+            Log::channel('u8_daily')->info('物料同步异常', ['msg' => $exception->getMessage()]);
+            return 1; // 返回非 0 代表失败,不会触发 onSuccess
         }
     }
 
@@ -218,7 +221,7 @@ class U8SettleInventory extends Command
 
     public function post_helper($url, $data, $header = [], $timeout = 30)
     {
-        Log::channel('apiLog')->info('存货同步', ["api" => $url, "param" => $data]);
+        Log::channel('apiLog')->info('物料同步', ["api" => $url, "param" => $data]);
 
         $ch = curl_init();
         curl_setopt($ch, CURLOPT_URL, $url);
@@ -234,13 +237,13 @@ class U8SettleInventory extends Command
         if ($r === false) {
             $errorMessage = curl_error($ch);
             curl_close($ch);
-            Log::channel('apiLog')->error('存货同步异常:WMS_CURL_ERROR', ["msg" => $errorMessage]);
+            Log::channel('apiLog')->error('物料同步异常:WMS_CURL_ERROR', ["msg" => $errorMessage]);
             return [false, "网络错误: " . $errorMessage];
         }
         curl_close($ch);
 
         $return = json_decode($r, true);
-        Log::channel('apiLog')->info('存货同步返回结果', ["res" => $return]);
+        Log::channel('apiLog')->info('物料同步返回结果', ["res" => $return]);
 
         // 判断逻辑:code 存在且为 200 才算 true
         if (isset($return['code']) && $return['code'] == 200) {

+ 23 - 2
app/Console/Kernel.php

@@ -4,6 +4,7 @@ namespace App\Console;
 
 use Illuminate\Console\Scheduling\Schedule;
 use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
+use Illuminate\Support\Facades\Log;
 
 class Kernel extends ConsoleKernel
 {
@@ -24,8 +25,28 @@ class Kernel extends ConsoleKernel
      */
     protected function schedule(Schedule $schedule)
     {
-        // $schedule->command('inspire')
-        //          ->hourly();
+        // 每五分钟同步一次 外部定时任务 然后 物料第一次同步检验手动同步
+        $schedule->command('command:u8_settle_inventory')
+            ->everyMinute()
+            ->withoutOverlapping(10) // 锁长时间一点,给第一次同步留足时间
+            ->onSuccess(function () {
+                // 2. 只有当 U8SettleInventory 的 handle() 返回 0 时,才执行单据同步
+                \Illuminate\Support\Facades\Artisan::call('command:u8_settle');
+            })
+            ->onFailure(function(){
+                Log::channel('u8_daily')->warning('物料同步失败,单据同步已挂起。');
+            });
+
+        if (str_contains(PHP_OS, 'WIN')) {
+            $schedule->call(function () {
+                // 启动新队列
+                // 使用 start /B 配合 php 运行,WindowStyle Hidden 隐藏窗口
+                $cmd = "start /B php artisan queue:work redis --queue=sync_wms_order";
+                pclose(popen($cmd, "r"));
+
+                \Illuminate\Support\Facades\Log::channel('u8_daily')->info("单进程守卫:未检测到运行中的队列,已成功拉起新进程。");
+            })->everyMinute();
+        }
     }
 
     /**

+ 89 - 22
app/Jobs/ProcessWMSDataJob.php

@@ -3,6 +3,7 @@
 namespace App\Jobs;
 
 use App\Model\SyncTempRecord;
+use App\Service\U8ThirdPartyService;
 use Illuminate\Bus\Queueable;
 use Illuminate\Contracts\Queue\ShouldQueue;
 use Illuminate\Foundation\Bus\Dispatchable;
@@ -89,30 +90,59 @@ class ProcessWMSDataJob implements ShouldQueue
             'details'       => []
         ];
 
-        if (isset($u8Data['details']) && is_array($u8Data['details'])) {
-            foreach ($u8Data['details'] as $item) {
-                $jsonBody['details'][] = [
-                    'lineNum'       => $item['lineNum'] ?? 0,
-                    'materialCode'  => $item['materialCode'] ?? '',
-                    'planQty'       => (float)($item['planQty'] ?? 0),
-                    'lottar1'       => $item['lottar1'] ?? "",
-                    'lottar2'       => '',
-                    'lottar3'       => '',
-                    'lottar4'       => '',
-                    'lottar5'       => '',
-                    'lottar6'       => '',
-                    'lottar7'       => '',
-                    'lottar8'       => '',
-                    'lottar9'       => '',
-                ];
-            }
-        }
-
         // 4. 接口路由
-        $inboundTypes = [SyncTempRecord::type_one, SyncTempRecord::type_three];
+        $inboundTypes = [SyncTempRecord::type_one, SyncTempRecord::type_three, SyncTempRecord::type_six, SyncTempRecord::type_five];
         $path = in_array($record->type, $inboundTypes) ? '/erp/inbound' : '/erp/outbound';
+        if($record->type_2 == 1 && $record->type == SyncTempRecord::type_one) $path = '/erp/outbound';
         $apiUrl = config('wms.api_url') . $path;
 
+        if (isset($u8Data['details']) && is_array($u8Data['details'])) {
+            if($path == '/erp/inbound'){ //入
+                foreach ($u8Data['details'] as $item) {
+                    $productDate = "";
+                    if(! empty($item['dMDate'])) $productDate = date("Y-m-d", strtotime($item['dMDate']));
+                    $validTime = 0;
+                    if(! empty($item['iMassDate'])) $validTime = $item['iMassDate'];
+                    $lot = "";
+                    if(! empty($item['cBatch'])) $lot = $item['cBatch'];
+                    $jsonBody['details'][] = [
+                        'lineNum'       => $item['lineNum'] ?? 0,
+                        'materialCode'  => $item['materialCode'] ?? '',
+                        'planQty'       => (float)abs($item['planQty']),
+                        'productDate'       => $productDate,
+                        'validTime'       => $validTime,
+                        'lot'       => $lot,
+                        'lottar1'       => $item['cDefine23'] ?? "",
+                        'lottar2'       => "",
+                        'lottar3'       => '',
+                        'lottar4'       => '',
+                        'lottar5'       => '',
+                        'lottar6'       => '',
+                        'lottar7'       => '',
+                        'lottar8'       => '',
+                        'lottar9'       => '',
+                    ];
+                }
+            }else{//出
+                foreach ($u8Data['details'] as $item) {
+                    $jsonBody['details'][] = [
+                        'lineNum'       => $item['lineNum'] ?? 0,
+                        'materialCode'  => $item['materialCode'] ?? '',
+                        'planQty'       => (float)abs($item['planQty']),
+                        'lottar1'       => "",
+                        'lottar2'       => $item['cBatch'] ?? "",
+                        'lottar3'       => '',
+                        'lottar4'       => '',
+                        'lottar5'       => '',
+                        'lottar6'       => '',
+                        'lottar7'       => '',
+                        'lottar8'       => '',
+                        'lottar9'       => '',
+                    ];
+                }
+            }
+        }
+
         // 5. 调用 post_helper
         list($status, $result) = $this->post_helper($apiUrl, $jsonBody, ['Content-Type: application/json']);
 
@@ -164,11 +194,15 @@ class ProcessWMSDataJob implements ShouldQueue
         return [$status ?? true, $msg ?? ""];
     }
 
-    //todo
     public function zj($record, $u8Data, $type){
+        if($record['type_2'] == 1){
+            $orderNo = $u8Data['from_order'];
+        }else{
+            $orderNo = $u8Data['bj_order'];
+        }
         // 3. 组装报文
         $jsonBody = [
-            'orderNo'       => $record->u8_no,
+            'orderNo'       => $orderNo,
             'materialCode' => $u8Data['materialCode'],
             'lot' => $u8Data['lot'] ?? "",
             'inspectionStatus' => $type,
@@ -186,6 +220,39 @@ class ProcessWMSDataJob implements ShouldQueue
             return [false, $result];
         }
 
+        //生成用友单据
+        $service = new U8ThirdPartyService();
+        //报检单类型
+        $bg_type = $record['type_2'];
+        if($bg_type == 1){
+            //采购
+            if($type == 1 || $type == 3){
+                //合格 让步 =》 采购入库
+                list($status, $msg) = $service->purchaseInByZj(['record' => $record, 'payload' => $u8Data,'cvouchtype' => 'QM03','type' => $type]);
+            }else{
+                //不合格 =》其他入库单
+                list($status, $msg) = $service->otherInByZj(['record' => $record, 'payload' => $u8Data, 'cvouchtype' => 'QM03']);
+            }
+        }elseif ($bg_type == 2){
+            //产品
+            if($type == 1 || $type == 3){
+                //合格 让步 =》 产成品入库
+                list($status, $msg) = $service->productInByZj(['record' => $record, 'payload' => $u8Data, 'cvouchtype' => 'QM04','type' => $type]);
+            }else{
+                //不合格 =》其他入库单
+                list($status, $msg) = $service->otherInByZj(['record' => $record, 'payload' => $u8Data, 'cvouchtype' => 'QM04']);
+            }
+        }else{
+            //退货 不需要了
+            list($status, $msg) = [true, ''];
+        }
+
+       if (!$status) {
+            // 接口返回失败或网络失败
+            $record->update(['status' => SyncTempRecord::status_two, 'error_msg' => $msg]);
+            return [false, $msg];
+        }
+
         // 6. 接口返回成功 (200) 的后续操作
         DB::transaction(function () use ($record, $u8Data) {
             // 更新本地流水状态为成功

+ 4 - 4
app/Model/SyncTempRecord.php

@@ -23,9 +23,9 @@ class SyncTempRecord extends Model
         self::opt_two  => 'D',
     ];
 
-    const status_zero = 0;
-    const status_one = 1;
-    const status_two = 2;
+    const status_zero = 0; // 未处理
+    const status_one = 1; // 成功
+    const status_two = 2; // 失败
 
     const type_one = 'purchaseArrival'; // 采购到货单 0 | 采购退货单 1
     const type_two = 'materialRequest'; //领料申请单
@@ -56,7 +56,7 @@ class SyncTempRecord extends Model
         self::type_three => 'WIP_IN',  // 产品报检单
         self::type_four => 'FG_OUT', // 销售订单
         self::type_five => 'MS_IN', // 其他入
-        self::type_six => 'IV_ADJ', // 销售退货
+        self::type_six => 'FG_XT', // 销售退货
         self::type_seven => 'MS_OUT', // 其他出
         self::type_eight => 'U8_check', // 检验单
     ];

+ 267 - 0
app/Service/DeviceService.php

@@ -0,0 +1,267 @@
+<?php
+
+namespace App\Service;
+
+use App\Model\Employee;
+use App\Model\Device;
+use App\Model\DeviceDetails;
+use Illuminate\Support\Facades\DB;
+
+class DeviceService extends Service
+{
+    public function deviceEdit($data,$user){
+        list($status,$msg) = $this->deviceRule($data, $user, false);
+        if(!$status) return [$status,$msg];
+
+        try {
+            DB::beginTransaction();
+
+            $model = Device::where('id',$data['id'])->first();
+            $model->code = $data['code'] ?? '';
+            $model->title = $data['title'] ?? '';
+            $model->size = $data['size'] ?? '';
+            $model->mark = $data['mark'] ?? '';
+            $model->is_use = $data['is_use'] ?? 0;
+            $model->type = $data['type'] ?? 0;
+            $model->type_2 = $data['type_2'] ?? 0;
+            $model->in_time = $data['in_time'] ?? 0;
+            $model->power = $data['power'] ?? 0;
+            $model->number = $data['number'] ?? 0;
+            $model->save();
+
+            $time = time();
+            DeviceDetails::where('del_time',0)
+                ->where('device_id', $model->id)
+                ->update(['del_time' => $time]);
+            $this->saveDetail($model->id, $time, $data);
+
+            DB::commit();
+        }catch (\Exception $exception){
+            DB::rollBack();
+            return [false,$exception->getMessage()];
+        }
+
+        return [true, ''];
+    }
+
+    public function deviceAdd($data,$user){
+        list($status,$msg) = $this->deviceRule($data, $user);
+        if(!$status) return [$status,$msg];
+
+        try {
+            DB::beginTransaction();
+
+            $model = new Device();
+            $model->code = $data['code'] ?? '';
+            $model->title = $data['title'] ?? '';
+            $model->size = $data['size'] ?? '';
+            $model->mark = $data['mark'] ?? '';
+            $model->is_use = $data['is_use'] ?? 0;
+            $model->type = $data['type'] ?? 0;
+            $model->type_2 = $data['type_2'] ?? 0;
+            $model->in_time = $data['in_time'] ?? 0;
+            $model->power = $data['power'] ?? 0;
+            $model->number = $data['number'] ?? 0;
+            $model->crt_id = $user['id'];
+            $model->save();
+
+            $this->saveDetail($model->id, time(), $data);
+
+            DB::commit();
+        }catch (\Exception $exception){
+            DB::rollBack();
+            return [false,$exception->getMessage()];
+        }
+
+        return [true, ''];
+    }
+
+    private function saveDetail($id, $time, $data){
+        if(! empty($data['details'])){
+            $unit = [];
+            foreach ($data['details'] as $value){
+                $unit[] = [
+                    'device_id' => $id,
+                    'time' => $value['time'],
+                    'total_hours' => $value['total_hours'],
+                    'total_hours_2' => $value['total_hours_2'],
+                    'crt_time' => $time,
+                ];
+            }
+            if(! empty($unit)) DeviceDetails::insert($unit);
+        }
+    }
+
+    private function getDetail($id){
+        $data = DeviceDetails::where('del_time',0)
+            ->where('device_id', $id)
+            ->get()->toArray();
+
+        $unit = [];
+        foreach ($data as $value){
+            $unit[] = [
+                'time' => date("Y-m",$value['time']),
+                'total_hours' => $value['total_hours'],
+                'total_hours_2' => $value['total_hours_2'],
+            ];
+        }
+
+        $detail = [
+            'details' => $unit,
+        ];
+
+        foreach ($detail as $key => $value) {
+            if (empty($value)) {
+                $detail[$key] = (object)[]; // 转成 stdClass 对象
+            }
+        }
+
+        return $detail;
+    }
+
+    public function deviceDel($data){
+        if($this->isEmpty($data,'id')) return [false,'请选择数据!'];
+
+        try {
+            DB::beginTransaction();
+            $time = time();
+
+            Device::where('del_time',0)
+                ->whereIn('id',$data['id'])
+                ->update(['del_time' => $time]);
+
+            DeviceDetails::where('del_time',0)
+                ->whereIn('device_id', $data['id'])
+                ->update(['del_time' => $time]);
+
+            DB::commit();
+        }catch (\Exception $exception){
+            DB::rollBack();
+            return [false,$exception->getMessage()];
+        }
+
+        return [true, ''];
+    }
+
+    public function deviceDetail($data, $user){
+        if($this->isEmpty($data,'id')) return [false,'请选择数据!'];
+        $customer = Device::where('del_time',0)
+            ->where('id',$data['id'])
+            ->first();
+        if(empty($customer)) return [false,'设备不存在或已被删除'];
+        $customer = $customer->toArray();
+        $customer['crt_name'] = Employee::where('id',$customer['crt_id'])->value('emp_name');
+        $customer['crt_time'] = $customer['crt_time'] ? date("Y-m-d H:i:s",$customer['crt_time']): '';
+        $customer['in_time'] = $customer['in_time'] ? date("Y-m-d",$customer['in_time']): '';
+
+        $details = $this->getDetail($data['id']);
+        $customer = array_merge($customer, $details);
+
+        return [true, $customer];
+    }
+
+    public function deviceCommon($data,$user, $field = []){
+        if(empty($field)) $field = Device::$field;
+
+        $model = Device::where('del_time',0)
+            ->select($field)
+            ->orderby('power', 'desc');
+
+        if(! empty($data['title'])) $model->where('title', 'LIKE', '%'.$data['title'].'%');
+        if(! empty($data['code'])) $model->where('code', 'LIKE', '%'.$data['code'].'%');
+        if(! empty($data['id'])) $model->whereIn('id', $data['id']);
+        if(! empty($data['is_use'])) $model->where('is_use', $data['is_use']);
+        if(! empty($data['type'])) $model->where('type', $data['type']);
+        if(! empty($data['type_2'])) $model->where('type_2', $data['type_2']);
+        if(! empty($data['crt_id'])) $model->whereIn('crt_id', $data['crt_id']);
+        if(! empty($data['crt_time'][0]) && ! empty($data['crt_time'][1])) {
+            $return = $this->changeDateToTimeStampAboutRange($data['crt_time']);
+            $model->where('crt_time','>=',$return[0]);
+            $model->where('crt_time','<=',$return[1]);
+        }
+        if(! empty($data['power'])){
+            $power = $data['power'];
+            $type = $power['type'] ?? '';
+
+            if($type){
+                if($type == 1){
+                    $str = '>';
+                }elseif ($type == 2){
+                    $str = '=';
+                }else{
+                    $str = '<';
+                }
+                $value = $power['value'] ?? 0;
+                $model->where('power',$str, $value);
+            }
+        }
+
+        return $model;
+    }
+
+    public function deviceList($data,$user){
+        $model = $this->deviceCommon($data, $user);
+        $list = $this->limit($model,'',$data);
+        $list = $this->fillData($list);
+
+        return [true, $list];
+    }
+
+    public function deviceRule(&$data, $user, $is_add = true){
+        if(empty($data['code'])) return [false, '编码不能为空'];
+        if(empty($data['title'])) return [false, '名称不能为空'];
+        if(empty($data['is_use'])) return [false, '是否启用不能为空'];
+        if(! isset(Device::Use[$data['is_use']])) return [false, '是否启用错误'];
+        if(empty($data['type'])) return [false, '固定资产类型不能为空'];
+        if(! isset(Device::$type[$data['type']])) return [false, '固定资产类型错误'];
+        if(! empty($data['in_time'])) $data['in_time'] = $this->changeDateToDate($data['in_time']);
+        if(empty($data['type_2'])) return [false, '类型不能为空'];
+        if(! isset(Device::$type_2[$data['type_2']])) return [false, '类型错误'];
+
+        if(! empty($data['details'])){
+            list($status, $msg) = $this->checkArrayRepeat($data['details'],'time','设备年月');
+            if(! $status) return [false, $msg];
+            foreach ($data['details'] as $key => $value){
+                if(empty($value['time'])) return [false, '设备年月不能为空'];
+                $data['details'][$key]['time'] = $this->changeDateToMonth($value['time']);
+                $res = $this->checkNumber($value['total_hours'],0,'positive');
+                if(! $res['valid']) return [false,'满勤工时:' . $res['error']];
+                $res = $this->checkNumber($value['total_hours_2'],0,'positive');
+                if(! $res['valid']) return [false,'研发工时:' . $res['error']];
+            }
+        }
+
+        if($is_add){
+            $bool = Device::where('code',$data['code'])
+                ->where('crt_id', $user['id'])
+                ->where('del_time',0)
+                ->exists();
+        }else{
+            if(empty($data['id'])) return [false,'ID不能为空'];
+            $bool = Device::where('code',$data['code'])
+                ->where('crt_id', $user['id'])
+                ->where('id','<>',$data['id'])
+                ->where('del_time',0)
+                ->exists();
+        }
+        if($bool) return [false, '编码已存在'];
+
+        return [true, $data];
+    }
+
+    public function fillData($data){
+        if(empty($data['data'])) return $data;
+
+        $emp = (new EmployeeService())->getEmployeeMap(array_unique(array_column($data['data'],'crt_id')));
+        foreach ($data['data'] as $key => $value){
+            $data['data'][$key]['crt_time'] = $value['crt_time'] ? date('Y-m-d H:i:s',$value['crt_time']) : '';
+            $data['data'][$key]['crt_name'] = $emp[$value['crt_id']] ?? '';
+            $data['data'][$key]['is_use_title'] = Device::Use[$value['is_use']] ?? '';
+            $data['data'][$key]['type_title'] = Device::$type[$value['type']] ?? '';
+            $data['data'][$key]['type_2_title'] = Device::$type_2[$value['type_2']] ?? '';
+            $data['data'][$key]['power'] = floatval($value['power']) == 0.0 ? '' : $value['power'];
+        }
+
+        return $data;
+    }
+}

Файловите разлики са ограничени, защото са твърде много
+ 1437 - 70
app/Service/U8ThirdPartyService.php


+ 641 - 56
app/Service/U8ThirtyPartyDatabaseServerService.php

@@ -141,65 +141,57 @@ class U8ThirtyPartyDatabaseServerService extends Service
 
     public function getArrivalVouchById($orderId)
     {
-        try {
-            // 1. 获取主表 (PU_ArrivalVouch) 并关联 采购类型表 (PurchaseType)
-            $main = DB::connection($this->connectionName)
-                ->table('PU_ArrivalVouch as main')
-                ->leftJoin('PurchaseType as pt', 'main.cPTCode', '=', 'pt.cPTCode') // 关联采购类型表
-                ->lock('WITH(NOLOCK)')
-                ->where('main.ID', $orderId)
-                ->select([
-                    'main.ID as id',
-                    'main.cCode as no',
-                    'main.cVenCode as supply_code',
-                    'main.cDepCode as depart_code',
-                    'main.dDate as order_date',
-                    'main.cBusType as b_type',
-                    'main.cPTCode as cg_type',
-                    'pt.cRdCode as rd_code'
-                ])
-                ->first();
-
-            if (!$main) {
-                return [false, "到货单 ID:{$orderId} 不存在"];
-            }
-
-            $order = (array)$main;
-
-            // 2. 获取子表 (PU_ArrivalVouchs)
-            $details = DB::connection($this->connectionName)
-                ->table('PU_ArrivalVouchs as detail')
-                ->lock('WITH(NOLOCK)')
-                ->where('ID', $orderId) // 子表里的 ID 关联主表的 ID
-                ->select([
-                    'detail.cInvCode',
-                    'detail.iQuantity',
-                    'detail.iQuantity as iNNum',
-                    'detail.iinvexchrate',
-                    'detail.cBatch',
-                    'detail.dPDate',
-                    'detail.dVDate',
-                    'detail.Autoid as iArrsId',
-                    'detail.ivouchrowno as iRowNo',
-                    'detail.iOriTaxCost',
-                    'detail.iTaxRate',
+        // 1. 获取主表 (PU_ArrivalVouch) 并关联 采购类型表 (PurchaseType)
+        $main = DB::connection($this->connectionName)
+            ->table('PU_ArrivalVouch as main')
+            ->leftJoin('PurchaseType as pt', 'main.cPTCode', '=', 'pt.cPTCode') // 关联采购类型表
+            ->lock('WITH(NOLOCK)')
+            ->where('main.ID', $orderId)
+            ->select([
+                'main.ID as id',
+                'main.cCode as no',
+                'main.cVenCode as supply_code',
+                'main.cDepCode as depart_code',
+                'main.dDate as order_date',
+                'main.cBusType as b_type',
+                'main.cPTCode as cg_type',
+                'pt.cRdCode as rd_code'
+            ])
+            ->first();
+
+        if (!$main) return [];
+
+        $order = (array)$main;
+
+        // 2. 获取子表 (PU_ArrivalVouchs)
+        $details = DB::connection($this->connectionName)
+            ->table('PU_ArrivalVouchs as detail')
+            ->lock('WITH(NOLOCK)')
+            ->where('ID', $orderId) // 子表里的 ID 关联主表的 ID
+            ->select([
+                'detail.cInvCode',
+                'detail.iQuantity',
+                'detail.iQuantity as iNNum',
+                'detail.iinvexchrate',
+                'detail.cBatch',
+                'detail.dPDate',
+                'detail.dVDate',
+                'detail.Autoid as iArrsId',
+                'detail.ivouchrowno as iRowNo',
+                'detail.iOriTaxCost',
+                'detail.iTaxRate',
 //                    'detail.cordercode',
-                    'detail.cWhCode',
-                ])
-                ->orderBy('detail.ivouchrowno', 'ASC') // 按 U8 原始行号排序
-                ->get();
-
-            // 3. 组合数据并返回
-            $order['details'] = $details->map(function ($item) {
-                return (array)$item;
-            })->toArray();
+                'detail.cWhCode',
+            ])
+            ->orderBy('detail.ivouchrowno', 'ASC') // 按 U8 原始行号排序
+            ->get();
 
-            return [true, $order];
+        // 3. 组合数据并返回
+        $order['details'] = $details->map(function ($item) {
+            return (array)$item;
+        })->toArray();
 
-        } catch (\Throwable $e) {
-            \Log::error("获取到货单失败: " . $e->getMessage());
-            return [false, "数据库查询异常: " . $e->getMessage()];
-        }
+        return $order;
     }
 
     /**
@@ -293,4 +285,597 @@ class U8ThirtyPartyDatabaseServerService extends Service
             return [false, []];
         }
     }
+
+    //获取单个产品报检单的明细
+    public function getBjOrder($id){
+        return DB::connection($this->connectionName)
+            ->table('QMINSPECTVOUCHERS as detail')
+            ->lock('WITH(NOLOCK)')
+            ->where('detail.ID', $id)
+            ->select('detail.*')
+            ->get()
+            ->map(function ($value) {
+                return (array)$value;
+            })
+            ->keyBy('CINVCODE')
+            ->toArray();
+    }
+
+    /**
+     * 更新报检单明细
+     * @param array $update [AutoID => [字段名 => 值], ...]
+     * @param array $insert [[字段名 => 值], [字段名 => 值], ...]
+     */
+    public function updateBjOrder($update, $insert)
+    {
+        try {
+            return DB::connection($this->connectionName)->transaction(function () use ($update, $insert) {
+
+                // 1. 处理更新部分
+                if (!empty($update)) {
+                    foreach ($update as $autoId => $fields) {
+                        DB::connection($this->connectionName)
+                            ->table('QMINSPECTVOUCHERS')
+                            ->where('AUTOID', $autoId)
+                            ->update($fields);
+                    }
+                }
+
+                // 2. 处理插入部分 (拆分行)
+                if (!empty($insert)) {
+                    // 获取当前单据的最大行号,确保新行号递增
+                    // 注意:这里需要从 $insert 的第一个元素获取 ID,因为它们都属于同一个主表单据
+                    $mainId = $insert[0]['ID'] ?? null;
+
+                    if ($mainId) {
+                        $maxRowID = DB::connection($this->connectionName)
+                                ->table('QMINSPECTVOUCHERS')
+                                ->max('AUTOID') ?? 0;
+
+                        foreach ($insert as &$newRow) {
+                            $maxRowID++;
+                            $newRow['AUTOID'] = $maxRowID;
+                        }
+
+                        // 使用批量插入提高性能
+                        DB::connection($this->connectionName)
+                            ->table('QMINSPECTVOUCHERS')
+                            ->insert($insert);
+                    }
+                }
+            });
+            return [true, ''];
+        } catch (\Throwable $e) {
+            return [false, $e->getMessage()];
+        }
+    }
+
+    public function getJyOrder($id)
+    {
+        // 1. 获取表头信息 (主表)
+        $main = DB::connection($this->connectionName)
+            ->table('QMCHECKVOUCHER')
+            ->lock('WITH(NOLOCK)')
+            ->where('ID', $id)
+            ->first();
+
+        if (!$main) {
+            return []; // 或者返回空数组 []
+        }
+
+        $main = (array)$main;
+
+        return $main;
+    }
+
+    public function getScDetails($id)
+    {
+        // 1. 获取表头信息 (主表)
+        $main = DB::connection($this->connectionName)
+            ->table('mom_orderdetail')
+            ->lock('WITH(NOLOCK)')
+            ->where('MoDid', $id)
+            ->first();
+
+        if (!$main) {
+            return []; // 或者返回空数组 []
+        }
+
+        $main = (array)$main;
+
+        return $main;
+    }
+
+    //获取单个销售订单的信息
+    public function getXsOrder($id)
+    {
+        // 1. 获取销售订单主表信息 (SO_SOMain)
+        $main = DB::connection($this->connectionName)
+            ->table('SO_SOMain')
+            ->lock('WITH(NOLOCK)')
+            ->where('ID', $id)
+            ->first();
+
+        if (!$main) {
+            return [];
+        }
+
+        $main = (array)$main;
+
+        // 2. 获取销售订单子表信息 (SO_SODetails)
+        $details = DB::connection($this->connectionName)
+            ->table('SO_SODetails')
+            ->lock('WITH(NOLOCK)')
+            ->where('ID', $id) // 子表通过 ID 关联主表
+            ->get()
+            ->map(function ($value) {
+                return (array)$value;
+            })
+            ->toArray();
+
+        // 3. 将子表数据放入 details 键中
+        $main['details'] = $details;
+
+        return $main;
+    }
+
+    public function getXsThOrder($id)
+    {
+        // 1. 获取销售退货单主表信息 (DispatchList)
+        $main = DB::connection($this->connectionName)
+            ->table('DispatchList')
+            ->lock('WITH(NOLOCK)')
+            ->where('DLID', $id) // 注意:主键叫 DLID
+            ->first();
+
+        if (!$main) {
+            return [];
+        }
+
+        $main = (array)$main;
+
+        // 2. 获取销售退货单子表信息 (DispatchLists)
+        $details = DB::connection($this->connectionName)
+            ->table('DispatchLists')
+            ->lock('WITH(NOLOCK)')
+            ->where('DLID', $id) // 通过 DLID 关联
+            ->get()
+            ->map(function ($value) {
+                return (array)$value;
+            })
+            ->toArray();
+
+        // 3. 将子表数据放入 details 键中
+        $main['details'] = $details;
+
+        return $main;
+    }
+
+    public function getFhOrder($id)
+    {
+        // 1. 获取销售发货单主表信息 (DispatchList)
+        $main = DB::connection($this->connectionName)
+            ->table('DispatchList')
+            ->lock('WITH(NOLOCK)')
+            ->where('DLID', $id) // U8发货单主键通常是 DLID
+            ->first();
+
+        if (!$main) {
+            return [];
+        }
+
+        $main = (array)$main;
+
+        // 2. 获取销售发货单子表信息 (DispatchLists)
+        $details = DB::connection($this->connectionName)
+            ->table('DispatchLists') // 注意这里是 DispatchLists
+            ->lock('WITH(NOLOCK)')
+            ->where('DLID', $id) // 子表通过 DLID 关联主表
+            ->get()
+            ->map(function ($value) {
+                return (array)$value;
+            })
+            ->toArray();
+
+        // 3. 将子表数据放入 details 键中
+        $main['details'] = $details;
+
+        return $main;
+    }
+
+    public function getCGDHDetails($id)
+    {
+        // 2. 获取采购到货单子表信息 (PU_ArrivalVouchs)
+        $details = DB::connection($this->connectionName)
+            ->table('PU_ArrivalVouchs')
+            ->lock('WITH(NOLOCK)')
+            ->where('ID', $id) // 通过 ID 关联主表
+            ->get()
+            ->map(function ($value) {
+                return (array)$value;
+            });
+
+        // 3. 将子表数据以 cInvCode 为 Key 进行组织
+        // 注意:如果一张单据里有重复的存货编码,后面的行会覆盖前面的行
+        $details = $details->keyBy('cInvCode')->toArray();
+
+        return $details;
+    }
+
+    public function getLlSQDetails($id)
+    {
+        // 1. 获取领料申请单子表信息 (MaterialAppVouchs)
+        $details = DB::connection($this->connectionName)
+            ->table('MaterialAppVouchs') // 领料申请单子表名
+            ->lock('WITH(NOLOCK)')
+            ->where('ID', $id) // 通过 ID 关联主表
+            ->get()
+            ->map(function ($value) {
+                return (array)$value;
+            });
+
+        // 2. 将子表数据以 cInvCode 为 Key 进行组织
+        // 提示:领料申请单中同一存货可能出现在不同行(如:对应不同的生产订单行)
+        // 如果确定 cInvCode 唯一,可用 keyBy;如果不唯一,建议直接返回数组或 keyBy('AutoID')
+        $details = $details->keyBy('cInvCode')->toArray();
+
+        return $details;
+    }
+
+    public function updateDhOrder($update, $insert)
+    {
+        try {
+            return DB::connection($this->connectionName)->transaction(function () use ($update, $insert) {
+
+                // 1. 处理更新部分 (子表: PU_ArrivalVouchs)
+                if (!empty($update)) {
+                    foreach ($update as $autoId => $fields) {
+                        DB::connection($this->connectionName)
+                            ->table('PU_ArrivalVouchs') // 修正为子表名
+                            ->where('Autoid', $autoId)  // U8 习惯大写 A 小写 utoid,但 SQL 不敏感
+                            ->update($fields);
+                    }
+                }
+
+                // 2. 处理插入部分 (拆分行)
+                if (!empty($insert)) {
+                    $mainId = $insert[0]['ID'] ?? null;
+
+                    if ($mainId) {
+                        // 获取全表最大 Autoid,确保全局唯一
+                        $maxRowID = DB::connection($this->connectionName)
+                                ->table('PU_ArrivalVouchs') // 修正为子表名
+                                ->max('Autoid') ?? 0;
+
+                        foreach ($insert as &$newRow) {
+                            $maxRowID++;
+                            $newRow['Autoid'] = $maxRowID;
+                        }
+
+                        // 使用批量插入
+                        DB::connection($this->connectionName)
+                            ->table('PU_ArrivalVouchs')
+                            ->insert($insert);
+                    }
+                }
+
+                return [true, '']; // 事务成功返回
+            });
+        } catch (\Throwable $e) {
+            // 打印错误堆栈有助于调试
+            return [false, "修改采购到货单失败: " . $e->getMessage()];
+        }
+    }
+
+    public function getCgOrder($id)
+    {
+        // 1. 获取采购到货单主表信息 (PU_ArrivalVouch)
+        // 关键:关联键是 ID
+        $main = DB::connection($this->connectionName)
+            ->table('PU_ArrivalVouch')
+            ->lock('WITH(NOLOCK)')
+            ->where('ID', $id)
+            ->first();
+
+        if (!$main) {
+            return [];
+        }
+
+        $main = (array)$main;
+
+        // 2. 获取采购到货单子表信息 (PU_ArrivalVouchs)
+        $details = DB::connection($this->connectionName)
+            ->table('PU_ArrivalVouchs')
+            ->lock('WITH(NOLOCK)')
+            ->where('ID', $id) // 子表通过 ID 关联主表
+            ->get()
+            ->map(function ($value) {
+                return (array)$value;
+            })
+            ->toArray();
+
+        // 3. 将子表数据放入 details 键中
+        $main['details'] = $details;
+
+        return $main;
+    }
+
+    public function getJyOrder2($id)
+    {
+        // 关联采购到货单子表 (PU_ArrivalVouchs) 获取金额字段
+        $order = DB::connection($this->connectionName)
+            ->table('QMCHECKVOUCHER as qm')
+            ->leftJoin('PU_ArrivalVouchs as arr', 'qm.SOURCEAUTOID', '=', 'arr.Autoid')
+            ->select(
+                'qm.*',
+                'arr.iCost',        // 原币无税单价
+                'arr.iOriTaxCost',  // 原币含税单价
+                'arr.iTaxRate'      // 税率
+            )
+            ->where('qm.ID', $id) // 假设这是检验单主表ID
+            ->first();
+
+        return $order ? (array)$order : [];
+    }
+
+    public function updateLLOrder($update, $insert)
+    {
+        try {
+            return DB::connection($this->connectionName)->transaction(function () use ($update, $insert) {
+
+                // 1. 处理更新部分 (子表: MaterialAppVouchs)
+                if (!empty($update)) {
+                    foreach ($update as $autoId => $fields) {
+                        DB::connection($this->connectionName)
+                            ->table('MaterialAppVouchs') // 领料申请单子表
+                            ->where('autoid', $autoId)    // 注意字段名在 U8 里可能是 autoid 或 AutoID
+                            ->update($fields);
+                    }
+                }
+
+                // 2. 处理插入部分 (拆分行/新增行)
+                if (!empty($insert)) {
+                    // 获取当前领料申请单子表的最大 Autoid,确保手动分配不冲突
+                    $maxRowID = DB::connection($this->connectionName)
+                            ->table('MaterialAppVouchs')
+                            ->max('autoid') ?? 0;
+
+                    foreach ($insert as &$newRow) {
+                        $maxRowID++;
+                        // U8 的 autoid 通常必须手动指定
+                        $newRow['autoid'] = $maxRowID;
+                    }
+
+                    // 使用批量插入
+                    DB::connection($this->connectionName)
+                        ->table('MaterialAppVouchs')
+                        ->insert($insert);
+                }
+
+                return [true, ''];
+            });
+        } catch (\Throwable $e) {
+            // 建议记录详细日志
+            return [false, "修改领料申请单失败: " . $e->getMessage()];
+        }
+    }
+
+    public function getLLOrder($id)
+    {
+        // 关键:关联键是 ID
+        $main = DB::connection($this->connectionName)
+            ->table('MaterialAppVouch')
+            ->lock('WITH(NOLOCK)')
+            ->where('ID', $id)
+            ->first();
+
+        if (!$main) {
+            return [];
+        }
+
+        $main = (array)$main;
+
+        // 2. 获取采购到货单子表信息 (PU_ArrivalVouchs)
+        $details = DB::connection($this->connectionName)
+            ->table('MaterialAppVouchs')
+            ->lock('WITH(NOLOCK)')
+            ->where('ID', $id) // 子表通过 ID 关联主表
+            ->get()
+            ->map(function ($value) {
+                return (array)$value;
+            })
+            ->toArray();
+
+        // 3. 将子表数据放入 details 键中
+        $main['details'] = $details;
+
+        return $main;
+    }
+
+    public function checkInventoryControl($invCodes)
+    {
+        if (empty($invCodes)) {
+            return [false, '存货编码为空'];
+        }
+
+        // 1. 查询存货档案
+        $list = DB::connection($this->connectionName)
+            ->table('Inventory')
+            ->whereIn('cInvCode', $invCodes)
+            ->select(['cInvCode', 'cInvName', 'bInvBatch', 'bInvQuality'])
+            ->get();
+
+        $noBatch = [];      // 未开启批次管理的
+        $noExpiration = []; // 未开启保质期管理的
+        $notFound = array_diff($invCodes, $list->pluck('cInvCode')->toArray()); // 数据库中不存在的
+
+        foreach ($list as $item) {
+            // 检查批次管理 (bInvBatch 为 0 表示未开启)
+            if (empty($item->bInvBatch)) {
+                $noBatch[] = $item->cInvCode . '(' . $item->cInvName . ')';
+            }
+
+            // 检查保质期管理 (bInvQuality 为 0 表示未开启)
+            if (empty($item->bInvQuality)) {
+                $noExpiration[] = $item->cInvCode . '(' . $item->cInvName . ')';
+            }
+        }
+
+        // 2. 组织提示结果
+        $messages = [];
+        if (!empty($noBatch)) {
+            $messages[] = "【未开启批次管理】: " . implode(', ', $noBatch);
+        }
+        if (!empty($noExpiration)) {
+            $messages[] = "【未开启保质期管理】: " . implode(', ', $noExpiration);
+        }
+        if (!empty($notFound)) {
+            $messages[] = "【档案不存在】: " . implode(', ', $notFound);
+        }
+
+        if (empty($messages)) {
+            return [true, ''];
+        }
+
+        return [false, implode("\n", $messages)];
+    }
+
+    public function rebuildDhDetails($mainId, $insertData)
+    {
+        try {
+            return DB::connection($this->connectionName)->transaction(function () use ($mainId, $insertData) {
+
+                // 1. 删除旧明细
+                DB::connection($this->connectionName)
+                    ->table('PU_ArrivalVouchs')
+                    ->where('ID', $mainId)
+                    ->delete();
+
+                // 2. 获取新的起始 Autoid
+                $maxAutoid = DB::connection($this->connectionName)
+                        ->table('PU_ArrivalVouchs')
+                        ->max('Autoid') ?? 0;
+
+                // 3. 分配新 Autoid 并插入
+                foreach ($insertData as &$row) {
+                    $maxAutoid++;
+                    $row['Autoid'] = $maxAutoid;
+                }
+
+                DB::connection($this->connectionName)
+                    ->table('PU_ArrivalVouchs')
+                    ->insert($insertData);
+
+                return [true, ''];
+            });
+        } catch (\Throwable $e) {
+            return [false, "重建明细失败: " . $e->getMessage()];
+        }
+    }
+
+    public function rebuildLLDetails($mainId, $insertData)
+    {
+        try {
+            return DB::connection($this->connectionName)->transaction(function () use ($mainId, $insertData) {
+
+                // 1. 删除旧明细 (领料申请单子表)
+                DB::connection($this->connectionName)
+                    ->table('MaterialAppVouchs')
+                    ->where('ID', $mainId)
+                    ->delete();
+
+                // 2. 获取新的起始 autoid
+                $maxAutoid = DB::connection($this->connectionName)
+                        ->table('MaterialAppVouchs')
+                        ->max('AutoID') ?? 0;
+
+                // 3. 分配新 autoid 并插入
+                foreach ($insertData as &$row) {
+                    $maxAutoid++;
+                    $row['AutoID'] = $maxAutoid;
+                }
+
+                DB::connection($this->connectionName)
+                    ->table('MaterialAppVouchs')
+                    ->insert($insertData);
+
+                return [true, ''];
+            });
+        } catch (\Throwable $e) {
+            return [false, "重组领料申请单失败: " . $e->getMessage()];
+        }
+    }
+
+    public function rebuildBjDetails1($mainId, $insertData)
+    {
+        try {
+            return DB::connection($this->connectionName)->transaction(function () use ($mainId, $insertData) {
+
+                // 1. 删除旧明细
+                DB::connection($this->connectionName)
+                    ->table('QMINSPECTVOUCHERS')
+                    ->where('ID', $mainId)
+                    ->delete();
+
+                // 2. 获取新的起始 Autoid (报检单通常是 Autoid)
+                $maxAutoid = DB::connection($this->connectionName)
+                        ->table('QMINSPECTVOUCHERS')
+                        ->max('Autoid') ?? 0;
+
+                // 3. 分配新 Autoid
+                foreach ($insertData as &$row) {
+                    $maxAutoid++;
+                    $row['Autoid'] = $maxAutoid;
+                }
+
+                // 4. 批量插入
+                DB::connection($this->connectionName)
+                    ->table('QMINSPECTVOUCHERS')
+                    ->insert($insertData);
+
+                return [true, ''];
+            });
+        } catch (\Throwable $e) {
+            return [false, "重组报检单失败: " . $e->getMessage()];
+        }
+    }
+
+    public function rebuildBjDetails($mainId, $insertData)
+    {
+        try {
+            return DB::connection($this->connectionName)->transaction(function () use ($mainId, $insertData) {
+
+                // 1. 删除旧明细
+                DB::connection($this->connectionName)
+                    ->table('QMINSPECTVOUCHERS')
+                    ->where('ID', $mainId)
+                    ->delete();
+
+                $maxAutoid = DB::connection($this->connectionName)
+                        ->table('QMINSPECTVOUCHERS')
+                        ->max('Autoid') ?? 0;
+
+                // 过滤掉不可插入的字段,特别是 UFTS
+                foreach ($insertData as $key => $row) {
+                    $maxAutoid++;
+
+                    // 彻底清理:移除 UFTS 字段,防止插入报错及 JSON 转换报错
+                    unset($row['UFTS']);
+
+                    $row['Autoid'] = $maxAutoid;
+                    $insertData[$key] = $row;
+                }
+
+                // 4. 批量插入
+                DB::connection($this->connectionName)
+                    ->table('QMINSPECTVOUCHERS')
+                    ->insert($insertData);
+
+                return [true, '操作成功'];
+            });
+        } catch (\Throwable $e) {
+            // 这里返回错误信息时,确保不包含二进制内容
+            return [false, "重组报检单失败: " . $e->getMessage()];
+        }
+    }
 }

+ 9 - 0
artisan_runner.bat

@@ -0,0 +1,9 @@
+@echo off
+:: 1. 依然建议保留清理,防止僵尸进程堆积
+taskkill /F /IM php.exe /T >nul 2>&1
+
+d:
+cd D:\phpstudy_pro\WWW\drb
+
+:: 2. 直接运行
+"D:\phpstudy_pro\Extensions\php\php7.4.3nts\php.exe" artisan schedule:run

+ 6 - 0
config/logging.php

@@ -121,6 +121,12 @@ return [
             'level' => 'debug',
             'days' => 3,
         ],
+        'u8_daily' => [
+            'driver' => 'daily',
+            'path' => storage_path('logs/u8_details.log'),
+            'level' => 'info',
+            'days' => 14, // 自动只保留最近14天的日志
+        ],
     ],
 
 ];

+ 9 - 9
config/wms.php

@@ -1,16 +1,16 @@
 <?php
 
 return [
-    "api_url" => "http://fat.informrack.com:7151/wms-admin",
+    "api_url" => env('YF_API'), //音飞接口
     "drb" => [
-        'api_host' => '',
-        'api_port' => '',
-        'database' => 'UFDATA_200_2021',
-        'user_id' => 'demo',
-        'user_password' => 'DEMO',
-        'database_port' => '41402',
-        'username' => 'sa',
-        'password' => 'Aa1',
+        'api_host' => env('U8_API'),
+        'api_port' => env('U8_API_PORT'),
+        'database' => env('U8_DATABASE'),
+        'user_id' => env('U8_USER'),
+        'user_password' => env('U8_PASS'),
+//        'database_port' => '41402',
+//        'username' => 'sa',
+//        'password' => 'Aa1',
     ],
 ];
 

Някои файлове не бяха показани, защото твърде много файлове са промени