Browse Source

星科源 大版本修改

cqp 6 days ago
parent
commit
6090151f63

+ 7 - 0
app/Http/Controllers/Api/TestController.php

@@ -4,11 +4,18 @@ namespace App\Http\Controllers\Api;
 
 use App\Jobs\ProcessDataJob;
 use App\Model\Record;
+use App\Service\U8ThirdPartyService;
 
 class TestController extends BaseController
 {
     public function test(){
+//        $record = Record::where('id',1065)->first()->toArray();
 
+        $service = new U8ThirdPartyService();
+//        list($status, $msg) = $service->puAppVouch($record);
+//        list($status, $msg) = $service->poPomain($record);
+//        list($status, $msg) = $service->purchaseInAdd($record);
+//        dd($status, $msg);
     }
 
     private function submitAgain(){

+ 317 - 0
app/Http/Controllers/Api/U8Controller.php

@@ -432,4 +432,321 @@ class U8Controller extends BaseController
             return $this->json_return(201,$data);
         }
     }
+
+    public function getPurchaseTypeList(Request $request)
+    {
+        $userData = $request->userData;
+        $service = new U8ServerService($userData);
+        $error = $service->getError();
+        if(! empty($error)) return $this->json_return(201, $error);
+
+        list($status,$data) = $service->getPurchaseTypeList($request->all(),$userData);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
+
+    public function inventoryU8List(Request $request)
+    {
+        $userData = $request->userData;
+        $service = new U8ServerService($userData);
+        $error = $service->getError();
+        if(! empty($error)) return $this->json_return(201, $error);
+
+        list($status,$data) = $service->inventoryU8List($request->all(),$userData);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
+
+    public function warehouseU8List(Request $request)
+    {
+        $userData = $request->userData;
+        $service = new U8ServerService($userData);
+        $error = $service->getError();
+        if(! empty($error)) return $this->json_return(201, $error);
+
+        list($status,$data) = $service->warehouseU8List($request->all(),$userData);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
+
+
+    // 请购单添加到本地
+
+    public function purchaseRequisitionAdd(Request $request)
+    {
+        $userData = $request->userData;
+        $service = new U8XkyServerService();
+        list($status,$data) = $service->purchaseRequisitionAdd($request->all(),$userData);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
+
+    public function purchaseRequisitionEdit(Request $request)
+    {
+        $userData = $request->userData;
+        $service = new U8XkyServerService();
+        list($status,$data) = $service->purchaseRequisitionEdit($request->all(),$userData);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
+
+    public function purchaseRequisitionList(Request $request)
+    {
+        $userData = $request->userData;
+        $service = new U8XkyServerService();
+        list($status,$data) = $service->purchaseRequisitionList($request->all(),$userData);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
+
+    public function purchaseRequisitionMyDetail(Request $request)
+    {
+        $userData = $request->userData;
+        $service = new U8XkyServerService();
+        list($status,$data) = $service->purchaseRequisitionMyDetail($request->all(),$userData);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
+
+    public function purchaseRequisitionDel(Request $request)
+    {
+        $userData = $request->userData;
+        $service = new U8XkyServerService();
+        list($status,$data) = $service->purchaseRequisitionDel($request->all(),$userData);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
+
+    // u8请购单列表
+    public function purchaseRequisitionU8List(Request $request)
+    {
+        $userData = $request->userData;
+        $service = new U8ServerService($userData);
+        $error = $service->getError();
+        if(! empty($error)) return $this->json_return(201, $error);
+
+        list($status,$data) = $service->purchaseRequisitionU8List($request->all(),$userData);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
+
+    public function getRequisitionDetails(Request $request)
+    {
+        $userData = $request->userData;
+        $service = new U8ServerService($userData);
+        $error = $service->getError();
+        if(! empty($error)) return $this->json_return(201, $error);
+
+        list($status,$data) = $service->getRequisitionDetails($request->all(),$userData);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
+
+    // 新增采购订单到本地
+
+    public function purchaseOrderAdd(Request $request)
+    {
+        $userData = $request->userData;
+        $service = new U8XkyServerService();
+        list($status,$data) = $service->purchaseOrderAdd($request->all(),$userData);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
+
+    public function purchaseOrderEdit(Request $request)
+    {
+        $userData = $request->userData;
+        $service = new U8XkyServerService();
+        list($status,$data) = $service->purchaseOrderEdit($request->all(),$userData);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
+
+    public function purchaseOrderList(Request $request)
+    {
+        $userData = $request->userData;
+        $service = new U8XkyServerService();
+        list($status,$data) = $service->purchaseOrderList($request->all(),$userData);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
+
+    public function purchaseOrderMyDetail(Request $request)
+    {
+        $userData = $request->userData;
+        $service = new U8XkyServerService();
+        list($status,$data) = $service->purchaseOrderMyDetail($request->all(),$userData);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
+
+    public function purchaseOrderDel(Request $request)
+    {
+        $userData = $request->userData;
+        $service = new U8XkyServerService();
+        list($status,$data) = $service->purchaseOrderDel($request->all(),$userData);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
+
+
+    // u8采购订单列表
+    public function purchaseOrderU8List(Request $request)
+    {
+        $userData = $request->userData;
+        $service = new U8ServerService($userData);
+        $error = $service->getError();
+        if(! empty($error)) return $this->json_return(201, $error);
+
+        list($status,$data) = $service->purchaseOrderU8List($request->all(),$userData);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
+
+    public function getPurchaseOrderDetails(Request $request)
+    {
+        $userData = $request->userData;
+        $service = new U8ServerService($userData);
+        $error = $service->getError();
+        if(! empty($error)) return $this->json_return(201, $error);
+
+        list($status,$data) = $service->getPurchaseOrderDetails($request->all(),$userData);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
+
+    // 新增采购入库单到本地
+
+    public function purchaseOrderInAdd(Request $request)
+    {
+        $userData = $request->userData;
+        $service = new U8XkyServerService();
+        list($status,$data) = $service->purchaseOrderInAdd($request->all(),$userData);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
+
+    public function purchaseOrderInEdit(Request $request)
+    {
+        $userData = $request->userData;
+        $service = new U8XkyServerService();
+        list($status,$data) = $service->purchaseOrderInEdit($request->all(),$userData);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
+
+    public function purchaseOrderInList(Request $request)
+    {
+        $userData = $request->userData;
+        $service = new U8XkyServerService();
+        list($status,$data) = $service->purchaseOrderInList($request->all(),$userData);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
+
+    public function purchaseOrderInMyDetail(Request $request)
+    {
+        $userData = $request->userData;
+        $service = new U8XkyServerService();
+        list($status,$data) = $service->purchaseOrderInMyDetail($request->all(),$userData);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
+
+    public function purchaseOrderInDel(Request $request)
+    {
+        $userData = $request->userData;
+        $service = new U8XkyServerService();
+        list($status,$data) = $service->purchaseOrderInDel($request->all(),$userData);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
 }

+ 41 - 729
app/Jobs/ProcessDataJob.php

@@ -8,6 +8,7 @@ use App\Model\Record;
 use App\Model\U8State;
 use App\Model\Vendor;
 use App\Service\U8DatabaseServerService;
+use App\Service\U8ThirdPartyService;
 use Illuminate\Bus\Queueable;
 use Illuminate\Contracts\Queue\ShouldQueue;
 use Illuminate\Foundation\Bus\Dispatchable;
@@ -51,7 +52,7 @@ class ProcessDataJob implements ShouldQueue
             ->update(['state' => U8State::state_one, 'result' => $msg]);
     }
 
-    private function syncApprovedRecords($record)
+    private function syncApprovedRecords1($record)
     {
         try {
             $LoginType = $record['login_type'];
@@ -123,748 +124,59 @@ class ProcessDataJob implements ShouldQueue
         return [true, ''];
     }
 
-    public function inventoryAddToU81($data, $service){
-        $inventory = Inventory::where('del_time', 0)
-            ->where('order_number', $data['order_number'])
-            ->where('login_type', $data['login_type'])
-            ->first();
-        if(empty($inventory)) return [false, '存货记录不存在或已被删除'];
-        $inventory = $inventory->toArray();
-
-        $title = $inventory['title'];
-        $category_code = $inventory['category_code'];
-        if(! empty($data['code'])){
-            //用户传入
-            $no = $inventory['code'];
-            $flag_title = "重填";
-        }else{
-            //生成编码
-            list($status, $msg) = $this->generate('inventory',$category_code, $service);
-            if(! $status) return [false, $msg];
-            $no = $msg;
-            $flag_title = "重试";
-        }
-
-        $inventoryData = [
-            'cInvCode' => $no,
-            'cInvName' => $title,
-            'cInvCCode' => $category_code,
-            'cInvStd' => $inventory['size'] ?? null, // 规格型号
-            'bSale'         => $inventory['bSale'], //内销
-            'bExpSale'        => $inventory['bExpSale'], //外销
-            'bPurchase'     => $inventory['bPurchase'], // 采购
-            'bSelf'         => $inventory['bSelf'], // 自制
-            'bComsume'      => $inventory['bComsume'], // 生产耗材
-            'iGroupType' => $inventory['unit_group_type'], // 计量单位组类别
-            'cGroupCode' => $inventory['unit_group_code'], //计量单位组
-            'cComUnitCode' => $inventory['unit_code'], // 主计量单位
-            'cShopUnit' => $inventory['unit_code'], // 零售计量单位
-            'iImpTaxRate' => $inventory['iImpTaxRate'], // 进项税率
-            'iTaxRate'      => $inventory['iTaxRate'], // 销项税率
-            'dSDate' => date("Y-m-d 00:00:00.000"), // 启用日期
-            'cEnterprise' => $inventory['vendor_code_title'] ?? null,
-            'iSupplyType' => '0', // 供应类型
-            'fConvertRate' => '1.0', // 转换因子
-            'bInTotalCost' => '1', // 成本累计否
-            'cPlanMethod' => 'R',
-            'cSRPolicy' => 'PE',
-            'bBomMain' => '0', // 允许BOM母件
-            'bBomSub' => '0', // 允许BOM子件
-            'bProductBill' => '0', // 允许生产订单
-            'iPlanDefault' => '1',
-            'iAllocatePrintDgt' => '4',
-            'bService' => '0',
-            'bAccessary' => '0',
-            'iInvAdvance' => '0.0',
-            'bInvQuality' => '0',
-            'bInvBatch' => '0',
-            'bInvEntrust' => '0',
-            'bInvOverStock' => '0',
-            'bFree1' => '0',
-            'bFree2' => '0',
-            'bInvType' => '0',
-            'bFree3' => '0',
-            'bFree4' => '0',
-            'bFree5' => '0',
-            'bFree6' => '0',
-            'bFree7' => '0',
-            'bFree8' => '0',
-            'bFree9' => '0',
-            'bFree10' => '0',
-            'cCreatePerson' => 'demo',
-            'cModifyPerson' => 'demo', // 变更
-            'dModifyDate' => date("Y-m-d H:i:s.000"),
-            'bFixExch' => '0',
-            'bTrack' => '0',
-            'bSerial' => '0',
-            'bBarCode' => '0',
-            'bSolitude' => '0',
-            'bSpecialties' => '0',
-            'bPropertyCheck' => '0',
-            'iRecipeBatch' => '0',
-            'bPromotSales' => '0',
-            'bPlanInv' => '0',
-            'bProxyForeign' => '0',
-            'bATOModel' => '0',
-            'bCheckItem' => '0',
-            'bPTOModel' => '0',
-            'bEquipment' => '0',
-            'bMPS' => '0',
-            'bROP' => '0',
-            'bRePlan' => '0',
-            'bBillUnite' => '0',
-            'bCutMantissa' => '0',
-            'bConfigFree1' => '0',
-            'bConfigFree2' => '0',
-            'bConfigFree3' => '0',
-            'bConfigFree4' => '0',
-            'bConfigFree5' => '0',
-            'bConfigFree6' => '0',
-            'bConfigFree7' => '0',
-            'bConfigFree8' => '0',
-            'bConfigFree9' => '0',
-            'bConfigFree10' => '0',
-            'bPeriodDT' => '0',
-            'bOutInvDT' => '0',
-            'bBackInvDT' => '0',
-            'bDTWarnInv' => '0',
-            'bImportMedicine' => '0',
-            'bFirstBusiMedicine' => '0',
-            'bForeExpland' => '0',
-            'bInvModel' => '0',
-            'bKCCutMantissa' => '0',
-            'bReceiptByDT' => '0',
-            'bCheckBSATP' => '0',
-            'bCheckFree1' => '0',
-            'bCheckFree2' => '0',
-            'bCheckFree3' => '0',
-            'bCheckFree4' => '0',
-            'bCheckFree5' => '0',
-            'bCheckFree6' => '0',
-            'bCheckFree7' => '0',
-            'bCheckFree8' => '0',
-            'bCheckFree9' => '0',
-            'bCheckFree10' => '0',
-            'iCheckATP' => '0',
-            'bPiece' => '0',
-            'bSrvItem' => '0',
-            'bSrvFittings' => '0',
-            'bSpecialOrder' => '0',
-            'bTrackSaleBill' => '0',
-            'bCheckBatch' => '0',
-            'bMngOldpart' => '0',
-        ];
-
-        $inventorySubData = [
-            'cInvSubCode' => $no,
-            'iSurenessType' => '1',
-            'bIsAttachFile' => '0',
-            'bInByProCheck' => '1',
-            'iRequireTrackStyle' => '0',
-            'iExpiratDateCalcu' => '0',
-            'iBOMExpandUnitType' => '1',
-            'iDrawType' => $inventory['iDrawType'] ?? 0, // 领用方式
-            'fInvCIQExch' => $inventory['customs_change_rate'] ?? 1, // 海关换算率
-            'bInvKeyPart' => '1',
-            'iAcceptEarlyDays' => '999',
-            'dInvCreateDatetime' => date("Y-m-d H:i:s.000"),
-            'bPUQuota' => '0',
-            'bInvROHS' => '0',
-            'bPrjMat' => '0',
-            'bInvAsset' => '0',
-            'bSrvProduct' => '0',
-            'iAcceptDelayDays' => '0',
-            'bSCkeyProjections' => '0',
-            'iSupplyPeriodType' => '1',
-            'iAvailabilityDate' => '1',
-            'bImport' => '0',
-            'bCheckSubitemCost' => '1',
-            'fRoundFactor' => '0.0',
-            'bConsiderFreeStock' => '1',
-            'bSuitRetail' => '0',
-            'bFeatureMatch' => '0',
-            'bProduceByFeatureAllocate' => '0',
-            'bMaintenance' => '0',
-            'iMaintenanceCycleUnit' => '0',
-            'bCoupon' => '0',
-            'bStoreCard' => '0',
-            'bProcessProduct' => '0',
-            'bProcessMaterial' => '0',
-            // 所有的价格自由项默认设为 '0'
-            'bPurPriceFree1' => '0', 'bPurPriceFree2' => '0', 'bPurPriceFree3' => '0', 'bPurPriceFree4' => '0', 'bPurPriceFree5' => '0',
-            'bPurPriceFree6' => '0', 'bPurPriceFree7' => '0', 'bPurPriceFree8' => '0', 'bPurPriceFree9' => '0', 'bPurPriceFree10' => '0',
-            'bOMPriceFree1' => '0', 'bOMPriceFree2' => '0', 'bOMPriceFree3' => '0', 'bOMPriceFree4' => '0', 'bOMPriceFree5' => '0',
-            'bOMPriceFree6' => '0', 'bOMPriceFree7' => '0', 'bOMPriceFree8' => '0', 'bOMPriceFree9' => '0', 'bOMPriceFree10' => '0',
-            'bSalePriceFree1' => '0', 'bSalePriceFree2' => '0', 'bSalePriceFree3' => '0', 'bSalePriceFree4' => '0', 'bSalePriceFree5' => '0',
-            'bSalePriceFree6' => '0', 'bSalePriceFree7' => '0', 'bSalePriceFree8' => '0', 'bSalePriceFree9' => '0', 'bSalePriceFree10' => '0',
-            // 所有的控制自由项默认设为 '0'
-            'bControlFreeRange1' => '0', 'bControlFreeRange2' => '0', 'bControlFreeRange3' => '0', 'bControlFreeRange4' => '0', 'bControlFreeRange5' => '0',
-            'bControlFreeRange6' => '0', 'bControlFreeRange7' => '0', 'bControlFreeRange8' => '0', 'bControlFreeRange9' => '0', 'bControlFreeRange10' => '0',
-            // 所有的批次属性默认设为 '0'
-            'bBatchProperty1' => '0', 'bBatchProperty2' => '0', 'bBatchProperty3' => '0', 'bBatchProperty4' => '0', 'bBatchProperty5' => '0',
-            'bBatchProperty6' => '0', 'bBatchProperty7' => '0', 'bBatchProperty8' => '0', 'bBatchProperty9' => '0', 'bBatchProperty10' => '0',
-            'bBondedInv' => '0',
-            'bBatchCreate' => '0',
-        ];
-
-        try {
-            $service->beginTransaction();
-
-            $exists = $service->table('Inventory')
-                ->where('cInvCode', $inventoryData['cInvCode'])
-                ->lockForUpdate() // 锁定该行,防止并发冲突
-                ->exists();
-
-            if ($exists) return [false, '存货编码已存在,请' . $flag_title];
-
-            $service->table('Inventory')->insert($inventoryData);
-            $service->table('Inventory_sub')->insert($inventorySubData);
-
-            $service->commit();
-        } catch (\Throwable $exception) {
-            $service->rollBack();
-
-            return [false, "创建用友失败: " . $exception->getMessage()];
-        }
-
-        return [true, ''];
-    }
-
-    public function inventoryAddToU82($data, $username, $service)
-    {
-        // 1. 获取本地存货记录
-        $inventory = Inventory::where('del_time', 0)
-            ->where('order_number', $data['order_number'])
-            ->where('login_type', $data['login_type'])
-            ->first();
-
-        if (empty($inventory)) {
-            return [false, '本地存货记录不存在或已被删除'];
-        }
-        $inventory = $inventory->toArray();
-
-        // 2. 提取核心属性变量并转换为布尔/整数
-        $bSale     = (int)($inventory['bSale'] ?? 0);     // 销售(内销)
-        $bExpSale  = (int)($inventory['bExpSale'] ?? 0);  // 外销
-        $bPurchase = (int)($inventory['bPurchase'] ?? 0); // 采购
-        $bSelf     = (int)($inventory['bSelf'] ?? 0);     // 自制
-        $bComsume  = (int)($inventory['bComsume'] ?? 0);  // 生产耗用
-        $bProxy    = (int)($inventory['bProxy'] ?? 0);    // 委外 (若数据库无此字段,建议默认0)
-
-        // --- 用友业务规则动态计算开始 ---
-
-        // 2.1 计划默认属性 (iPlanDefault)
-        // 规则:自制=1, 委外=2, 采购=3, 计划品=4。优先级:自制 > 委外 > 采购
-        $iPlanDefault = 0;
-        if ($bSelf) {
-            $iPlanDefault = 1;
-        } elseif ($bProxy) {
-            $iPlanDefault = 2;
-        } elseif ($bPurchase) {
-            $iPlanDefault = 3;
-        }
-
-        // 2.2 允许BOM母件 (bBomMain)
-        // 规则:自制、委外、计划品等默认为1;纯采购件默认为0
-        $bBomMain = ($bSelf || $bProxy) ? 1 : 0;
-
-        // 2.3 允许BOM子件 (bBomSub)
-        // 规则:只要涉及到生产消耗或采购,通常都允许作为子件
-        $bBomSub = ($bSelf || $bProxy || $bPurchase || $bComsume) ? 1 : 0;
-
-        // 2.4 允许生产订单 (bProductBill)
-        // 规则:只有“自制”属性为“是”时,才允许下达生产订单
-        $bProductBill = $bSelf ? 1 : 0;
-
-        // 2.5 计划方法 (cPlanMethod) 和 成本相关 (bInTotalCost)
-        // 规则:如果非内外销且非生产耗用,但勾选了BOM子件,属于辅助性物料,不计算MRP
-        $cPlanMethod = 'R'; // R: MRP/MPS计算
-        $bInTotalCost = 1;  // 默认参与成本累计
-        if (!$bSale && !$bExpSale && !$bComsume && $bBomSub) {
-            $cPlanMethod = 'N'; // N: 不计算
-            $bInTotalCost = 0;
-        }
-
-        // --- 用友业务规则动态计算结束 ---
-
-        // 3. 编码生成或使用传入编码
-        $category_code = $inventory['category_code'];
-        if (!empty($data['code'])) {
-            $no = $data['code'];
-            $flag_title = "重填";
-        } else {
-            // 调用编码生成器 (假设方法名为 generate)
-            list($status, $msg) = $this->generate('inventory', $category_code, $service);
-            if (!$status) {
-                return [false, "生成存货编码失败: " . $msg];
-            }
-            $no = $msg;
-            $flag_title = "重试";
-        }
-
-        // 4. 构建 Inventory 主表数据
-        $inventoryData = [
-            'cInvCode'          => $no,
-            'cInvName'          => $inventory['title'],
-            'cInvCCode'         => $category_code,
-            'cInvStd'           => $inventory['size'] ?? null,   // 规格型号
-            'bSale'             => $bSale,
-            'bExpSale'          => $bExpSale,
-            'bPurchase'         => $bPurchase,
-            'bSelf'             => $bSelf,
-            'bComsume'          => $bComsume,
-            'bProxyForeign'     => $bProxy,                      // 委外
-            'iGroupType'        => $inventory['unit_group_type'],
-            'cGroupCode'        => $inventory['unit_group_code'],
-            'cComUnitCode'      => $inventory['unit_code'],      // 主计量单位
-            'cShopUnit'         => $inventory['unit_code'],      // 零售单位
-            'iImpTaxRate'       => $inventory['iImpTaxRate'],    // 进项税率
-            'iTaxRate'          => $inventory['iTaxRate'],       // 销项税率
-            'dSDate'            => date("Y-m-d 00:00:00.000"),  // 启用日期
-            'cEnterprise'       => $inventory['vendor_code_title'] ?? null,
-            'iSupplyType'       => '0',                          // 领料方式:领用
-            'fConvertRate'      => '1.0',                        // 转换因子
-            'bInTotalCost'      => $bInTotalCost,                // 动态计算
-            'cPlanMethod'       => $cPlanMethod,                 // 动态计算
-            'cSRPolicy'         => 'PE',                         // 供需政策:PE
-            'bBomMain'          => $bBomMain,                    // 动态计算
-            'bBomSub'           => $bBomSub,                     // 动态计算
-            'bProductBill'      => $bProductBill,                // 动态计算
-            'iPlanDefault'      => $iPlanDefault,                // 动态计算
-            'iAllocatePrintDgt' => '4',
-            'bService'          => '0',
-            'bAccessary'        => '0',
-            'iInvAdvance'       => '0.0',
-            'bInvQuality'       => '0',
-            'bInvBatch'         => '0',
-            'bInvEntrust'       => '0',
-            'bInvOverStock'     => '0',
-            'cCreatePerson'     => $username,
-            'dModifyDate'       => date("Y-m-d H:i:s.000"),
-            'bPlanInv'          => '0',
-            'bATOModel'         => '0',
-            'bPTOModel'         => '0',
-            'bMPS'              => ($iPlanDefault == 1 || $iPlanDefault == 2) ? '1' : '0', // 只有自制委外才可能作为MPS件
-            'bROP'              => '0',
-            'bRePlan'           => '0',
-            'bCutMantissa'      => '0',
-            'bCheckBSATP'       => '0',
-            'iCheckATP'         => '0',
-            // 以下为大量自由项/控制位字段,默认设为 0
-            'bFree1' => '0', 'bFree2' => '0', 'bFree3' => '0', 'bFree4' => '0', 'bFree5' => '0',
-            'bFree6' => '0', 'bFree7' => '0', 'bFree8' => '0', 'bFree9' => '0', 'bFree10' => '0',
-            'bConfigFree1' => '0', 'bConfigFree2' => '0', 'bConfigFree3' => '0', 'bConfigFree4' => '0',
-            'bConfigFree5' => '0', 'bConfigFree6' => '0', 'bConfigFree7' => '0', 'bConfigFree8' => '0',
-            'bConfigFree9' => '0', 'bConfigFree10' => '0',
-        ];
-
-        // 5. 构建 Inventory_sub 表数据
-        $inventorySubData = [
-            'cInvSubCode'        => $no,
-            'iSurenessType'      => '1',
-            'bIsAttachFile'      => '0',
-            'bInByProCheck'      => '1',
-            'iRequireTrackStyle' => '0',
-            'iExpiratDateCalcu'  => '0',
-            'iBOMExpandUnitType' => '1',                          // BOM展开单位:主计量
-            'iDrawType'          => $inventory['iDrawType'] ?? 0, // 领用方式
-            'fInvCIQExch'        => $inventory['customs_change_rate'] ?? 1,
-            'bInvKeyPart'        => '1',
-            'iAcceptEarlyDays'   => '999',
-            'dInvCreateDatetime' => date("Y-m-d H:i:s.000"),
-            'bPUQuota'           => '0',
-            'bInvROHS'           => '0',
-            'bPrjMat'            => '0',
-            'bInvAsset'          => '0',
-            'bSrvProduct'        => '0',
-            'iAcceptDelayDays'   => '0',
-            'bSCkeyProjections'  => '0',
-            'iSupplyPeriodType'  => '1',                          // 供应期间类型:天
-            'iAvailabilityDate'  => '1',                          // 第一需求日
-            'bImport'            => '0',
-            'bCheckSubitemCost'  => '1',
-            'fRoundFactor'       => '0.0',
-            'bConsiderFreeStock' => '1',
-            'bSuitRetail'        => '0',
-            'bFeatureMatch'      => '0',
-            'bProduceByFeatureAllocate' => '0',
-            'bMaintenance'       => '0',
-            'iMaintenanceCycleUnit'     => '0',
-            'bCoupon'            => '0',
-            'bStoreCard'         => '0',
-            'bProcessProduct'    => '0',
-            'bProcessMaterial'   => '0',
-            // 自由项价格控制全部设为 0
-            'bPurPriceFree1' => '0', 'bOMPriceFree1' => '0', 'bSalePriceFree1' => '0',
-            'bControlFreeRange1' => '0', 'bBatchProperty1' => '0',
-            'bBondedInv'         => '0',
-            'bBatchCreate'       => '0',
-        ];
-
-        // 6. 执行数据库同步(使用事务)
-        try {
-            $service->beginTransaction();
-
-            // 检查存货编码是否冲突
-            $exists = $service->table('Inventory')
-                ->where('cInvCode', $no)
-                ->lockForUpdate()
-                ->exists();
-
-            if ($exists) {
-                $service->rollBack();
-                return [false, '存货编码 [' . $no . '] 在用友系统中已存在,请' . $flag_title];
-            }
-
-            // 插入主表和从表
-            $service->table('Inventory')->insert($inventoryData);
-            $service->table('Inventory_sub')->insert($inventorySubData);
-
-            $service->commit();
-        } catch (\Throwable $exception) {
-            $service->rollBack();
-            return [false, "同步用友数据库失败: " . $exception->getMessage()];
-        }
-
-        return [true, '同步成功'];
-    }
-
-    public function vendorAddToU82($data, $username,$service){
-        $vendor = Vendor::where('del_time', 0)
-            ->where('order_number', $data['order_number'])
-            ->where('login_type', $data['login_type'])
-            ->first();
-        if(empty($vendor)) return [false, '供应商记录不存在或已被删除'];
-        $vendor = $vendor->toArray();
-
-        if(! empty($vendor['code'])){
-            //用户传入
-            $no = $vendor['code'];
-            $flag_title = "重填";
-        }else{
-            //生成编码
-            list($status, $msg) = $this->generate('vendor','', $service);
-            if(! $status) return [false, $msg];
-            $no = $msg;
-            $flag_title = "重试";
-        }
-
-        $vendorData = [
-            'cVenCode' => $no,
-            'cVenName' => $vendor['title'],
-            'cVenAbbName' => $vendor['easy_title'],
-            'cVCCode' => $vendor['category_code'],
-            'dVenDevDate' => date("Y-m-d 00:00:00.000"),
-            'iVenDisRate' => '0.0',
-            'iVenCreLine' => '0.0',
-            'iVenCreDate' => '0',
-            'cVenHeadCode' => $no,
-            'iAPMoney' => '0.0',
-            'iLastMoney' => '0.0',
-            'iLRMoney' => '0.0',
-            'iFrequency' => '0',
-            'bVenTax' => '1',
-            'cCreatePerson' => $username,
-            'cModifyPerson' => $username,
-            'dModifyDate' => date("Y-m-d H:i:s.000"),
-            'iGradeABC' => '-1',
-            'bLicenceDate' => '0',
-            'bBusinessDate' => '0',
-            'bProxyDate' => '0',
-            'bPassGMP' => '0',
-            'bVenCargo' => '1', // 采购
-            'bProxyForeign' => '0', // 委外
-            'bVenService' => '0', // 服务
-            'bVenOverseas' => '0', // 国外
-            'cVenExch_name' => '人民币',
-            'iVenGSPType' => '0',
-            'iVenGSPAuth' => '-1',
-            'bVenAccPeriodMng' => '0',
-            'bVenHomeBranch' => '0',
-            'dVenCreateDatetime' => date("Y-m-d H:i:s.000"),
-            'bIsVenAttachFile' => '0',
-            'bRetail' => '0',
-        ];
-
-        try {
-            $service->beginTransaction();
-
-            $exists = $service->table('Vendor')
-                ->where('cVenCode', $vendorData['cVenCode'])
-                ->lockForUpdate() // 锁定该行,防止并发冲突
-                ->exists();
-
-            if ($exists) return [false, '供应商编码已存在,请' . $flag_title];
-
-            $service->table('Vendor')->insert($vendorData);
-
-            $service->commit();
-
-        } catch (\Throwable $exception) {
-            $service->rollBack();
-
-            return [false, "创建供应商失败: " . $exception->getMessage()];
-        }
-
-        return [true, ''];
-    }
-
-    public function generate2($type, $classCode = "", $service)
+    private function syncApprovedRecords($record)
     {
         try {
-            // 1. 确定对象映射
-            $cardNumber = ($type === 'inventory') ? 'inventory' : 'Vendor';
-            $cardNumber_name = ($type === 'inventory') ? '存货' : '供应商';
-            $table = ($type === 'inventory') ? 'Inventory' : 'Vendor';
-            $codeField = ($type === 'inventory') ? 'cInvCode' : 'cVenCode';
-
-            // 2. 获取 U8 规则定义
-            $rule = $service->table('VoucherNumber')
-                ->where('CardNumber', $cardNumber)
-                ->first();
-
-            if (!$rule) return [false, "未找到 {$cardNumber_name} 的规则定义"];
-
-            /**
-             * 3. 动态解析前缀 (Prefix1, Prefix2, Prefix3)
-             * U8 的规则通常存放在 PrefixRule 或 Prefix 字段中
-             */
-            $prefix = "";
-            for ($i = 1; $i <= 3; $i++) {
-                $ruleField = "Prefix{$i}Rule";
-                $valField = "Prefix{$i}";
-
-                // 检查规则描述
-                $ruleDesc = $rule->$ruleField ?? ''; // 例如 "存货分类编码" 或 "GYS"
-                $staticVal = $rule->$valField ?? '';
-
-                if (str_contains($ruleDesc, '分类') || str_contains($staticVal, '分类')) {
-                    // 如果规则提到“分类”,则填入传入的分类编码
-                    $prefix .= $classCode;
-                } elseif (!empty($ruleDesc)) {
-                    // 如果规则是具体的字符(如 "GYS"),直接拼接
-                    $prefix .= $ruleDesc;
-                } elseif (!empty($staticVal) && $staticVal !== '手工输入' && $staticVal !== '存货分类编码') {
-                    // 如果静态值不是提示语,则作为前缀
-                    $prefix .= $staticVal;
-                }
-            }
-
-            // 4. 获取流水号配置 (Glide)
-            $glideLen = $rule->GlideLen > 0 ? $rule->GlideLen : 4;
-            $startNum = $rule->iStartNumber ?? 1;
+            $LoginType = $record['login_type'];
+            $database = $record['database'];
 
-            // 5. 查找当前最大编码
-            $expectedLen = strlen($prefix) + $glideLen;
+            $service = new U8DatabaseServerService(['zt_database' => $database]);
+            if ($service->error) return [false, $service->error];
+            $service2 = new U8ThirdPartyService();
 
-            $lastCode = $service->table($table)
-                ->where($codeField, 'like', $prefix . '%')
-                ->whereRaw("LEN($codeField) = $expectedLen")
-                ->orderBy($codeField, 'desc')
-                ->value($codeField);
+            $time = date("Y-m-d H:i:s");
+            $time1 = date("Y-m-d 00:00:00");
 
-            // 6. 生成编码
-            if (!$lastCode) {
-                // 初始:前缀 + 起始值补零
-                $finalCode = $prefix . str_pad($startNum, $glideLen, '0', STR_PAD_LEFT);
-            } else {
-                // 截取流水号自增
-                $lastSerial = substr($lastCode, -$glideLen);
-                $nextSerial = ++$lastSerial;
+            if($record['del_time'] == 2){
+                $type = $record['type'];
+                $order_number = $record['order_number'];
+                $system_name = "system";
+                $name = DDEmployee::where('userid', $record['userid'])->where('login_type', $LoginType)->value('name');
+                if(! empty($name)) $system_name = $name;
 
-                // 溢出检查
-                if (strlen($nextSerial) > $glideLen) {
-                    return [false, "流水号已溢出"];
+                if($type == Record::type_one){
+                    list($status, $msg) = $service2->poPomain($record);
+                    if(! $status) return [false, $msg];
+                }elseif($type == Record::type_two){
+                    list($status, $msg) = $service2->puAppVouch($record);
+                    if(! $status) return [false, $msg];
+                }elseif($type == Record::type_three){
+                    list($status, $msg) = $service2->purchaseInAdd($record);
+                    if(! $status) return [false, $msg];
+                }elseif($type == Record::type_four){
+                    list($status, $msg) = $this->inventoryAddToU8($record, $name, $service->db);
+                    if(! $status) return [false, $msg];
+                }elseif($type == Record::type_five){
+                    list($status, $msg) = $this->vendorAddToU8($record, $name, $service->db);
+                    if(! $status) return [false, $msg];
                 }
-                $finalCode = $prefix . str_pad($nextSerial, $glideLen, '0', STR_PAD_LEFT);
-            }
-
-            return [true, $finalCode];
-
-        } catch (\Throwable $e) {
-            return [false, "生成失败: " . $e->getMessage()];
-        }
-    }
-
-    /**
-     * 将存货信息同步到用友 U8 系统
-     * @param array $data 包含 order_number 和 login_type 等关键参数
-     * @param string $username 当前操作人
-     * @param object $service 用友数据库连接实例 (DB Service)
-     * @return array [bool, string]
-     */
-    public function inventoryAddToU83($data, $username, $service)
-    {
-        // 1. 获取本地存货记录
-        $inventory = Inventory::where('del_time', 0)
-            ->where('order_number', $data['order_number'])
-            ->where('login_type', $data['login_type'])
-            ->first();
-
-        if (empty($inventory)) {
-            return [false, '本地存货记录不存在或已被删除'];
-        }
-        $inventory = $inventory->toArray();
-
-        // 2. 提取核心属性变量并转换为布尔/整数
-        $bSale     = (int)($inventory['bSale'] ?? 0);     // 销售(内销)
-        $bExpSale  = (int)($inventory['bExpSale'] ?? 0);  // 外销
-        $bPurchase = (int)($inventory['bPurchase'] ?? 0); // 采购
-        $bSelf     = (int)($inventory['bSelf'] ?? 0);     // 自制
-        $bComsume  = (int)($inventory['bComsume'] ?? 0);  // 生产耗用
-        $bProxy    = (int)($inventory['bProxy'] ?? 0);    // 委外
-
-        // --- 用友业务规则动态计算 ---
-        $iPlanDefault = $bSelf ? 1 : ($bProxy ? 2 : ($bPurchase ? 3 : 0));
-        $bBomMain     = ($bSelf || $bProxy) ? 1 : 0;
-        $bBomSub      = ($bSelf || $bProxy || $bPurchase || $bComsume) ? 1 : 0;
-        $bProductBill = $bSelf ? 1 : 0;
-        $cPlanMethod  = 'R';
-        $bInTotalCost = 1;
-        if (!$bSale && !$bExpSale && !$bComsume && $bBomSub) {
-            $cPlanMethod = 'N';
-            $bInTotalCost = 0;
-        }
-
-        // 3. 编码生成逻辑
-        $category_code = $inventory['category_code'];
-        $serialInfo = null;
-        if (!empty($data['code'])) {
-            $no = $data['code'];
-            $flag_title = "重填";
-        } else {
-            list($status, $res) = $this->generate('inventory', $category_code, $service);
-            if (!$status) return [false, "生成存货编码失败: " . $res];
-            $no = $res['finalCode'];
-            $serialInfo = $res;
-            $flag_title = "重试";
-        }
-
-        // 4. 构建 Inventory 主表数据 (还原所有原始字段)
-        $inventoryData = [
-            'cInvCode'          => $no,
-            'cInvName'          => $inventory['title'],
-            'cInvCCode'         => $category_code,
-            'cInvStd'           => $inventory['size'] ?? null,
-            'bSale'             => $bSale,
-            'bExpSale'          => $bExpSale,
-            'bPurchase'         => $bPurchase,
-            'bSelf'             => $bSelf,
-            'bComsume'          => $bComsume,
-            'bProxyForeign'     => $bProxy,
-            'iGroupType'        => $inventory['unit_group_type'],
-            'cGroupCode'        => $inventory['unit_group_code'],
-            'cComUnitCode'      => $inventory['unit_code'],
-            'cShopUnit'         => $inventory['unit_code'],
-            'iImpTaxRate'       => $inventory['iImpTaxRate'],
-            'iTaxRate'          => $inventory['iTaxRate'],
-            'dSDate'            => date("Y-m-d 00:00:00.000"),
-            'cEnterprise'       => $inventory['vendor_code_title'] ?? null,
-            'iSupplyType'       => '0',
-            'fConvertRate'      => '1.0',
-            'bInTotalCost'      => $bInTotalCost,
-            'cPlanMethod'       => $cPlanMethod,
-            'cSRPolicy'         => 'PE',
-            'bBomMain'          => $bBomMain,
-            'bBomSub'           => $bBomSub,
-            'bProductBill'      => $bProductBill,
-            'iPlanDefault'      => $iPlanDefault,
-            'iAllocatePrintDgt' => '4',
-            'bService'          => '0',
-            'bAccessary'        => '0',
-            'iInvAdvance'       => '0.0',
-            'bInvQuality'       => '0',
-            'bInvBatch'         => '0',
-            'bInvEntrust'       => '0',
-            'bInvOverStock'     => '0',
-            'cCreatePerson'     => $username,
-            'dModifyDate'       => date("Y-m-d H:i:s.000"),
-            'bPlanInv'          => '0',
-            'bATOModel'         => '0',
-            'bPTOModel'         => '0',
-            'bMPS'              => ($iPlanDefault == 1 || $iPlanDefault == 2) ? '1' : '0',
-            'bROP'              => '0',
-            'bRePlan'           => '0',
-            'bCutMantissa'      => '0',
-            'bCheckBSATP'       => '0',
-            'iCheckATP'         => '0',
-            'bFree1' => '0', 'bFree2' => '0', 'bFree3' => '0', 'bFree4' => '0', 'bFree5' => '0',
-            'bFree6' => '0', 'bFree7' => '0', 'bFree8' => '0', 'bFree9' => '0', 'bFree10' => '0',
-            'bConfigFree1' => '0', 'bConfigFree2' => '0', 'bConfigFree3' => '0', 'bConfigFree4' => '0',
-            'bConfigFree5' => '0', 'bConfigFree6' => '0', 'bConfigFree7' => '0', 'bConfigFree8' => '0',
-            'bConfigFree9' => '0', 'bConfigFree10' => '0',
-        ];
 
-        // 5. 构建 Inventory_sub 表数据
-        $inventorySubData = [
-            'cInvSubCode'        => $no,
-            'iSurenessType'      => '1',
-            'bIsAttachFile'      => '0',
-            'bInByProCheck'      => '1',
-            'iRequireTrackStyle' => '0',
-            'iExpiratDateCalcu'  => '0',
-            'iBOMExpandUnitType' => '1',
-            'iDrawType'          => $inventory['iDrawType'] ?? 0,
-            'fInvCIQExch'        => $inventory['customs_change_rate'] ?? 1,
-            'bInvKeyPart'        => '1',
-            'iAcceptEarlyDays'   => '999',
-            'dInvCreateDatetime' => date("Y-m-d H:i:s.000"),
-            'bPUQuota'           => '0',
-            'bInvROHS'           => '0',
-            'bPrjMat'            => '0',
-            'bInvAsset'          => '0',
-            'bSrvProduct'        => '0',
-            'iAcceptDelayDays'   => '0',
-            'bSCkeyProjections'  => '0',
-            'iSupplyPeriodType'  => '1',
-            'iAvailabilityDate'  => '1',
-            'bImport'            => '0',
-            'bCheckSubitemCost'  => '1',
-            'fRoundFactor'       => '0.0',
-            'bConsiderFreeStock' => '1',
-            'bSuitRetail'        => '0',
-            'bFeatureMatch'      => '0',
-            'bProduceByFeatureAllocate' => '0',
-            'bMaintenance'       => '0',
-            'iMaintenanceCycleUnit'     => '0',
-            'bCoupon'            => '0',
-            'bStoreCard'         => '0',
-            'bProcessProduct'    => '0',
-            'bProcessMaterial'   => '0',
-            'bPurPriceFree1' => '0', 'bOMPriceFree1' => '0', 'bSalePriceFree1' => '0',
-            'bControlFreeRange1' => '0', 'bBatchProperty1' => '0',
-            'bBondedInv'         => '0',
-            'bBatchCreate'       => '0',
-        ];
-
-        // 6. 执行同步
-        try {
-            $service->beginTransaction();
-
-            $exists = $service->table('Inventory')->where('cInvCode', $no)->lockForUpdate()->exists();
-            if ($exists) {
-                $service->rollBack();
-                return [false, '存货编码 [' . $no . '] 在用友系统中已存在,请' . $flag_title];
-            }
-
-            $service->table('Inventory')->insert($inventoryData);
-            $service->table('Inventory_sub')->insert($inventorySubData);
+                // 更新本地数据 通过状态
+                Record::where("id", $record['id'])->update(['del_time' => 3]);
 
-            // 更新流水号表
-            if ($serialInfo) {
-                $service->table('VoucherHistory')->updateOrInsert(
-                    ['CardNumber' => 'inventory', 'cContent' => '存货分类编码', 'cSeed' => $category_code],
-                    ['cNumber' => $serialInfo['serial']]
+                // 更新状态为 通过状态
+                U8State::updateOrCreate(
+                    ['order_number' => $record['order_number'], 'login_type' => $record['login_type'], 'type' => $record['type']],
+                    ['state' => U8State::state_one]
                 );
             }
 
-            $service->commit();
-        } catch (\Throwable $exception) {
-            $service->rollBack();
-            return [false, "同步用友数据库失败: " . $exception->getMessage()];
+            $service->close();
+        } catch (\Throwable $e) {
+            return [false, $e->getMessage()];
         }
 
-        return [true, '同步成功'];
+        return [true, ''];
     }
 
     public function inventoryAddToU8($data, $username, $service)

+ 14 - 0
app/Model/PoPodetails.php

@@ -0,0 +1,14 @@
+<?php
+
+namespace App\Model;
+
+use Illuminate\Database\Eloquent\Model;
+
+class PoPodetails extends Model
+{
+    protected $guarded = [];
+    protected $table = "po_podetails"; //指定表
+    const CREATED_AT = null;
+    const UPDATED_AT = null;
+    protected $dateFormat = 'U';
+}

+ 34 - 0
app/Model/PoPomain.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace App\Model;
+
+use Illuminate\Database\Eloquent\Model;
+
+class PoPomain extends Model
+{
+    protected $guarded = [];
+    protected $table = "po_pomain"; //指定表
+    const CREATED_AT = 'crt_time';
+    const UPDATED_AT = 'upd_time';
+    protected $dateFormat = 'U';
+
+    const State_minus_one = -1;//驳回
+    const STATE_ZERO = 0;//未审核
+    const STATE_ONE = 1;//待审核
+    const STATE_TWO = 2;//已审核
+    public static $name = [
+        self::State_minus_one => '驳回',
+        self::STATE_ZERO => '未审核',
+        self::STATE_ONE => '待审核',
+        self::STATE_TWO => '已审核',
+    ];
+
+    const Order_type = "po_pomain";
+
+    /**
+     * 属性转换为原生类型
+     */
+    protected $casts = [
+        'cappcode' => 'array', // 声明 content 字段读取时自动转为数组
+    ];
+}

+ 27 - 0
app/Model/PuAppVouch.php

@@ -0,0 +1,27 @@
+<?php
+
+namespace App\Model;
+
+use Illuminate\Database\Eloquent\Model;
+
+class PuAppVouch extends Model
+{
+    protected $guarded = [];
+    protected $table = "pu_appvouch"; //指定表
+    const CREATED_AT = 'crt_time';
+    const UPDATED_AT = 'upd_time';
+    protected $dateFormat = 'U';
+
+    const State_minus_one = -1;//驳回
+    const STATE_ZERO = 0;//未审核
+    const STATE_ONE = 1;//待审核
+    const STATE_TWO = 2;//已审核
+    public static $name = [
+        self::State_minus_one => '驳回',
+        self::STATE_ZERO => '未审核',
+        self::STATE_ONE => '待审核',
+        self::STATE_TWO => '已审核',
+    ];
+
+    const Order_type = "pu_appvouch";
+}

+ 14 - 0
app/Model/PuAppVouchs.php

@@ -0,0 +1,14 @@
+<?php
+
+namespace App\Model;
+
+use Illuminate\Database\Eloquent\Model;
+
+class PuAppVouchs extends Model
+{
+    protected $guarded = [];
+    protected $table = "pu_appvouchs"; //指定表
+    const CREATED_AT = null;
+    const UPDATED_AT = null;
+    protected $dateFormat = 'U';
+}

+ 41 - 0
app/Model/RdRecord01.php

@@ -0,0 +1,41 @@
+<?php
+
+namespace App\Model;
+
+use Illuminate\Database\Eloquent\Model;
+
+class RdRecord01 extends Model
+{
+    protected $guarded = [];
+    protected $table = "rd_record01"; //指定表
+    const CREATED_AT = 'crt_time';
+    const UPDATED_AT = 'upd_time';
+    protected $dateFormat = 'U';
+
+    const State_minus_one = -1;//驳回
+    const STATE_ZERO = 0;//未审核
+    const STATE_ONE = 1;//待审核
+    const STATE_TWO = 2;//已审核
+    public static $name = [
+        self::State_minus_one => '驳回',
+        self::STATE_ZERO => '未审核',
+        self::STATE_ONE => '待审核',
+        self::STATE_TWO => '已审核',
+    ];
+
+    const bredvouch_zero = 0;
+    const bredvouch_one = 1;
+    public static $bredvouch_title = [
+        self::bredvouch_zero => '蓝字采购入库单',
+        self::bredvouch_one => '红字采购入库单',
+    ];
+
+    const Order_type = "rd_record01";
+
+    /**
+     * 属性转换为原生类型
+     */
+    protected $casts = [
+        'cOrderCode' => 'array', // 声明 content 字段读取时自动转为数组
+    ];
+}

+ 14 - 0
app/Model/RdRecords01.php

@@ -0,0 +1,14 @@
+<?php
+
+namespace App\Model;
+
+use Illuminate\Database\Eloquent\Model;
+
+class RdRecords01 extends Model
+{
+    protected $guarded = [];
+    protected $table = "rd_records01"; //指定表
+    const CREATED_AT = null;
+    const UPDATED_AT = null;
+    protected $dateFormat = 'U';
+}

+ 170 - 3
app/Service/DingService.php

@@ -618,7 +618,8 @@ dd($res);
         return [true, $formData];
     }
 
-    private function typeOne($userOrder){
+    // 来源于用友 旧----------------------------------
+    private function typeOne1($userOrder){
         if (empty($userOrder)) return [];
         $formData = [
             [
@@ -672,7 +673,7 @@ dd($res);
         return $formData;
     }
 
-    private function typeTwo($userOrder){
+    private function typeTwo2($userOrder){
         if (empty($userOrder)) return [];
         $formData = [
             [
@@ -726,7 +727,7 @@ dd($res);
         return $formData;
     }
 
-    private function typeThree($userOrder){
+    private function typeThree3($userOrder){
         if (empty($userOrder)) return [];
         $formData = [
             [
@@ -784,6 +785,172 @@ dd($res);
         return $formData;
     }
 
+    private function typeOne($userOrder){
+        if (empty($userOrder)) return [];
+        $formData = [
+            [
+                "name"  => "订单日期",
+                "value" => $userOrder['order_time']
+            ],
+            [
+                "name"  => "流水号",
+                "value" => $userOrder['order_number'] ?? ''
+            ],
+            [
+                "name"  => "业务类型",
+                "value" => $userOrder['cBusType'] ?? ''
+            ],
+            [
+                "name"  => "供应商",
+                "value" => $userOrder['cVenCodeTitle'] ?? ''
+            ],
+            [
+                "name"  => "制单人",
+                "value" => $userOrder['crt_name'] ?? ''
+            ],
+            [
+                "name"  => "表体", // 对应 TableField 的 label
+                "value" => json_encode(
+                    array_map(function($item){
+                        return [
+                            [
+                                "name"  => "存货名称",
+                                "value" => $item['name'] ?? ''
+                            ],
+                            [
+                                "name"  => "数量",
+                                "value" => $item['quantity'] ?? 0
+                            ],
+                            [
+                                "name"  => "主计量", // 修改这里,对应模板字段
+                                "value" => $item['unit'] ?? ''
+                            ],
+                            [
+                                "name"  => "原币价税合计",
+                                "value" => round($item['quantity'] * $item['price'], 2)
+                            ]
+                        ];
+                    }, $userOrder['detail'] ?? []),
+                    JSON_UNESCAPED_UNICODE
+                )
+            ]
+        ];
+
+        return $formData;
+    }
+
+    private function typeTwo($userOrder){
+        if (empty($userOrder)) return [];
+        $formData = [
+            [
+                "name"  => "流水号",
+                "value" => $userOrder['order_number'] ?? ''
+            ],
+            [
+                "name"  => "日期",
+                "value" => $userOrder['order_time']
+            ],
+            [
+                "name"  => "业务类型",
+                "value" => $userOrder['cBusType'] ?? ''
+            ],
+            [
+                "name"  => "请购人",
+                "value" => ''
+            ],
+            [
+                "name"  => "制单人",
+                "value" => $userOrder['crt_name'] ?? ''
+            ],
+            [
+                "name"  => "表体", // 对应 TableField 的 label
+                "value" => json_encode(
+                    array_map(function($item){
+                        return [
+                            [
+                                "name"  => "存货名称",
+                                "value" => $item['name'] ?? ''
+                            ],
+                            [
+                                "name"  => "数量",
+                                "value" => $item['quantity'] ?? 0
+                            ],
+                            [
+                                "name"  => "主计量", // 修改这里,对应模板字段
+                                "value" => $item['unit'] ?? ''
+                            ],
+                            [
+                                "name"  => "要求到货日期",
+                                "value" => $item['dRequirDate'] ?? ''
+                            ]
+                        ];
+                    }, $userOrder['detail'] ?? []),
+                    JSON_UNESCAPED_UNICODE
+                )
+            ]
+        ];
+
+        return $formData;
+    }
+
+    private function typeThree($userOrder){
+        if (empty($userOrder)) return [];
+        $formData = [
+            [
+                "name"  => "流水号",
+                "value" => $userOrder['order_number'] ?? ''
+            ],
+            [
+                "name"  => "入库日期",
+                "value" => date('Y-m-d', strtotime($userOrder['order_date'] ?? ''))
+            ],
+            [
+                "name"  => "仓库",
+                "value" => $userOrder['warehouseCodeTitle'] ?? ''
+            ],
+            [
+                "name"  => "入库类别",
+                "value" => $userOrder['cRdCodeTitle'] ?? ''
+            ],
+            [
+                "name"  => "供货单位",
+                "value" => $userOrder['cVenCodeTitle'] ?? ''
+            ],
+            [
+                "name"  => "制单人",
+                "value" => $userOrder['crt_name'] ?? ''
+            ],
+            [
+                "name"  => "表体", // 对应 TableField 的 label
+                "value" => json_encode(
+                    array_map(function($item){
+                        return [
+                            [
+                                "name"  => "存货名称",
+                                "value" => $item['name'] ?? ''
+                            ],
+                            [
+                                "name"  => "数量",
+                                "value" => $item['quantity'] ?? 0,
+                            ],
+                            [
+                                "name"  => "主计量", // 修改这里,对应模板字段
+                                "value" => $item['unit'] ?? ''
+                            ],
+                            [
+                                "name"  => "原币价税合计",
+                                "value" => round($item['quantity'] * $item['price'], 2)
+                            ]
+                        ];
+                    }, $userOrder['detail'] ?? []),
+                    JSON_UNESCAPED_UNICODE
+                )
+            ]
+        ];
+
+        return $formData;
+    }
+
     private function typeFour($userOrder){
         if (empty($userOrder)) return [];
         $formData = [

+ 37 - 0
app/Service/Service.php

@@ -862,4 +862,41 @@ class Service
         // 3. 拼接输出
         return $prefix . $period . str_pad($sequence, $length, '0', STR_PAD_LEFT);
     }
+
+    /**
+     * 判断地址(IP或域名)是否网络通畅
+     * @param string $address 域名或IP
+     * @param int $port 端口(U8通常是1433,或者你的7151)
+     * @param int $timeout 超时秒数
+     * @return array [bool 是否通畅, string 结果描述]
+     */
+    function checkNetworkStatus($address, $port = 80, $timeout = 2) {
+        // 1. 去掉可能存在的空格或 http 协议头
+        $address = str_replace(['http://', 'https://'], '', trim($address));
+        $address = explode('/', $address)[0]; // 只取域名部分
+
+        $isIp = filter_var($address, FILTER_VALIDATE_IP);
+        $targetIp = $address;
+
+        // 2. 如果是域名,尝试解析
+        if (!$isIp) {
+            $targetIp = gethostbyname($address);
+            if ($targetIp === $address) {
+                return [false, "域名解析失败"];
+            }
+        }
+
+        // 3. 尝试建立 TCP 连接(这是判断通畅的核心)
+        $startTime = microtime(true);
+        $fp = @fsockopen($targetIp, $port, $errno, $errstr, $timeout);
+        $endTime = microtime(true);
+
+        if (!$fp) {
+            return [false, "无法连接到 {$address}:{$port}。错误: {$errstr} ({$errno})"];
+        }
+
+        fclose($fp);
+        $ms = round(($endTime - $startTime) * 1000, 2);
+        return [true, "连接成功!目标IP: {$targetIp},响应延迟: {$ms}ms"];
+    }
 }

+ 323 - 341
app/Service/U8ServerService.php

@@ -368,6 +368,7 @@ class U8ServerService extends Service
 
         $order = Inventory::where('del_time',0)
             ->where('order_number', $data['order_number'])
+            ->where('login_type', $user['login_type'])
             ->first();
         if(empty($order)) return [false, '存货不存在'];
         $order = $order->toArray() ;
@@ -381,6 +382,7 @@ class U8ServerService extends Service
 
         $order = Vendor::where('del_time',0)
             ->where('order_number', $data['order_number'])
+            ->where('login_type', $user['login_type'])
             ->first();
         if(empty($order)) return [false, '供应商不存在'];
         $order = $order->toArray() ;
@@ -391,15 +393,20 @@ class U8ServerService extends Service
 
     public function getOrderDetails($data,$user){
         $type = $data['type'];
+        [$success, $order] = [false, '异常错误'];
+
         if($type == 1){
             // 采购单
-            [$success, $order] = $this->purchaseOrderDetail($data,$user);
+//            [$success, $order] = $this->purchaseOrderDetail($data,$user);
+            [$success, $order] = (new U8XkyServerService())->purchaseOrderMyDetail($data,$user);
         }elseif ($type == 2){
             // 采购请购单
-            [$success, $order] = $this->purchaseRequisitionDetail($data,$user);
+//            [$success, $order] = $this->purchaseRequisitionDetail($data,$user);
+            [$success, $order] = (new U8XkyServerService())->purchaseRequisitionMyDetail($data,$user);
         }elseif ($type == 3){
             // 采购入库
-            [$success, $order] = $this->purchaseInOrderDetail($data,$user);
+//            [$success, $order] = $this->purchaseInOrderDetail($data,$user);
+            [$success, $order] = (new U8XkyServerService())->purchaseOrderInMyDetail($data,$user);
         }elseif ($type == 4){
             // 存货
             [$success, $order] = $this->inventoryDetail($data,$user);
@@ -756,370 +763,345 @@ class U8ServerService extends Service
         return [true, $list];
     }
 
+    // U8 采购类型
+    public function getPurchaseTypeList($data, $user)
+    {
+        $list = $this->databaseService->table('PurchaseType as P')
+            // 核心修改:左关联收发类别表 Rd_Style
+            ->leftJoin('Rd_Style as R', 'R.cRdCode', '=', 'P.cRdCode')
+            ->select(
+                'P.cPTCode',     // 采购类型编码 (如: 01, 02)
+                'P.cPTName',     // 采购类型名称 (如: 国内采购, 国外采购)
+                'P.bDefault',    // 是否默认值
+                // 核心修改:查出对应的默认收发类别编码和名称
+                DB::raw("ISNULL(P.cRdCode, '') as rd_code"),
+                DB::raw("ISNULL(R.cRdName, '') as rd_name")
+            )
+            ->orderBy('P.bDefault', 'DESC')
+            ->get();
 
-    //U8 存货新增到用友
-    public function inventoryAddToU8($data, $user){
-        $inventory = Inventory::where('del_time', 0)
-            ->where('id', $data['id'])
-            ->first();
-        if(empty($inventory)) return [false, '存货记录不存在或已被删除'];
-        $inventory = $inventory->toArray();
-
-        $title = $inventory['title'];
-        $category_code = $inventory['category_code'];
-        if(! empty($data['code'])){
-            //用户传入
-            $no = $inventory['code'];
-            $flag_title = "重填";
-        }else{
-            //生成编码
-            list($status, $msg) = $this->generate('inventory','1005');
-            if(! $status) return [false, $msg];
-            $no = $msg;
-            $flag_title = "重试";
-        }
+        return [true, $list];
+    }
 
-        $inventoryData = [
-            'cInvCode' => $no,
-            'cInvName' => $title,
-            'cInvCCode' => $category_code,
-            'cInvStd' => $inventory['size'] ?? null, // 规格型号
-            'bSale'         => $inventory['bSale'], //内销
-            'bExpSale'        => $inventory['bExpSale'], //外销
-            'bPurchase'     => $inventory['bPurchase'], // 采购
-            'bSelf'         => $inventory['bSelf'], // 自制
-            'bComsume'      => $inventory['bComsume'], // 生产耗材
-            'iGroupType' => $inventory['unit_group_type'], // 计量单位组类别
-            'cGroupCode' => $inventory['unit_group_code'], //计量单位组
-            'cComUnitCode' => $inventory['unit_code'], // 主计量单位
-            'cShopUnit' => $inventory['unit_code'], // 零售计量单位
-            'iImpTaxRate' => $inventory['iImpTaxRate'], // 进项税率
-            'iTaxRate'      => $inventory['iTaxRate'], // 销项税率
-            'dSDate' => date("Y-m-d 00:00:00.000"), // 启用日期
-            'cEnterprise' => $inventory['vendor_code_title'] ?? null,
-            'iSupplyType' => '0', // 供应类型
-            'fConvertRate' => '1.0', // 转换因子
-            'bInTotalCost' => '1', // 成本累计否
-            'cPlanMethod' => 'R',
-            'cSRPolicy' => 'PE',
-            'bBomMain' => '0', // 允许BOM母件
-            'bBomSub' => '0', // 允许BOM子件
-            'bProductBill' => '0', // 允许生产订单
-            'iPlanDefault' => '1',
-            'iAllocatePrintDgt' => '4',
-            'bService' => '0',
-            'bAccessary' => '0',
-            'iInvAdvance' => '0.0',
-            'bInvQuality' => '0',
-            'bInvBatch' => '0',
-            'bInvEntrust' => '0',
-            'bInvOverStock' => '0',
-            'bFree1' => '0',
-            'bFree2' => '0',
-            'bInvType' => '0',
-            'bFree3' => '0',
-            'bFree4' => '0',
-            'bFree5' => '0',
-            'bFree6' => '0',
-            'bFree7' => '0',
-            'bFree8' => '0',
-            'bFree9' => '0',
-            'bFree10' => '0',
-            'cCreatePerson' => 'demo',
-            'cModifyPerson' => 'demo', // 变更
-            'dModifyDate' => date("Y-m-d H:i:s.000"),
-            'bFixExch' => '0',
-            'bTrack' => '0',
-            'bSerial' => '0',
-            'bBarCode' => '0',
-            'bSolitude' => '0',
-            'bSpecialties' => '0',
-            'bPropertyCheck' => '0',
-            'iRecipeBatch' => '0',
-            'bPromotSales' => '0',
-            'bPlanInv' => '0',
-            'bProxyForeign' => '0',
-            'bATOModel' => '0',
-            'bCheckItem' => '0',
-            'bPTOModel' => '0',
-            'bEquipment' => '0',
-            'bMPS' => '0',
-            'bROP' => '0',
-            'bRePlan' => '0',
-            'bBillUnite' => '0',
-            'bCutMantissa' => '0',
-            'bConfigFree1' => '0',
-            'bConfigFree2' => '0',
-            'bConfigFree3' => '0',
-            'bConfigFree4' => '0',
-            'bConfigFree5' => '0',
-            'bConfigFree6' => '0',
-            'bConfigFree7' => '0',
-            'bConfigFree8' => '0',
-            'bConfigFree9' => '0',
-            'bConfigFree10' => '0',
-            'bPeriodDT' => '0',
-            'bOutInvDT' => '0',
-            'bBackInvDT' => '0',
-            'bDTWarnInv' => '0',
-            'bImportMedicine' => '0',
-            'bFirstBusiMedicine' => '0',
-            'bForeExpland' => '0',
-            'bInvModel' => '0',
-            'bKCCutMantissa' => '0',
-            'bReceiptByDT' => '0',
-            'bCheckBSATP' => '0',
-            'bCheckFree1' => '0',
-            'bCheckFree2' => '0',
-            'bCheckFree3' => '0',
-            'bCheckFree4' => '0',
-            'bCheckFree5' => '0',
-            'bCheckFree6' => '0',
-            'bCheckFree7' => '0',
-            'bCheckFree8' => '0',
-            'bCheckFree9' => '0',
-            'bCheckFree10' => '0',
-            'iCheckATP' => '0',
-            'bPiece' => '0',
-            'bSrvItem' => '0',
-            'bSrvFittings' => '0',
-            'bSpecialOrder' => '0',
-            'bTrackSaleBill' => '0',
-            'bCheckBatch' => '0',
-            'bMngOldpart' => '0',
-        ];
-
-        $inventorySubData = [
-            'cInvSubCode' => $no,
-            'iSurenessType' => '1',
-            'bIsAttachFile' => '0',
-            'bInByProCheck' => '1',
-            'iRequireTrackStyle' => '0',
-            'iExpiratDateCalcu' => '0',
-            'iBOMExpandUnitType' => '1',
-            'iDrawType' => $inventory['iDrawType'] ?? 0, // 领用方式
-            'fInvCIQExch' => $inventory['customs_change_rate'] ?? 1, // 海关换算率
-            'bInvKeyPart' => '1',
-            'iAcceptEarlyDays' => '999',
-            'dInvCreateDatetime' => date("Y-m-d H:i:s.000"),
-            'bPUQuota' => '0',
-            'bInvROHS' => '0',
-            'bPrjMat' => '0',
-            'bInvAsset' => '0',
-            'bSrvProduct' => '0',
-            'iAcceptDelayDays' => '0',
-            'bSCkeyProjections' => '0',
-            'iSupplyPeriodType' => '1',
-            'iAvailabilityDate' => '1',
-            'bImport' => '0',
-            'bCheckSubitemCost' => '1',
-            'fRoundFactor' => '0.0',
-            'bConsiderFreeStock' => '1',
-            'bSuitRetail' => '0',
-            'bFeatureMatch' => '0',
-            'bProduceByFeatureAllocate' => '0',
-            'bMaintenance' => '0',
-            'iMaintenanceCycleUnit' => '0',
-            'bCoupon' => '0',
-            'bStoreCard' => '0',
-            'bProcessProduct' => '0',
-            'bProcessMaterial' => '0',
-            // 所有的价格自由项默认设为 '0'
-            'bPurPriceFree1' => '0', 'bPurPriceFree2' => '0', 'bPurPriceFree3' => '0', 'bPurPriceFree4' => '0', 'bPurPriceFree5' => '0',
-            'bPurPriceFree6' => '0', 'bPurPriceFree7' => '0', 'bPurPriceFree8' => '0', 'bPurPriceFree9' => '0', 'bPurPriceFree10' => '0',
-            'bOMPriceFree1' => '0', 'bOMPriceFree2' => '0', 'bOMPriceFree3' => '0', 'bOMPriceFree4' => '0', 'bOMPriceFree5' => '0',
-            'bOMPriceFree6' => '0', 'bOMPriceFree7' => '0', 'bOMPriceFree8' => '0', 'bOMPriceFree9' => '0', 'bOMPriceFree10' => '0',
-            'bSalePriceFree1' => '0', 'bSalePriceFree2' => '0', 'bSalePriceFree3' => '0', 'bSalePriceFree4' => '0', 'bSalePriceFree5' => '0',
-            'bSalePriceFree6' => '0', 'bSalePriceFree7' => '0', 'bSalePriceFree8' => '0', 'bSalePriceFree9' => '0', 'bSalePriceFree10' => '0',
-            // 所有的控制自由项默认设为 '0'
-            'bControlFreeRange1' => '0', 'bControlFreeRange2' => '0', 'bControlFreeRange3' => '0', 'bControlFreeRange4' => '0', 'bControlFreeRange5' => '0',
-            'bControlFreeRange6' => '0', 'bControlFreeRange7' => '0', 'bControlFreeRange8' => '0', 'bControlFreeRange9' => '0', 'bControlFreeRange10' => '0',
-            // 所有的批次属性默认设为 '0'
-            'bBatchProperty1' => '0', 'bBatchProperty2' => '0', 'bBatchProperty3' => '0', 'bBatchProperty4' => '0', 'bBatchProperty5' => '0',
-            'bBatchProperty6' => '0', 'bBatchProperty7' => '0', 'bBatchProperty8' => '0', 'bBatchProperty9' => '0', 'bBatchProperty10' => '0',
-            'bBondedInv' => '0',
-            'bBatchCreate' => '0',
-        ];
+    // 存货档案
+    public function inventoryU8List($data, $user)
+    {
+        // 获取前端传过来的查询参数
+        $search_code = $data['code'] ?? ""; // 存货编码查询条件
+        $search_name = $data['name'] ?? ""; // 存货名称查询条件
+
+        $model = $this->databaseService->table('Inventory as i')
+            // 核心修改:关联计量单位表获取单位名称
+            ->leftJoin('ComputationUnit as u', 'u.cComUnitCode', 'i.cComUnitCode')
+            // 当编码查询条件不为空时,进行模糊查询
+            ->when(!empty($search_code), function ($query) use ($search_code) {
+                return $query->where('i.cInvCode', 'LIKE', '%' . $search_code . '%');
+            })
+            // 当名称查询条件不为空时,进行模糊查询
+            ->when(!empty($search_name), function ($query) use ($search_name) {
+                return $query->where('i.cInvName', 'LIKE', '%' . $search_name . '%');
+            })
+            ->select(
+                'i.cInvCode as code',     // 存货编码
+                'i.cInvName as name',     // 存货名称
+                'i.cInvStd as size',       // 规格型号
+                'i.cComUnitCode as unit_code',     // 主计量单位编码
+                'u.cComUnitName as unit',     // 核心修改:主计量单位名称 (如: 个、千克、箱)
+                'i.iImpTaxRate as purchase_rate'   // 进项税率
+            )
+            ->orderBy('i.cInvCode', 'ASC');
 
-        try {
-            $this->databaseService->beginTransaction();
+        // 如果存货档案数据量非常大,建议这里配合分页使用,例如:
+        $list = $this->limit($model, '', $data);
 
-            $exists = $this->databaseService->table('Inventory')
-                ->where('cInvCode', $inventoryData['cInvCode'])
-                ->lockForUpdate() // 锁定该行,防止并发冲突
-                ->exists();
+        return [true, $list];
+    }
 
-            if ($exists) return [false, '存货编码已存在,请' . $flag_title];
+    // 仓库档案
+    public function warehouseU8List($data, $user)
+    {
+        $list = $this->databaseService->table('Warehouse as W')
+            ->select(
+                'W.cWhCode as code',         // 仓库编码 (如: 01, 02)
+                'W.cWhName as name'        // 仓库名称 (如: 原材料库, 半成品库)
+            )
+            ->orderBy('W.cWhCode', 'ASC')
+            ->get();
 
-            $this->databaseService->table('Inventory')->insert($inventoryData);
-            $this->databaseService->table('Inventory_sub')->insert($inventorySubData);
+        return [true, $list];
+    }
 
-            $this->databaseService->commit();
-        } catch (\Throwable $exception) {
-            $this->databaseService->rollBack();
+    //获取u8请购单
+    public function purchaseRequisitionU8List($data, $user){
+        $order_date = $data['order_date'] ?? [];
+        $order_date = array_filter($order_date);
+        $code = $data['code'] ?? "";
 
-            return [false, "创建用友失败: " . $exception->getMessage()];
-        }
+        $model = $this->databaseService->table('PU_AppVouch as a')
+            ->when(! empty($code), function ($query) use($code){
+                return $query->where('a.cCode', 'LIKE', '%'.$code.'%');
+            })
+            ->when(! empty($order_date), function ($query) use($order_date){
+                $start = date('Y-m-d 00:00:00.000', $order_date[0]);
+                $end = date('Y-m-d 23:59:59.000', $order_date[1]);
+                return $query->whereBetween('a.dDate', [$start, $end]);
+            })
+        ->where('a.iverifystateex', 2)
+        ->whereExists(function ($query) {
+        $query->select(DB::raw(1))
+            ->from('PU_AppVouchs as b')
+            ->whereRaw('b.ID = a.ID') // 主外键关联
+            ->whereRaw('ISNULL(b.fQuantity, 0) > ISNULL(b.iReceivedQTY, 0)');
+        })
+        ->select(
+            'a.ID as id', // 必须把主表ID查出来,后续点击需要用来查子表
+            DB::raw("ISNULL(a.cBusType, '') as business_type"),
+            DB::raw("ISNULL(a.cCode, '') as order_number"),
+            DB::raw("ISNULL(CONVERT(varchar(10), a.dDate, 120), '') as order_date"),
+            DB::raw("ISNULL(a.cMaker, '') as crt_name")
+        )
+        ->orderBy('a.ID', 'desc');
 
-        return [true, ''];
+        $list = $this->limit($model, '', $data);
+
+        return [true, $list];
     }
 
-    //U8 供应商新增
-    public function vendorAddToU8($data, $user){
-        $vendor = Vendor::where('del_time', 0)
-            ->where('id', $data['id'])
-            ->first();
-        if(empty($vendor)) return [false, '供应商记录不存在或已被删除'];
-        $vendor = $vendor->toArray();
-        if($vendor['status'] != Vendor::STATE_TWO) return [false, '供应商记录未审核通过'];
-
-        if(! empty($vendor['code'])){
-            //用户传入
-            $no = $vendor['code'];
-            $flag_title = "重填";
-        }else{
-            //生成编码
-            list($status, $msg) = $this->generate('vendor');
-            if(! $status) return [false, $msg];
-            $no = $msg;
-            $flag_title = "重试";
-        }
+    public function getRequisitionDetails($data){
+        if (empty($data['id'])) return [false, '请购单主表ID不能为空'];
 
-        $vendorData = [
-            'cVenCode' => $no,
-            'cVenName' => $vendor['title'],
-            'cVenAbbName' => $vendor['easy_title'],
-            'cVCCode' => $vendor['category_code'],
-            'dVenDevDate' => date("Y-m-d 00:00:00.000"),
-            'iVenDisRate' => '0.0',
-            'iVenCreLine' => '0.0',
-            'iVenCreDate' => '0',
-            'cVenHeadCode' => $no,
-            'iAPMoney' => '0.0',
-            'iLastMoney' => '0.0',
-            'iLRMoney' => '0.0',
-            'iFrequency' => '0',
-            'bVenTax' => '1',
-            'cCreatePerson' => 'demo',
-            'cModifyPerson' => 'demo',
-            'dModifyDate' => date("Y-m-d H:i:s.000"),
-            'iGradeABC' => '-1',
-            'bLicenceDate' => '0',
-            'bBusinessDate' => '0',
-            'bProxyDate' => '0',
-            'bPassGMP' => '0',
-            'bVenCargo' => '1', // 采购
-            'bProxyForeign' => '0', // 委外
-            'bVenService' => '0', // 服务
-            'bVenOverseas' => '0', // 国外
-            'cVenExch_name' => '人民币',
-            'iVenGSPType' => '0',
-            'iVenGSPAuth' => '-1',
-            'bVenAccPeriodMng' => '0',
-            'bVenHomeBranch' => '0',
-            'dVenCreateDatetime' => date("Y-m-d H:i:s.000"),
-            'bIsVenAttachFile' => '0',
-            'bRetail' => '0',
-        ];
+        $mainId = $data['id'];
 
-        try {
-            $this->databaseService->beginTransaction();
+        $details = $this->databaseService->table('PU_AppVouchs as b')
+            ->leftJoin('Inventory as i', 'i.cInvCode', 'b.cInvCode') // 通常明细需要关联存货档案拿名称和规格
+            ->leftJoin('ComputationUnit as u', 'u.cComUnitCode', 'i.cComUnitCode')
+            ->where('b.ID', $mainId)
+            ->whereRaw('ISNULL(b.fQuantity, 0) > ISNULL(b.iReceivedQTY, 0)')
+            ->select(
+                'b.AutoID as detail_id',          // 子表行单据唯一标识
+                'b.ID as main_id',                // 主表ID
+                'b.ivouchrowno as row_no',         // 行号
+                'b.cInvCode as code',     // 存货编码
+                'b.dRequirDate as plan_date',     // 需求日期 | 采购订单里的计划到货日期
+                'b.fTaxPrice as price',     // 原币含税单价
+                'b.iPerTaxRate as rate',     // 税率
+                'i.cComUnitCode as unit_code',     // 主计量单位编码
+                'u.cComUnitName as unit',     // 核心修改:主计量单位名称 (如: 个、千克、箱)
+                DB::raw("ISNULL(i.cInvName, '') as name"), // 存货名称
+                DB::raw("ISNULL(i.cInvStd, '') as size"),   // 规格型号
+                DB::raw("ISNULL(b.fQuantity, 0) as req_qty"),       // 请购数量 (fQuantity)
+                DB::raw("ISNULL(b.iReceivedQTY, 0) as order_qty"),  // 累计订货数量 (iReceivedQTY)
+                DB::raw("(ISNULL(b.fQuantity, 0) - ISNULL(b.iReceivedQTY, 0)) as available_qty") // 剩余数量
+            )
+            ->orderBy('b.ivouchrowno', 'asc')
+            ->get();
 
-            $exists = $this->databaseService->table('Vendor')
-                ->where('cVenCode', $vendorData['cVenCode'])
-                ->lockForUpdate() // 锁定该行,防止并发冲突
-                ->exists();
+            // 转化为普通数组返回
+            $list = json_decode(json_encode($details), true);
 
-            if ($exists) return [false, '供应商编码已存在,请' . $flag_title];
+            return [true, $list];
+    }
 
-            $this->databaseService->table('Vendor')->insert($vendorData);
+    public function getRequisitionDetailsByCode($code = [])
+    {
+        if (empty($code)) return [false, '请购单号不能为空'];
+
+        // 2. 执行 U8 数据库查询
+        $list = $this->databaseService->table('PU_AppVouchs as b')
+            ->join('PU_AppVouch as a', 'a.ID', 'b.ID')
+            ->leftJoin('Inventory as i', 'i.cInvCode', 'b.cInvCode')
+            ->whereIn('a.cCode', $code)
+            // 过滤:只查出【请购数量 > 累计订货数量】即还未订货完的明细
+            ->whereRaw('ISNULL(b.fQuantity, 0) > ISNULL(b.iReceivedQTY, 0)')
+            ->select(
+                'a.cCode as cappcode',             // 顺便把主表单号也查出来,方便前端知道这一行属于哪张请购单
+                'b.AutoID as detail_id',          // 子表行单据唯一标识 (iAppIds)
+                'b.ID as main_id',                // 主表ID (cappcodeId)
+                'b.ivouchrowno as row_no',         // 行号
+                'b.cInvCode as material_code',     // 存货编码
+                'b.dRequirDate as plan_date',     // 需求日期 -> 对应采购订单的计划到货日期
+                DB::raw("ISNULL(i.cInvName, '') as material_name"), // 存货名称
+                DB::raw("ISNULL(i.cInvStd, '') as material_std"),   // 规格型号
+                DB::raw("ISNULL(b.fQuantity, 0) as req_qty"),       // 请购数量
+                DB::raw("ISNULL(b.iReceivedQTY, 0) as order_qty"),  // 累计订货数量
+                DB::raw("(ISNULL(b.fQuantity, 0) - ISNULL(b.iReceivedQTY, 0)) as available_qty") // 剩余可用数量
+            )
+            // 按照主表单号和子表行号升序排序,方便前端按单据分组展示
+            ->orderBy('a.cCode', 'asc')
+            ->orderBy('b.ivouchrowno', 'asc')
+            ->get();
 
-            $this->databaseService->commit();
+        // 3. 转化为普通数组返回
+        $list = json_decode(json_encode($list), true);
 
-        } catch (\Throwable $exception) {
-            $this->databaseService->rollBack();
+        return [true, $list];
+    }
 
-            return [false, "创建供应商失败: " . $exception->getMessage()];
-        }
+    //获取u8采购订单
+    public function purchaseOrderU8List($data, $user){
+        // 0 蓝单  1 红单
+        if(! isset($data['bredvouch'])) return [false, '参照类型(蓝单|红单不能为空)'];
+        $type = $data['bredvouch'];
+        $order_date = $data['order_date'] ?? [];
+        $order_date = array_filter($order_date);
+        $code = $data['code'] ?? "";
 
-        return [true, ''];
+        $model = $this->databaseService->table('PO_Pomain as a')
+            ->leftJoin('Vendor as v', 'v.cVenCode', '=', 'a.cVenCode')
+            ->when(! empty($code), function ($query) use($code){
+                return $query->where('a.cPOID', 'LIKE', '%'.$code.'%');
+            })
+            ->when(! empty($order_date), function ($query) use($order_date){
+                $start = date('Y-m-d 00:00:00.000', $order_date[0]);
+                $end = date('Y-m-d 23:59:59.000', $order_date[1]);
+                return $query->whereBetween('a.dPODate', [$start, $end]);
+            })
+            ->where('a.iverifystateex', 2)
+            ->whereExists(function ($query) use($type){
+                if($type == 0){
+                    $query->select(DB::raw(1))
+                        ->from('PO_Podetails as b')
+                        ->whereRaw('b.POID = a.POID')
+                        ->whereRaw('ISNULL(b.iQuantity, 0) > ISNULL(b.iReceivedQTY, 0)');
+                }elseif($type == 1){
+                    $query->select(DB::raw(1))
+                        ->from('PO_Podetails as b')
+                        ->whereRaw('b.POID = a.POID')
+                        ->whereRaw('ISNULL(b.iReceivedQTY, 0) > 0');
+                }
+            })
+            ->select(
+                'a.POID as id',
+                DB::raw("ISNULL(a.cBusType, '') as business_type"),
+                DB::raw("ISNULL(a.cVenCode, '') as supply_code"),
+                DB::raw("ISNULL(v.cVenName, '') as supply_name"),
+                DB::raw("ISNULL(a.cexch_name, '') as cexch_name"),
+                DB::raw("ISNULL(a.nflat, '') as nflat"),
+                DB::raw("ISNULL(a.iDiscountTaxType, '') as iDiscountTaxType"),
+                DB::raw("ISNULL(a.cPOID, '') as order_number"),
+                DB::raw("ISNULL(CONVERT(varchar(10), a.dPODate, 120), '') as order_date"),
+                DB::raw("ISNULL(a.cMaker, '') as crt_name")
+            )
+            ->orderBy('a.ID', 'desc');
+
+        $list = $this->limit($model, '', $data);
+
+        return [true, $list];
+    }
+    // 供应商 业务类型 汇率 扣税类别 币种 相同才能一起选
+    // 只能同时选择供应商、币种、汇率、扣税类别、业务类型、流程模式相同的行! 这是用友的提示
+
+    // 获取u8采购订单明细
+    public function getPurchaseOrderDetails($data){
+        if (empty($data['id'])) return [false, '采购订单主表ID不能为空'];
+        // 0 蓝单  1 红单
+        if(! isset($data['bredvouch'])) return [false, '参照类型(蓝单|红单不能为空)'];
+        $type = $data['bredvouch'];
+
+        $mainId = $data['id'];
+        $list = $this->databaseService->table('PO_Podetails as b')
+            ->leftJoin('Inventory as i', 'i.cInvCode', 'b.cInvCode') // 通常明细需要关联存货档案拿名称和规格
+            ->leftJoin('ComputationUnit as u', 'u.cComUnitCode', 'i.cComUnitCode')
+            ->where('b.POID', $mainId)
+            ->when(!empty($type), function ($query) use($type){
+                if($type == 0){
+                    return $query->whereRaw('ISNULL(b.iQuantity, 0) > ISNULL(b.iReceivedQTY, 0)');
+                }elseif($type == 1){
+                    return $query->whereRaw('ISNULL(b.iReceivedQTY, 0) > 0');
+                }
+            })
+            ->select(
+                'b.POID as main_id',                // 主表ID
+                'b.ID as detail_id',          // 子表行单据唯一标识
+                'b.ivouchrowno as row_no',         // 行号
+                'b.cInvCode as code',     // 存货编码
+                'b.iTaxPrice as price',     // 原币含税单价
+                'b.iPerTaxRate as rate',     // 税率
+                'i.cComUnitCode as unit_code',     // 主计量单位编码
+                'i.bInvBatch as pici',     // 批次管理
+                'i.bInvQuality as baozhiqi',     // 保质期管理
+                'u.cComUnitName as unit',     // 核心修改:主计量单位名称 (如: 个、千克、箱)
+                DB::raw("ISNULL(i.cInvName, '') as name"), // 存货名称
+                DB::raw("ISNULL(i.cInvStd, '') as size"),   // 规格型号
+                DB::raw("ISNULL(b.iQuantity, 0) as i_qty"),       // 采购订单数量 (iQuantity)
+                DB::raw("ISNULL(b.iReceivedQTY, 0) as in_qty"),  // 累计入库数量 (iReceivedQTY)
+                DB::raw("(ISNULL(b.iQuantity, 0) - ISNULL(b.iReceivedQTY, 0)) as available_qty") // 剩余可入库数量
+            )
+            ->orderBy('b.ivouchrowno', 'asc')
+            ->get();
+
+        // 转化为普通数组返回
+//        $list = json_decode(json_encode($list), true);
+
+        return [true, $list];
     }
 
-    // 生成编码
-    public function generate($type, $classCode = "")
+    public function getPurchaseOrderDetailsByCode($code = [])
     {
-        try {
-            // 1. 确定对象映射
-            $cardNumber = ($type === 'inventory') ? 'inventory' : 'Vendor';
-            $cardNumber_name = ($type === 'inventory') ? '存货' : '供应商';
-            $table = ($type === 'inventory') ? 'Inventory' : 'Vendor';
-            $codeField = ($type === 'inventory') ? 'cInvCode' : 'cVenCode';
-
-            // 2. 获取 U8 规则定义
-            $rule = $this->databaseService->table('VoucherNumber')
-                ->where('CardNumber', $cardNumber)
-                ->first();
-
-            if (!$rule) return [false, "未找到 {$cardNumber_name} 的规则定义"];
-
-            /**
-             * 3. 动态解析前缀 (Prefix1, Prefix2, Prefix3)
-             * U8 的规则通常存放在 PrefixRule 或 Prefix 字段中
-             */
-            $prefix = "";
-            for ($i = 1; $i <= 3; $i++) {
-                $ruleField = "Prefix{$i}Rule";
-                $valField = "Prefix{$i}";
-
-                // 检查规则描述
-                $ruleDesc = $rule->$ruleField ?? ''; // 例如 "存货分类编码" 或 "GYS"
-                $staticVal = $rule->$valField ?? '';
-
-                if (str_contains($ruleDesc, '分类') || str_contains($staticVal, '分类')) {
-                    // 如果规则提到“分类”,则填入传入的分类编码
-                    $prefix .= $classCode;
-                } elseif (!empty($ruleDesc)) {
-                    // 如果规则是具体的字符(如 "GYS"),直接拼接
-                    $prefix .= $ruleDesc;
-                } elseif (!empty($staticVal) && $staticVal !== '手工输入' && $staticVal !== '存货分类编码') {
-                    // 如果静态值不是提示语,则作为前缀
-                    $prefix .= $staticVal;
-                }
-            }
+        if (empty($code)) return [false, '采购订单号不能为空'];
 
-            // 4. 获取流水号配置 (Glide)
-            $glideLen = $rule->GlideLen > 0 ? $rule->GlideLen : 4;
-            $startNum = $rule->iStartNumber ?? 1;
-
-            // 5. 查找当前最大编码
-            $expectedLen = strlen($prefix) + $glideLen;
-
-            $lastCode = $this->databaseService->table($table)
-                ->where($codeField, 'like', $prefix . '%')
-                ->whereRaw("LEN($codeField) = $expectedLen")
-                ->orderBy($codeField, 'desc')
-                ->value($codeField);
-
-            // 6. 生成编码
-            if (!$lastCode) {
-                // 初始:前缀 + 起始值补零
-                $finalCode = $prefix . str_pad($startNum, $glideLen, '0', STR_PAD_LEFT);
-            } else {
-                // 截取流水号自增
-                $lastSerial = substr($lastCode, -$glideLen);
-                $nextSerial = ++$lastSerial;
-
-                // 溢出检查
-                if (strlen($nextSerial) > $glideLen) {
-                    return [false, "流水号已溢出"];
-                }
-                $finalCode = $prefix . str_pad($nextSerial, $glideLen, '0', STR_PAD_LEFT);
-            }
+        // 执行 U8 数据库查询
+        $list = $this->databaseService->table('PO_Podetails as b')
+            ->join('PO_Pomain as a', 'a.POID', '=', 'b.POID')
+            ->leftJoin('Inventory as i', 'i.cInvCode', '=', 'b.cInvCode')
+            ->whereIn('a.cPOID', $code)
+            ->select(
+                'a.cPOID as order_number',
+                'b.ID as detail_id',
+                'b.POID as main_id',
+                'b.ivouchrowno as row_no',
+                'b.cInvCode as cInvCode',
+                DB::raw("ISNULL(i.cInvName, '') as name"),
+                DB::raw("ISNULL(i.cInvStd, '') as size"),
+                DB::raw("ISNULL(i.cComUnitCode, '') as unit"),
+                DB::raw("ISNULL(b.iPerTaxRate, 0) as rate"),
+                DB::raw("ISNULL(b.iUnitPrice, 0) as price"),
+                DB::raw("ISNULL(b.iQuantity, 0) as po_qty"),
+                DB::raw("ISNULL(b.iReceivedQTY, 0) as received_qty"),
+                DB::raw("(ISNULL(b.iQuantity, 0) - ISNULL(b.iReceivedQTY, 0)) as available_qty"),
+
+                // ==================== 新增:主表强控制联动校验字段 ====================
+                DB::raw("ISNULL(a.cBusType, '') as cBusType"),                 // 业务类型
+                DB::raw("ISNULL(a.cVenCode, '') as cVenCode"),                 // 供应商编码
+                DB::raw("ISNULL(a.cexch_name, '人民币') as cexch_name"),        // 币种
+                DB::raw("CAST(ISNULL(a.nflat, 1.0) AS DECIMAL(10,4)) as nflat"),// 汇率
+                DB::raw("ISNULL(a.iDiscountTaxType, 0) as iDiscountTaxType")   // 扣税类别
+            )
+            ->orderBy('a.cPOID', 'asc')
+            ->orderBy('b.ivouchrowno', 'asc')
+            ->get();
+
+        // 转化为普通数组返回
+        $list = json_decode(json_encode($list), true);
+
+        if (empty($list)) {
+            return [false, '未查询到对应的采购订单明细数据'];
+        }
+
+        // ==================== 核心修改:多单合单严格一致性校验 ====================
+        if (count($code) > 1) {
+            // 1. 校验供应商
+            $venCodes = array_unique(array_column($list, 'cVenCode'));
+            if (count($venCodes) > 1) return [false, '只能同时选择【供应商】相同的采购订单进行合并入库!'];
+
+            // 2. 校验业务类型
+            $busTypes = array_unique(array_column($list, 'cBusType'));
+            if (count($busTypes) > 1) return [false, '只能同时选择【业务类型】相同的采购订单进行合并入库!'];
 
-            return [true, $finalCode];
+            // 3. 校验币种
+            $exchNames = array_unique(array_column($list, 'cexch_name'));
+            if (count($exchNames) > 1) return [false, '只能同时选择【币种】相同的采购订单进行合并入库!'];
 
-        } catch (\Throwable $e) {
-            return [false, "生成失败: " . $e->getMessage()];
+            // 4. 校验汇率 (转成 float 排除数据库浮点数末尾 0 的干扰)
+            $nflats = array_unique(array_map('floatval', array_column($list, 'nflat')));
+            if (count($nflats) > 1) return [false, '只能同时选择【汇率】相同的采购订单进行合并入库!'];
+
+            // 5. 校验扣税类别
+            $taxTypes = array_unique(array_column($list, 'iDiscountTaxType'));
+            if (count($taxTypes) > 1) return [false, '只能同时选择【扣税类别】相同的采购订单进行合并入库!'];
         }
+        // ====================================================================
+
+        return [true, $list];
     }
 }

+ 431 - 0
app/Service/U8ThirdPartyService.php

@@ -0,0 +1,431 @@
+<?php
+
+namespace App\Service;
+
+use App\Model\DDEmployee;
+use App\Model\PoPodetails;
+use App\Model\PoPomain;
+use App\Model\PuAppVouch;
+use App\Model\PuAppVouchs;
+use App\Model\RdRecord01;
+use App\Model\RdRecords01;
+use Illuminate\Support\Facades\Cache;
+use Illuminate\Support\Facades\Log;
+
+class U8ThirdPartyService extends Service
+{
+    public function getToken($data){
+        if(empty($data['database'])) return [false, '账套不能为空'];
+        $key = "xky_u8_api" . $data['database'];
+        $config = config('wms');
+
+        // 1. 自检网络通畅
+        list($bool, $msg) = $this->checkNetworkStatus($config['api_host'], $config['api_port']);
+        if (!$bool) return [false, "网络连接失败: " . $msg];
+
+        $host = $config['api_host'] . ":" . $config['api_port'];
+
+        // 2. 尝试从缓存获取
+        $token = Cache::get($key);
+
+        if (! $token) {
+            // 3. 缓存失效,请求新 Token
+            $url = $host . "/api/System/GetToken";
+            $date = date("Y-m-d");
+            $json = [
+                "U8DbName"      => $data['database'],
+                "sUserId"       => $config['user_id'],
+                "sPassword"     => $config['user_password'],
+                "LoginDateTime" => $date,
+                "bPersist"      => true
+            ];
+
+            $header = ['Content-Type:application/json'];
+
+            // 调用你的 POST 辅助函数
+            list($status, $result) = $this->post_helper1($url, json_encode($json), $header);
+
+            if (!$status) return [false, "用友token获取失败: " . $result];
+            if (!isset($result['code'])) return [false, '获取用友登录信息失败: 响应格式异常'];
+            if ($result['code'] != 0) return [false, "U8错误: " . ($result['msg'] ?? '未知错误')];
+
+            $token = $result['data']['Token'] ?? "";
+
+            if (empty($token)) return [false, "接口返回的 Token 为空"];
+
+            // 30分钟 = 1800秒
+            Cache::put($key, $token, now()->addMinutes(30));
+        }
+
+        return [true, ['host' => $host, 'token' => $token]];
+    }
+
+    public function puAppVouch($record)
+    {
+        // 1. 查询本地请购单主表(严格匹配 MySQL 字段名)
+        $order = PuAppVouch::where('del_time', 0)
+            ->where('order_number', $record['order_number'])
+            ->where('login_type', $record['login_type'])
+            ->first();
+        if (empty($order)) return [false, '请购单不存在或已被删除'];
+        $order_array = $order->toArray();
+
+        // 2. 查询本地请购单明细子表(多行数据)
+        $details = PuAppVouchs::where('del_time', 0)
+            ->where('main_id', $order_array['id'])
+            ->get()->toArray();
+        if (empty($details)) return [false, '请购单明细不存在或已被删除'];
+
+        // 3. 获取用友 U8 接口的 Token
+        list($status, $msg) = $this->getToken($record);
+        if (! $status) return [false, $msg];
+
+        // 4. 循环组装表体明细 (iBody)
+        $iBody = [];
+        foreach ($details as $index => $item) {
+            $qty = (float)$item['quantity'];      // 数量:quantity
+            $taxUnitPrice = (float)$item['price']; // 原币含税单价:price
+            $taxRate = (float)$item['rate'];      // 税率:rate(例如 13 或 17)
+
+            // --- 核心价格与金额计算逻辑 ---
+            // 1. 原币价税合计 / 含税金额 (iOriSum)
+            $iOriSum = round($qty * $taxUnitPrice, 2);
+
+            // 2. 原币无税金额 / 金额 (iOriMoney)
+            $iOriMoney = round($iOriSum / (1 + ($taxRate / 100)), 2);
+
+            // 3. 原币税额 (iOriTaxPrice)
+            $iOriTaxPrice = round($iOriSum - $iOriMoney, 2);
+
+            // 4. 原币无税单价 (iOriCost)
+            $iOriCost = round($taxUnitPrice / (1 + ($taxRate / 100)), 6);
+
+            // 因为币种是人民币,汇率是 1,所以 本币价格 = 原币价格
+            $fMoney = $iOriMoney;     // 本币无税金额
+            $iMoney = $iOriMoney;     // 本币无税金额(对应你列出的 iMoney)
+            $iTaxPrice = $iOriTaxPrice; // 本币税额
+
+            $iBody[] = [
+                "ivouchrowno"   => $index + 1,             // 行号且唯一
+                "cInvCode"      => (string)$item['cInvCode'], // 存货编码
+                "fQuantity"     => $qty,                   // fQuantity 数量
+                "iPerTaxRate"   => (int)$taxRate,          // iPerTaxRate 税率
+                "fNum"          => 0,                      // 件数
+                "dRequirDate"   => $item['dRequirDate'], // 需求日期
+                "dArriveDate"   => $item['dArriveDate'], // 建议订货日期
+                "cexch_name"    => "人民币",                // 币种
+                "iExchRate"     => 1,                      // 汇率
+
+                // --- 补充的单价字段 ---
+                "iOriTaxCost"   => $taxUnitPrice,          // iOriTaxCost 原币含税单价
+                "fTaxPrice"     => $taxUnitPrice,          // fTaxPrice 含税单价
+                "fUnitPrice"    => $iOriCost,              // fUnitPrice 无税单价
+                "iOriCost"      => $iOriCost,              // iOriCost 原币单价
+
+                // --- 补充的金额/税额字段 ---
+                "fMoney"        => $fMoney,                // fMoney 金额 (本币无税金额)
+                "iMoney"        => $iMoney,                // iMoney 本币金额
+                "iOriMoney"     => $iOriMoney,             // iOriMoney 原币金额
+                "iOriTaxPrice"  => $iOriTaxPrice,          // iOriTaxPrice 原币税额
+                "iTaxPrice"     => $iTaxPrice,             // iTaxPrice 本币税额
+                "iOriSum"       => $iOriSum,               // iOriSum 原币价税合计
+            ];
+        }
+
+        // 5. 组织请购单请求数据结构
+        $tmp = [
+            "Inum" => "PuAppVouch",
+            "Data" => [
+                "iHead" => [
+                    "cBusType"     => $order_array['cBusType'],
+                    "cPTCode"      => $order_array['cPTCode'],
+                    "cMemo"        => "接口生成",
+                    "IsVerify"     => true,
+                    "ddate"        => $order_array['order_time'],
+                    "PriceCalKey"  => "iOriTaxCost",
+                    "cMaker" => DDEmployee::where('userid', $order_array['crt_id'])->where('login_type', $record['login_type'])->value('name'),
+                ],
+                "iBody" => $iBody
+            ]
+        ];
+
+        $final_data = [$tmp];
+
+        // 6. 准备发送请求
+        $host = $msg['host'] ?? "";
+        $token = $msg['token'] ?? "";
+
+        $header = [
+            "Authorization: {$token}",
+            'Content-Type: application/json'
+        ];
+
+        $url = rtrim($host, '/') . "/api/PuAppVouch/Add";
+        $json = json_encode($final_data, JSON_UNESCAPED_UNICODE);
+
+        // 7. 发送 POST 请求
+        list($status, $result) = $this->post_helper1($url, $json, $header, 30);
+
+        if (! $status) return [false, $result];
+        if (! isset($result['code'])) return [false, '接口响应异常,请检查用友服务'];
+        if ($result['code'] != 0) return [false, $result['msg']];
+
+        // 8. 回写用友生成的单据编号
+        $code = $result['data'][0]['VouchCode'];
+        $order->code = $code;
+        $order->save();
+
+        return [true, ''];
+    }
+
+    public function poPomain($record)
+    {
+        // 1. 查询本地采购订单主表(对应 po_pomain 表)
+        $order = PoPomain::where('del_time', 0)
+            ->where('order_number', $record['order_number'])
+            ->where('login_type', $record['login_type'])
+            ->first();
+        if (empty($order)) return [false, '采购订单主表记录不存在或已被删除'];
+        $order_array = $order->toArray();
+
+        // 2. 查询本地采购订单明细子表(对应 po_podetails 表)
+        $details = PoPodetails::where('del_time', 0)
+            ->where('main_id', $order_array['id'])
+            ->get()->toArray();
+        if (empty($details)) return [false, '采购订单明细不存在或已被删除'];
+
+        // 3. 获取用友 U8 接口的 Token 和 Host 基础信息
+        list($status, $msg) = $this->getToken($record);
+        if (! $status) return [false, $msg];
+
+        // 4. 循环组装采购订单表体明细 (iBody)
+        $iBody = [];
+        foreach ($details as $index => $item) {
+            $qty = (float)$item['quantity'];      // 数量:quantity
+            $taxUnitPrice = (float)$item['price']; // 原币含税单价:price
+            $taxRate = (float)$item['rate'];      // 税率:rate(例如 13 或 17)
+            $iAppIds = $item['iAppIds'] ?? null;
+
+            // U8 采购订单要求的明细行基础结构
+            $bodyRow = [
+                "ivouchrowno"   => $index + 1,             // 行号且唯一
+                "cInvCode"      => $item['cInvCode'], // 存货编码
+                "iQuantity"     => $qty,                   // 数量
+                "iPerTaxRate"     => $taxRate,             // 税率
+                "iTaxPrice"     => $taxUnitPrice,          // 原币含税单价(与表头 PriceCalKey 对应)
+                "dArriveDate"   => $item['dArriveDate'],   // 建议/计划到货日期
+                "bGsp"          => 0,                      // 是否质检,默认0
+                "iAppIds"       => $iAppIds,
+            ];
+
+            $iBody[] = $bodyRow;
+        }
+
+        $cappcode = null;
+        if(! empty($order_array['cappcode'])) $cappcode = $order_array['cappcode'][0] ?? null;
+
+        // 5. 组织采购订单请求的表头数据结构 (iHead)
+        $iHead = [
+            "cVenCode"          => $order_array['cVenCode'],                // 供应商编码
+            "cDepCode"          => $order_array['cDepCode'] ?? null,         // 部门编码
+            "iDiscountTaxType"  => 0,                                       // 0--应税外加(默认), 1--应税内含
+            "iTaxRate"          => (int)$order_array['iTaxRate'],           // 税率
+            "nflat"             => (int)($order_array['nflat'] ?? 1),       // 汇率
+            "cexch_name"        => !empty($order_array['cexch_name']) ? $order_array['cexch_name'] : "人民币", // 币种
+            "IsVerify"          => true,                                    // 是否审核 (默认生成即审核)
+            "cMemo"             => !empty($order_array['mark']) ? $order_array['mark'] : "接口生成", // 备注
+            "PriceCalKey"       => "iTaxPrice",                             // 以含税单价作为计算基准
+            "dPODate"           => $order_array['order_time'],               // 单据日期
+            "cappcode"           => $cappcode,              // 请购单号
+            "cMaker" => DDEmployee::where('userid', $order_array['crt_id'])->where('login_type', $record['login_type'])->value('name'),
+
+        ];
+
+        if(! empty($cappcode)) $iHead['cSource'] = 'app'; //参照的固定参数
+
+        // 6. 包装成接口所需的嵌套数组格式
+        $tmp = [
+            "Inum" => "PurchaseOrder",
+            "Data" => [
+                "iHead" => $iHead,
+                "iBody" => $iBody
+            ]
+        ];
+
+        $final_data = [$tmp];
+
+        // 7. 准备发送网络请求
+        $host = $msg['host'] ?? "";
+        $token = $msg['token'] ?? "";
+
+        $header = [
+            "Authorization: {$token}",
+            'Content-Type: application/json'
+        ];
+
+        $url = rtrim($host, '/') . "/api/PurchaseOrder/Add";
+        $json = json_encode($final_data, JSON_UNESCAPED_UNICODE);
+
+        // 8. 调用 POST 助手发送
+        list($status, $result) = $this->post_helper1($url, $json, $header, 30);
+
+        if (! $status) return [false, $result];
+        if (! isset($result['code'])) return [false, '接口响应异常,请检查用友服务状态'];
+        if ($result['code'] != 0) return [false, $result['msg']];
+
+        // 9. 成功后回写用友生成的采购订单编号 (VouchCode)
+        $u8VouchCode = $result['data'][0]['VouchCode'];
+        $order->code = $u8VouchCode; // 回写到用友单据编号字段
+        $order->save();
+
+        return [true, ''];
+    }
+
+    public function purchaseInAdd($record)
+    {
+        // 1. 查询本地采购入库单主表(对应 rd_record01 表)
+        $order = RdRecord01::where('del_time', 0)
+            ->where('order_number', $record['order_number'])
+            ->where('login_type', $record['login_type'])
+            ->first();
+        if (empty($order)) return [false, '采购入库单主表记录不存在或已被删除'];
+        $order_array = $order->toArray();
+
+        // 2. 查询本地采购入库单明细子表(对应 rd_records01 表)
+        $details = RdRecords01::where('del_time', 0)
+            ->where('main_id', $order_array['id'])
+            ->get()->toArray();
+        if (empty($details)) return [false, '采购入库单明细不存在或已被删除'];
+
+        // 3. 获取用友 U8 接口的 Token 和 Host 基础信息
+        list($status, $msg) = $this->getToken($record);
+        if (!$status) return [false, $msg];
+
+        // 4. 循环组装采购入库单表体明细 (iBody)
+        $iBody = [];
+        foreach ($details as $index => $item) {
+            $qty = (float)$item['quantity'];
+            $taxUnitPrice = (float)$item['price']; // 原币含税单价:price
+            $taxRate = (float)$item['rate'];      // 税率:rate(例如 13 或 17)
+
+            // U8 采购入库单接口要求的明细行数据结构
+            $bodyRow = [
+                "iRowNo"        => $index + 1,        // 行号必填且唯一
+                "cInvCode"      => $item['cInvCode'], // 存货编码
+                "cBatch"        => $item['cBatch'] ?? null,                // 批号(按需传入,默认空)
+                "dMadeDate"        => $item['dMadeDate'] ?? null,                // 生产日期(按需传入,默认空)
+                "dVDate"        => $item['dVDate'] ?? null,                // 失效日期(按需传入,默认空)
+                "iTaxRate"     => $taxRate,             // 税率
+                "iOriTaxCost"     => $taxUnitPrice,    // 原币含税单价(与表头 PriceCalKey 对应)
+                "iinvexchrate"  => 0,                 // 换算率,默认0
+                "iQuantity"     => $qty,              // 实际入库数量(蓝单为正,红单为负)
+                "iNum"          => 0,                 // 辅计量件数,默认0
+                "iNQuantity"    => $qty,              // 应收应发数量(默认等于实际入库数量)
+                "iNNum"         => 0,                 // 应收应发辅计量数量,默认0
+                "iPOsID"        => $item['iPOsID'] // 核心必填:采购订单子表唯一标识ID
+            ];
+
+            $iBody[] = $bodyRow;
+        }
+
+        $cOrderCode = null;
+        if(! empty($order_array['cOrderCode'])) $cOrderCode = $order_array['cOrderCode'][0] ?? null;
+
+        // 5. 组织采购入库单请求的表头数据结构 (iHead)
+        $iHead = [
+            "bIsRedVouch"   => $order['bredvouch'] == 1 ? true : false , //是否红单
+            "IsVerify"      => true,                                             // 是否审核
+            "bCalPrice"     => true,                                              // 是否由接口自动计算金额 (方式一:拉取订单价格和税率)
+            "PriceCalKey"       => "iOriTaxCost",                             // 以含税单价作为计算基准
+            "cWhCode"       => $order_array['warehouseCode'],                    // 仓库编码
+            "cPTCode"       => $order_array['cPTCode'],                           // 采购类型编码
+            "cRdCode"       => $order_array['cRdCode'],                           // 出入库/收发类别编码
+            "cVenCode"      => $order_array['cVenCode'],                          // 供应商编码
+            "cExch_Name"    => !empty($order_array['cexch_name']) ? $order_array['cexch_name'] : "人民币", // 币种
+            "iExchRate"     => (int)($order_array['nflat'] ?? 1),                // 汇率
+            "iTaxRate"      => (int)$order_array['iTaxRate'],                     // 税率
+            "cDepCode"      => $order_array['cDepCode'] ?? null,                  // 部门编码
+            "cOrderCode"    => $cOrderCode,                                       // 关联的采购订单号
+            "cBusType"      => !empty($order_array['cBusType']) ? $order_array['cBusType'] : "普通采购", // 业务类型
+            "cSource"       => "采购订单",                                         // 单据来源固定为采购订单
+            "cMemo"         => !empty($order_array['mark']) ? $order_array['mark'] : "API生成",  // 备注
+            "dDate"         => $order_array['order_time'],                         // 单据日期
+            "cMaker" => DDEmployee::where('userid', $order_array['crt_id'])->where('login_type', $record['login_type'])->value('name'),
+        ];
+
+        // 6. 包装成接口所需的嵌套外层数组格式
+        $tmp = [
+            "Inum" => "PurchaseIn",
+            "Data" => [
+                "iHead" => $iHead,
+                "iBody" => $iBody
+            ]
+        ];
+
+        $final_data = [$tmp];
+
+        // 7. 准备发送网络请求
+        $host  = $msg['host'] ?? "";
+        $token = $msg['token'] ?? "";
+
+        $header = [
+            "Authorization: {$token}",
+            'Content-Type: application/json'
+        ];
+
+        $url  = rtrim($host, '/') . "/api/PurchaseIn/Add";
+        $json = json_encode($final_data, JSON_UNESCAPED_UNICODE);
+
+        // 8. 调用 POST 助手发送请求
+        list($status, $result) = $this->post_helper1($url, $json, $header, 30);
+
+        if (!$status) return [false, $result];
+        if (!isset($result['code'])) return [false, '接口响应异常,请检查用友服务状态'];
+        if ($result['code'] != 0) return [false, $result['msg']];
+
+        // 9. 成功后回写用友生成的采购入库单单据编号 (VouchCode) 到本地 code
+        // 注意:文档中返回的 data 也是一个包裹数组
+        $u8VouchCode = $result['data'][0]['VouchCode'];
+        $order->code = $u8VouchCode;
+        $order->save();
+
+        return [true, ''];
+    }
+
+    public function post_helper1($url, $data, $header = [], $timeout = 20){
+        Log::channel('apiLog')->info('POST', ["api" => $url , "param" => json_decode($data,true) ,"header" => $header]);
+
+        $ch = curl_init();
+        curl_setopt($ch, CURLOPT_URL, $url);
+        curl_setopt($ch,  CURLOPT_RETURNTRANSFER, true);
+        curl_setopt($ch, CURLOPT_ENCODING, '');
+        curl_setopt($ch, CURLOPT_POST, 1);
+        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
+        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
+        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
+        curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
+        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
+
+        if(!is_null($data)) curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
+        $r = curl_exec($ch);
+
+        if ($r === false) {
+            // 获取错误号
+            $errorNumber = curl_errno($ch);
+            // 获取错误信息
+            $errorMessage = curl_error($ch);
+            $message = "cURL Error #{$errorNumber}: {$errorMessage}";
+
+            Log::channel('apiLog')->info('POST结果', ["message" => $message ]);
+            return [false, $message];
+        }
+        curl_close($ch);
+
+        $return = json_decode($r, true);
+        unset($r);
+        Log::channel('apiLog')->info('POST结果', ["message" => $return ]);
+
+        return [true, $return];
+    }
+}

+ 962 - 247
app/Service/U8XkyServerService.php

@@ -6,6 +6,12 @@ use App\Model\DDEmployee;
 use App\Model\Field;
 use App\Model\FieldData;
 use App\Model\Inventory;
+use App\Model\PoPodetails;
+use App\Model\PoPomain;
+use App\Model\PuAppVouch;
+use App\Model\PuAppVouchs;
+use App\Model\RdRecord01;
+use App\Model\RdRecords01;
 use App\Model\Record;
 use App\Model\U8State;
 use App\Model\Vendor;
@@ -201,6 +207,7 @@ class U8XkyServerService extends Service
 
     public function inventoryCommon($data, $user, $field = []){
         $type = U8State::type_four;
+        $qx = $user['qx'];
 
         $model = Inventory::from('inventory as i')
             ->leftJoin('u8_state as s', function ($join) use ($type, $user) {
@@ -211,6 +218,9 @@ class U8XkyServerService extends Service
             })
             ->where('i.del_time', 0)
             ->where('i.login_type', $user['login_type'])
+            ->when(empty($qx), function ($query) use($user){
+                return $query->where('v.crt_id', $user['userid']);
+            })
             ->select('i.*', DB::raw('IFNULL(s.state, -1) as state'),'s.result')
             ->orderby('i.id', 'desc');
 
@@ -429,6 +439,7 @@ class U8XkyServerService extends Service
 
     public function vendorCommon($data, $user, $field = []){
         $type = U8State::type_five;
+        $qx = $user['qx'];
 
         $model = Vendor::from('vendor as v')
             ->leftJoin('u8_state as s', function ($join) use ($type, $user) {
@@ -438,7 +449,9 @@ class U8XkyServerService extends Service
                     ->where('s.del_time', '=', 0);
             })
             ->where('v.del_time', 0)
-//            ->where('v.crt_id', $user['userid'])
+            ->when(empty($qx), function ($query) use($user){
+                return $query->where('v.crt_id', $user['userid']);
+            })
             ->select('v.*', DB::raw('IFNULL(s.state, -1) as state'),'s.result')
             ->orderby('v.id', 'desc');
 
@@ -525,20 +538,6 @@ class U8XkyServerService extends Service
         return [true, ''];
     }
 
-    public function filedCommon1($data, $user, $field = []){
-        $model = FieldData::select([
-                'userid',
-                'type',
-                // 使用 GROUP_CONCAT 将 title 合并,并起别名为 titles
-                DB::raw('GROUP_CONCAT(title SEPARATOR ",") as titles')
-            ])
-            ->where('login_type', $user['login_type'])
-            ->groupBy('userid', 'type')
-            ->orderBy('type', 'desc'); // 或者根据你的需求排序
-
-        return $model;
-    }
-
     public function getField($data, $user){
         if(empty($data['type'])) return [false, 'type类型不能为空'];
         $type = $data['type'];
@@ -746,300 +745,1016 @@ class U8XkyServerService extends Service
 
     //新增供应商到本地-----------------------------------------------
 
-    //U8 存货库存列表
-    public function stockList($data, $user)
-    {
+    //新增采购请购单到本地--------------------------------------------
+
+    public function purchaseRequisitionAdd($data, $user){
+        list($status, $msg) = $this->purchaseRequisitionRule($data, $user);
+        if(! $status) return [false, $msg];
+
         try {
-            $field_list = [];
-            $employee = DDEmployee::where('userid', $user['userid'])->where('login_type', $user['login_type'])->first();
-            $qx = $employee['qx'] ?? 0;
-            if(empty($qx)) {
-                $field_list = FieldData::where('userid', $user['userid'])
-                    ->where('login_type', $user['login_type'])
-                    ->where('type', FieldData::STATE_ZERO)
-                    ->pluck('key')
-                    ->all();
+            DB::beginTransaction();
+
+            $model = new PuAppVouch();
+            $model->order_number = $this->generateBillNo([
+                'type' => PuAppVouch::Order_type,
+                'login_type' => $user['login_type'],
+                'period' => date("Ym")
+            ]);
+            $model->order_time = $data['order_time'];
+            $model->cBusType = $data['cBusType']; // 业务类型前端写死
+            $model->cPTCode = $data['cPTCode'];
+            $model->cPTCodeTitle = $data['cPTCodeTitle'];
+            $model->login_type = $user['login_type'];
+            $model->crt_id = $user['userid'];
+            $model->save();
+
+            $this->saveDetail($model->id, $data);
+
+            DB::commit();
+        } catch (\Throwable $exception) {
+            DB::rollBack();
+            return [false, $exception->getMessage()];
+        }
+
+        return [true, ''];
+    }
+
+    private function saveDetail($id, $data){
+        if(! empty($data['details'])){
+            $unit = [];
+            foreach ($data['details'] as $value){
+                $unit[] = [
+                    'main_id' => $id,
+                    'cInvCode' => $value['cInvCode'],
+                    'quantity' => $value['quantity'],
+                    'price' => $value['price'] ?? 0,
+                    'dRequirDate' => $value['dRequirDate'],
+                    'dArriveDate' => $value['dArriveDate'],
+                    'rate' => $value['rate'],
+                    'name' => $value['name'],
+                    'size' => $value['size'] ?? '',
+                    'unit' => $value['unit'] ?? '',
+                ];
             }
+            if(! empty($unit)) PuAppVouchs::insert($unit);
+        }
+    }
+
+    private function getDetail($id){
+        $data = PuAppVouchs::where('del_time',0)
+            ->where('main_id', $id)
+            ->get()->toArray();
+
+        $detail = [
+            'details' => $data,
+        ];
+
+        return $detail;
+    }
+
+    public function purchaseRequisitionEdit($data, $user){
+        list($status, $msg) = $this->purchaseRequisitionRule($data, $user, false);
+        if(! $status) return [false, $msg];
+
+        try {
+            DB::beginTransaction();
+
+            $model = PuAppVouch::where('id', $data['id'])->first();
+            $model->order_time = $data['order_time'];
+            $model->cBusType = $data['cBusType'];
+            $model->cPTCode = $data['cPTCode'];
+            $model->cPTCodeTitle = $data['cPTCodeTitle'];
+            $model->save();
+
+            PuAppVouchs::where('del_time',0)
+                ->where('main_id', $data['id'])
+                ->update(['del_time' => time()]);
+
+            $this->saveDetail($model->id, $data);
+
+            DB::commit();
+        } catch (\Throwable $exception) {
+            DB::rollBack();
+            return [false, "编辑请购单失败: " . $exception->getMessage()];
+        }
+
+        return [true, ''];
+    }
+
+    public function purchaseRequisitionRule(&$data, $user, $is_add = true){
+        if(! $is_add && empty($data['id'])) return [false, 'ID不能为空'];
+        $id = $data['id'] ?? 0;
+
+        if(empty($data['order_time'])) return [false, '单据日期不能为空'];
+        $orderTime = trim($data['order_time']);
+        if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $orderTime) || strtotime($orderTime) === false) {
+            return [false, '单据日期格式不正确,必须为 YYYY-MM-DD 格式(如:2026-04-04)'];
+        }
+
+        if(empty($data['details'])) return [false, '表体不能为空'];
+        foreach ($data['details'] as $key => $value){
+            $line = "第 " . ($key + 1) . "行";
+            if(empty($value['cInvCode'])) return [false, $line . '存货编码不能为空'];
+            if(empty($value['name'])) return [false, $line . '存货名称不能为空'];
+            if(! is_numeric($value['quantity']) || floatval($value['quantity']) <= 0.0) return [false, $line . '存货数量不正常'];
+            if(! isset($value['rate']) || ! is_numeric($value['rate'])) return [false, $line . '税率为空或非数字'];
+
+            if(empty($value['dRequirDate'])) return [false, $line . '需求日期不能为空'];
+            if(empty($value['dArriveDate'])) return [false, $line . '建议订货日期不能为空'];
 
-            // 1. 构建基础查询:关联现存量表和存货档案表
-            $query = DB::connection('sqlsrv')
-                ->table('CurrentStock as S')
-                ->select([
-                    'S.cWhCode',              // 仓库编码
-                    'W.cWhName',              // 仓库名称
-                    'S.cInvCode',             // 存货编码
-                    'I.cInvName',             // 存货名称
-                    'I.cInvStd',              // 规格型号
-                    'I.cInvCCode',            // 分类编码
-
-                    // --- 数量字段对齐你的结构 ---
-                    'S.iQuantity',            // 结存数量 (账面现存量)
-                    'S.fAvaQuantity',         // 可用数量
-                    'S.fOutQuantity',         // 待发货数量 (待出)
-                    'S.fInQuantity',          // 待入库数量 (待入)
-                    'S.fStopQuantity',        // 冻结数量
-
-                    // --- 批次与日期 ---
-                    'S.cBatch',               // 批号
-                    'S.dMdate',               // 生产日期
-                    'S.dVDate',               // 失效日期
-                ])
-                ->join('Inventory as I', 'S.cInvCode', '=', 'I.cInvCode')
-                ->leftJoin('Warehouse as W', 'S.cWhCode', '=', 'W.cWhCode')
-                ->leftJoin('InventoryClass as IC', 'I.cInvCCode', '=', 'IC.cInvCCode');
-
-            // 2. 过滤条件:存货名称 (支持模糊查询)
-            if (!empty($data['material_title'])) {
-                $query->where('I.cInvName', 'like', '%' . $data['material_title'] . '%');
+            $dRequirDate = trim($value['dRequirDate']);
+            $dArriveDate = trim($value['dArriveDate']);
+
+            if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $dRequirDate) || strtotime($dRequirDate) === false) {
+                return [false, $line . "需求日期格式不正确,必须为 YYYY-MM-DD"];
+            }
+            if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $dArriveDate) || strtotime($dArriveDate) === false) {
+                return [false, $line . "建议订货日期格式不正确,必须为 YYYY-MM-DD"];
             }
 
-            // 2. 过滤条件:存货编码 (支持模糊查询)
-            if (!empty($data['material_code'])) {
-                $query->where('S.cInvCode', 'like', '%' . $data['material_code'] . '%');
+            $timeOrder = strtotime($orderTime);
+            $timeRequir = strtotime($dRequirDate);
+            $timeArrive = strtotime($dArriveDate);
+
+            if ($timeArrive < $timeOrder) {
+                return [false, $line . "建议订货日期({$dArriveDate})不能早于单据日期({$orderTime})"];
+            }
+            if ($timeRequir < $timeArrive) {
+                return [false, $line . "需求日期({$dRequirDate})不能早于建议订货日期({$dArriveDate})"];
             }
+        }
+
+        if(! $is_add){
+            $order = PuAppVouch::where('id', $data['id'])->where('del_time',0)->first();
+            if(empty($order)) return [false, '请购单信息不存在或已被删除'];
+            $order = $order->toArray();
+            list($status, $msg) = $this->checkState(U8State::type_two, $user, $order['order_number']);
+            if(! $status) return [false, $msg];
+        }
+
+        return [true, ''];
+    }
+
+    public function purchaseRequisitionCommon($data, $user, $field = []){
+        $type = U8State::type_two;
+        $qx = $user['qx'];
 
-            // 3. 过滤条件:存货分类 (支持左匹配,即选大类查出所有子类)
-            if (!empty($data['category_code'])) {
-                // U8 分类是级次结构,用 like '01%' 可以查出 01 开头的所有子类
-                $query->where('I.cInvCCode', 'like', $data['category_code'] . '%');
+        $model = PuAppVouch::from('pu_appvouch as v')
+            ->leftJoin('u8_state as s', function ($join) use ($type, $user) {
+                $join->on('v.order_number', '=', 's.order_number')
+                    ->where('s.type', '=', $type)
+                    ->where('s.login_type', '=', $user['login_type'])
+                    ->where('s.del_time', '=', 0);
+            })
+            ->where('v.del_time', 0)
+            ->when(empty($qx), function ($query) use($user){
+                return $query->where('v.crt_id', $user['userid']);
+            })
+            ->select('v.*', DB::raw('IFNULL(s.state, -1) as state'),'s.result')
+            ->orderby('v.id', 'desc');
+
+        if (isset($data['state']) && $data['state'] !== '') {
+            $state_filter = $data['state'];
+            if ($state_filter == -1) {
+                // 未发起审批:u8_states 表里没记录,s.id 就会是 NULL
+                $model->whereNull('s.id');
+            } else {
+                // 0:待审核 1:通过 2:驳回
+                $model->where('s.state', $state_filter);
             }
+        }
 
-            // 6. 排序
-            $query->orderBy('S.cInvCode', 'asc')->orderBy('S.cWhCode', 'asc');
+        if(! empty($data['code'])) $model->where('v.code', 'like', '%' . $data['code'] . '%');
+        if(! empty($data['id'])) $model->where('v.id', $data['id']);
+        if(! empty($data['order_number'])) $model->where('v.order_number', 'like', '%' . $data['order_number'] . '%');
+        if(! empty($data['crt_time'][0]) && ! empty($data['crt_time'][1])) {
+            $return = $this->changeDateToTimeStampAboutRange($data['crt_time']);
+            $model->where('v.crt_time', '>=', $return[0]);
+            $model->where('v.crt_time', '<=', $return[1]);
+        }
 
-            // 7. 调用你定义的分页方法
-            $columns = ['*'];
-            $result = $this->limit($query, $columns, $data);
+        return $model;
+    }
 
-            // 注意这里的 &$item,加了 & 符号才能直接修改原数组里的内容
-            foreach ($result['data'] as &$item) {
-                $numFields = ['iQuantity', 'fAvaQuantity', 'fOutQuantity', 'fInQuantity', 'fStopQuantity'];
+    public function purchaseRequisitionList($data, $user){
+        $model = $this->purchaseRequisitionCommon($data, $user);
+        $list = $this->limit($model,'',$data);
+        $list = $this->fillPurchaseRequisitionData($list,$user);
 
-                foreach ($numFields as $field) {
-                    if (isset($item->$field)) {
-                        $item->$field = (float)$item->$field;
-                    }
-                }
+        return [true, $list];
+    }
 
-                $item->dMdate = $item->dMdate ? date('Y-m-d', strtotime($item->dMdate)) : '';
-                $item->dVDate = $item->dVDate ? date('Y-m-d', strtotime($item->dVDate)) : '';
+    public function fillPurchaseRequisitionData($data, $user){
+        if(empty($data['data'])) return $data;
 
-                // 脱敏处理
-                if (!empty($field_list)) {
-                    foreach ($field_list as $blackField) {
-                        if (isset($item->$blackField)) {
-                            $item->$blackField = '*****';
-                        }
-                    }
-                }
-            }
-            unset($item); // 销毁引用
+        $e_map = DDEmployee::whereIn('userid', array_unique(array_column($data['data'], 'crt_id')))
+            ->where('login_type', $user['login_type'])
+            ->pluck('name', 'userid')
+            ->toArray();
+        foreach ($data['data'] as $key => $value){
+            $data['data'][$key]['crt_name'] = $e_map[$value['crt_id']] ?? "";
+            $data['data'][$key]['crt_time'] = $value['crt_time'] ? date('Y-m-d H:i:s',$value['crt_time']) : '';
+            $data['data'][$key]['state_title'] = U8State::state_name[$value['state']];
+        }
+
+        return $data;
+    }
+
+    public function purchaseRequisitionMyDetail($data, $user){
+        $id = $data['id'] ?? 0;
+        $order_number = $data['order_number'] ?? "";
+        if(empty($id) && empty($order_number)) return [false,'请选择数据'];
+
+        $customer = PuAppVouch::where('del_time',0)
+            ->when(! empty($id), function ($query) use($id){
+                return $query->where('id', $id);
+            })
+            ->when(! empty($order_number), function ($query) use($order_number){
+                return $query->where('id', $order_number);
+            })
+            ->where('login_type', $user['login_type'])
+            ->first();
+        if(empty($customer)) return [false,'采购请购单不存在或已被删除'];
+        $customer = $customer->toArray();
+        $customer['crt_name'] = DDEmployee::where('id',$customer['crt_id'])->value('name');
+        $customer['crt_time'] = $customer['crt_time'] ? date("Y-m-d H:i:s",$customer['crt_time']): '';
+
+        $details = $this->getDetail($data['id']);
+        $customer = array_merge($customer, $details);
+
+        return [true, $customer];
+    }
+
+    public function purchaseRequisitionDel($data, $user){
+        if($this->isEmpty($data,'id')) return [false,'请选择数据!'];
+
+        try {
+            DB::beginTransaction();
+            $time = time();
+
+            $order = PuAppVouch::where('id', $data['id'])->where('del_time',0)->first();
+            if(empty($order)) return [false, '请购单信息不存在或已被删除'];
+            $order = $order->toArray();
+            list($status, $msg) = $this->checkState(U8State::type_two, $user, $order['order_number']);
+            if(! $status) return [false, $msg];
 
-            return [true, $result];
+            PuAppVouch::where('del_time',0)
+                ->where('id',$data['id'])
+                ->update(['del_time' => $time]);
+
+            PuAppVouchs::where('del_time',0)
+                ->where('main_id',$data['id'])
+                ->update(['del_time' => $time]);
+
+            DB::commit();
+        }catch (\Exception $exception){
+            DB::rollBack();
+            return [false,$exception->getMessage()];
+        }
+
+        return [true, ''];
+    }
+
+    //新增采购订单到本地--------------------------------------------
 
+    public function purchaseOrderAdd($data, $user){
+        list($status, $msg) = $this->purchaseOrderRule($data, $user);
+        if(! $status) return [false, $msg];
+
+        try {
+            DB::beginTransaction();
+
+            $model = new PoPomain();
+            $model->order_number = $this->generateBillNo([
+                'type' => PoPomain::Order_type,
+                'login_type' => $user['login_type'],
+                'period' => date("Ym")
+            ]);
+            $model->order_time = $data['order_time'];
+            $model->cBusType = $data['cBusType'];
+            $model->cPTCode = $data['cPTCode'];
+            $model->cPTCodeTitle = $data['cPTCodeTitle'];
+            $model->cVenCode = $data['cVenCode'];
+            $model->cVenCodeTitle = $data['cVenCodeTitle'];
+            $model->cappcode = !empty($data['cappcode']) ? (array)$data['cappcode'] : [];
+            $model->nflat = $data['nflat'] ?? 1;
+            $model->cexch_name = $data['cexch_name'] ?? '人民币';
+            $model->iTaxRate = $data['iTaxRate'] ?? 13;
+            $model->mark = $data['mark'] ?? '';
+            $model->login_type = $user['login_type'];
+            $model->crt_id = $user['userid'];
+            $model->save();
+
+            $this->saveODetail($model->id, $data);
+
+            DB::commit();
         } catch (\Throwable $exception) {
-            return [false, "查询库存失败: " . $exception->getMessage()];
+            DB::rollBack();
+            return [false, $exception->getMessage()];
         }
+
+        return [true, ''];
     }
 
-    //U8 供应商列表
-    public function vendorU8List($data, $user)
-    {
-        // 1. 构建基础查询
-        $query = DB::connection('sqlsrv')
-            ->table('Vendor as V')
-            ->select([
-                'V.cVenCode',          // 供应商编码
-                'V.cVenName',          // 供应商名称
-                'V.cVenAbbName',       // 供应商简称
-                'V.cVCCode',           // 分类编码
-                'VC.cVCName',         // 分类名称 (来自 VendorClass)
-                'V.cVenAddress',       // 地址
-                'V.cVenPhone',         // 电话
-                'V.dVenDevDate',       // 发展日期
-                'V.cCreatePerson',     // 创建人
-                'V.bVenTax',           // 是否计税
-                'V.iId'                // 内部ID
-            ])
-            // 关联供应商分类表获取分类名称
-            ->leftJoin('VendorClass as VC', 'V.cVCCode', '=', 'VC.cVCCode');
-
-        // 2. 增加搜索逻辑 (可选)
-        if (!empty($data['keyword'])) {
-            $keyword = $data['keyword'];
-            $query->where(function($q) use ($keyword) {
-                $q->where('V.cVenCode', 'like', "%{$keyword}%")
-                    ->orWhere('V.cVenName', 'like', "%{$keyword}%")
-                    ->orWhere('V.cVenAbbName', 'like', "%{$keyword}%");
-            });
+    private function saveODetail($id, $data){
+        if(! empty($data['details'])){
+            $unit = [];
+            foreach ($data['details'] as $value){
+                $unit[] = [
+                    'main_id' => $id,
+                    'iAppIds' => $value['iAppIds'] ?? 0,
+                    'cInvCode' => $value['cInvCode'],
+                    'quantity' => $value['quantity'],
+                    'price' => $value['price'],
+                    'rate' => $value['rate'],
+                    'dArriveDate' => $value['dArriveDate'],
+                    'name' => $value['name'],
+                    'size' => $value['size'] ?? '',
+                    'unit' => $value['unit'] ?? '',
+                ];
+            }
+            if(! empty($unit)) PoPodetails::insert($unit);
         }
+    }
 
-        // 3. 排序 (默认按编码排序)
-        $query->orderBy('V.cVenCode', 'ASC');
+    private function getODetail($id){
+        $data = PoPodetails::where('del_time',0)
+            ->where('main_id', $id)
+            ->get()->toArray();
 
-        // 4. 调用你定义的分页方法
-        // 注意:limit 方法内部会执行 paginate 并将结果填充到 $data
-        $columns = ['*']; // select 已经在上面定义过了,这里传 * 即可
-        $result = $this->limit($query, $columns, $data);
+        $detail = [
+            'details' => $data,
+        ];
 
-        return [true, $result];
+        return $detail;
     }
 
-    // U8 供应商分类树结构
-    public function vendorClassTree($data, $user)
-    {
+    public function purchaseOrderEdit($data, $user){
+        list($status, $msg) = $this->purchaseOrderRule($data, $user, false);
+        if(! $status) return [false, $msg];
+
         try {
-            // 1. 获取所有供应商分类 (表名: VendorClass)
-            $classes = DB::connection('sqlsrv')
-                ->table('VendorClass')
-                ->select('cVCCode', 'cVCName', 'iVCGrade', 'bVCEnd') // 编码、名称、级次
-                ->orderBy('cVCCode', 'asc')
-                ->get();
-
-            if ($classes->isEmpty()) {
-                return [true, []];
+            DB::beginTransaction();
+
+            $model = PoPomain::where('id', $data['id'])->first();
+            $model->order_time = $data['order_time'];
+            $model->cBusType = $data['cBusType'];
+            $model->cPTCode = $data['cPTCode'];
+            $model->cPTCodeTitle = $data['cPTCodeTitle'];
+            $model->cVenCode = $data['cVenCode'];
+            $model->cVenCodeTitle = $data['cVenCodeTitle'];
+            $model->cappcode = !empty($data['cappcode']) ? (array)$data['cappcode'] : [];
+            $model->iTaxRate = $data['iTaxRate'] ?? 13;
+            $model->nflat = $data['nflat'] ?? 1;
+            $model->cexch_name = $data['cexch_name'] ?? '人民币';
+            $model->mark = $data['mark'] ?? '';
+            $model->save();
+
+            PoPodetails::where('del_time',0)
+                ->where('main_id', $data['id'])
+                ->update(['del_time' => time()]);
+
+            $this->saveODetail($model->id, $data);
+
+            DB::commit();
+        } catch (\Throwable $exception) {
+            DB::rollBack();
+            return [false, "编辑采购订单失败: " . $exception->getMessage()];
+        }
+
+        return [true, ''];
+    }
+
+    public function purchaseOrderRule(&$data, $user, $is_add = true)
+    {
+        if(! $is_add && empty($data['id'])) return [false, 'ID不能为空'];
+        $id = $data['id'] ?? 0;
+
+        if(empty($data['order_time'])) return [false, '单据日期不能为空'];
+        $orderTime = trim($data['order_time']);
+        if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $orderTime) || strtotime($orderTime) === false) {
+            return [false, '单据日期格式不正确,必须为 YYYY-MM-DD 格式(如:2026-04-04)'];
+        }
+        if(empty($data['cVenCode']) || empty($data['cVenCodeTitle'])) return [false, '供应商信息不能为空'];
+
+        // ==================== 核心修改:支持 JSON 字符串单号强校验 ====================
+        $u8DetailsMap = [];
+        $isRefApp = !empty($data['cappcode']);
+        if($isRefApp && ! is_array($data['cappcode'])) return [false, '请购单号非数组结构'];
+
+        if ($isRefApp) {
+            $service = new U8ServerService($user);
+            $error = $service->getError();
+            if(! empty($error)) return [false, $error];
+
+            // 1. 规整单号为干净的数组
+            $cappcodes = $data['cappcode'];
+            $cappcodes = array_filter(array_map('trim',$cappcodes));
+
+            // 【优化】如果数组被过滤后变空了,说明没有真正的参照单号,将 $isRefApp 标记为 false 即可,不直接报错
+            if (empty($cappcodes)) {
+                $isRefApp = false;
+            } else {
+                // 2. 调用用友接口,获取最新的可用明细
+                list($status, $u8Details) = $service->getRequisitionDetailsByCode($cappcodes);
+                if(! $status) return [false, $u8Details];
+
+                foreach ($u8Details as $u8Item) {
+                    $u8DetailsMap[$u8Item['detail_id']] = $u8Item;
+                }
+
+                // 3. 统计本地已预占的数量
+                $localOccupiedQuery = DB::table('po_pomain as m')
+                    ->join('po_podetails as d', 'd.main_id', '=', 'm.id')
+                    ->where('m.del_time', 0)
+                    ->where('d.del_time', 0)
+                    ->where('m.code', ''); // 还没同步成功
+
+                // 如果是编辑操作,排除自身
+                if (!$is_add) {
+                    $localOccupiedQuery->where('m.id', '!=', $id);
+                }
+
+                // 使用 JSON_CONTAINS 匹配本地主表中的 JSON 字段
+                $localOccupiedQuery->where(function ($query) use ($cappcodes) {
+                    foreach ($cappcodes as $index => $code) {
+                        if ($index === 0) {
+                            $query->whereRaw('JSON_CONTAINS(m.cappcode, ?)', ['"' . $code . '"']);
+                        } else {
+                            $query->orWhereRaw('JSON_CONTAINS(m.cappcode, ?)', ['"' . $code . '"']);
+                        }
+                    }
+                });
+
+                // 聚合得出被预占的总数量
+                $localOccupiedRows = $localOccupiedQuery->select(
+                    'd.iAppIds',
+                    DB::raw('SUM(d.quantity) as total_qty')
+                )
+                    ->groupBy('d.iAppIds')
+                    ->get();
+
+                $localOccupiedMap = [];
+                foreach ($localOccupiedRows as $row) {
+                    $localOccupiedMap[$row->iAppIds] = (float)$row->total_qty;
+                }
             }
+        }
+        // ====================================================================
 
-            // 2. 格式化数据,以编码为 Key
-            $classList = [];
-            foreach ($classes as $item) {
-                $classList[$item->cVCCode] = [
-                    'label'    => $item->cVCName,
-                    'value'    => $item->cVCCode, // 前端通常需要 value 字段
-                    'code'     => $item->cVCCode,
-                    'grade'    => $item->iVCGrade,
-                    'is_end'    => $item->bVCEnd,
-                    'children' => []
-                ];
+        if(empty($data['details'])) return [false, '表体不能为空'];
+        foreach ($data['details'] as $key => $value){
+            $line = "第 " . ($key + 1) . "行";
+            if(empty($value['cInvCode'])) return [false, $line . '存货编码不能为空'];
+            if(empty($value['name'])) return [false, $line . '存货名称不能为空'];
+
+            $currentQty = floatval($value['quantity'] ?? 0);
+            if(! is_numeric($value['quantity']) || $currentQty <= 0.0) return [false, $line . '存货数量不正常'];
+            if(! isset($value['rate']) || ! is_numeric($value['rate'])) return [false, $line . '税率为空或非数字'];
+
+            if(empty($value['dArriveDate'])) return [false, $line . '建议订货日期不能为空'];
+
+            $dArriveDate = trim($value['dArriveDate']);
+            if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $dArriveDate) || strtotime($dArriveDate) === false) {
+                return [false, $line . "计划到货日期格式不正确,必须为 YYYY-MM-DD"];
+            }
+
+            $timeOrder = strtotime($orderTime);
+            $timeArrive = strtotime($dArriveDate);
+            if ($timeArrive < $timeOrder) {
+                return [false, $line . "计划到货日期({$dArriveDate})不能早于单据日期({$orderTime})"];
             }
 
-            // 3. 构建引用树
-            $tree = [];
-            foreach ($classList as $code => &$node) {
-                // 获取父级编码
-                $parentCode = $this->getParentCode($code);
+            // ==================== 逐行精确匹配校验数量(混合单据核心修改) ====================
+            // 【关键改动】:不仅表头是参照,且当前行有具体的请购单明细ID(iAppIds > 0),才进行用友和本地库存校验
+            $iAppIds = isset($value['iAppIds']) ? (int)$value['iAppIds'] : 0;
 
-                if ($parentCode === null || !isset($classList[$parentCode])) {
-                    // 顶级节点
-                    $tree[] = &$node;
-                } else {
-                    // 挂载到父节点
-                    $classList[$parentCode]['children'][] = &$node;
+            if ($isRefApp && $iAppIds > 0) {
+
+                if (!isset($u8DetailsMap[$iAppIds])) {
+                    return [false, $line . "对应的请购单明细在用友系统已无剩余可用量或该请购单号输入有误,请刷新数据!"];
+                }
+
+                $u8RefCode = $u8DetailsMap[$iAppIds]['cappcode'];
+                $u8AvailableQty = (float)$u8DetailsMap[$iAppIds]['available_qty'];
+                $localOccupiedQty = $localOccupiedMap[$iAppIds] ?? 0.0;
+
+                $realAvailableQty = $u8AvailableQty - $localOccupiedQty;
+
+                if ($currentQty > $realAvailableQty) {
+                    if ($localOccupiedQty > 0) {
+                        return [false, $line . "【请购单:{$u8RefCode}】可下单数量不足!用友剩余: {$u8AvailableQty},本地在途预占: {$localOccupiedQty},实际可用仅剩: {$realAvailableQty},当前输入: {$currentQty}"];
+                    } else {
+                        return [false, $line . "【请购单:{$u8RefCode}】可下单数量不足!用友系统最大可用量为: {$u8AvailableQty},当前输入: {$currentQty}"];
+                    }
                 }
             }
+            // ====================================================================
+        }
+
+        if(! $is_add){
+            $order = PoPomain::where('id', $data['id'])->where('del_time',0)->first();
+            if(empty($order)) return [false, '采购单信息不存在或已被删除'];
+            $order = $order->toArray();
+            list($status, $msg) = $this->checkState(U8State::type_one, $user, $order['order_number']);
+            if(! $status) return [false, $msg];
+        }
+
+        return [true, ''];
+    }
+
+    public function purchaseOrderCommon($data, $user, $field = []){
+        $type = U8State::type_one;
+        $qx = $user['qx'];
+
+        $model = PoPomain::from('po_pomain as v')
+            ->leftJoin('u8_state as s', function ($join) use ($type, $user) {
+                $join->on('v.order_number', '=', 's.order_number')
+                    ->where('s.type', '=', $type)
+                    ->where('s.login_type', '=', $user['login_type'])
+                    ->where('s.del_time', '=', 0);
+            })
+            ->where('v.del_time', 0)
+            ->when(empty($qx), function ($query) use($user){
+                return $query->where('v.crt_id', $user['userid']);
+            })
+            ->select('v.*', DB::raw('IFNULL(s.state, -1) as state'),'s.result')
+            ->orderby('v.id', 'desc');
+
+        if (isset($data['state']) && $data['state'] !== '') {
+            $state_filter = $data['state'];
+            if ($state_filter == -1) {
+                // 未发起审批:u8_states 表里没记录,s.id 就会是 NULL
+                $model->whereNull('s.id');
+            } else {
+                // 0:待审核 1:通过 2:驳回
+                $model->where('s.state', $state_filter);
+            }
+        }
+
+        if(! empty($data['code'])) $model->where('v.code', 'like', '%' . $data['code'] . '%');
+        if(! empty($data['id'])) $model->where('v.id', $data['id']);
+        if(! empty($data['order_number'])) $model->where('v.order_number', 'like', '%' . $data['order_number'] . '%');
+        if(! empty($data['crt_time'][0]) && ! empty($data['crt_time'][1])) {
+            $return = $this->changeDateToTimeStampAboutRange($data['crt_time']);
+            $model->where('v.crt_time', '>=', $return[0]);
+            $model->where('v.crt_time', '<=', $return[1]);
+        }
+
+        return $model;
+    }
+
+    public function purchaseOrderList($data, $user){
+        $model = $this->purchaseOrderCommon($data, $user);
+        $list = $this->limit($model,'',$data);
+        $list = $this->fillPurchaseOrderData($list,$user);
+
+        return [true, $list];
+    }
+
+    public function fillPurchaseOrderData($data, $user){
+        if(empty($data['data'])) return $data;
+
+        $e_map = DDEmployee::whereIn('userid', array_unique(array_column($data['data'], 'crt_id')))
+            ->where('login_type', $user['login_type'])
+            ->pluck('name', 'userid')
+            ->toArray();
+        foreach ($data['data'] as $key => $value){
+            $data['data'][$key]['crt_name'] = $e_map[$value['crt_id']] ?? "";
+            $data['data'][$key]['crt_time'] = $value['crt_time'] ? date('Y-m-d H:i:s',$value['crt_time']) : '';
+            $data['data'][$key]['state_title'] = U8State::state_name[$value['state']];
+        }
+
+        return $data;
+    }
+
+    public function purchaseOrderMyDetail($data, $user){
+        $id = $data['id'] ?? 0;
+        $order_number = $data['order_number'] ?? "";
+        if(empty($id) && empty($order_number)) return [false,'请选择数据'];
+
+        $customer = PoPomain::where('del_time',0)
+            ->when(! empty($id), function ($query) use($id){
+                return $query->where('id', $id);
+            })
+            ->when(! empty($order_number), function ($query) use($order_number){
+                return $query->where('id', $order_number);
+            })
+            ->where('login_type', $user['login_type'])
+            ->first();
+        if(empty($customer)) return [false,'采购订单不存在或已被删除'];
+        $customer = $customer->toArray();
+        $customer['crt_name'] = DDEmployee::where('id',$customer['crt_id'])->value('name');
+        $customer['crt_time'] = $customer['crt_time'] ? date("Y-m-d H:i:s",$customer['crt_time']): '';
+
+        $details = $this->getODetail($data['id']);
+        $customer = array_merge($customer, $details);
+
+        return [true, $customer];
+    }
+
+    public function purchaseOrderDel($data, $user){
+        if($this->isEmpty($data,'id')) return [false,'请选择数据!'];
+
+        try {
+            DB::beginTransaction();
+            $time = time();
+
+            $order = PoPomain::where('id', $data['id'])->where('del_time',0)->first();
+            if(empty($order)) return [false, '采购订单信息不存在或已被删除'];
+            $order = $order->toArray();
+            list($status, $msg) = $this->checkState(U8State::type_one, $user, $order['order_number']);
+            if(! $status) return [false, $msg];
+
+            PoPomain::where('del_time',0)
+                ->where('id',$data['id'])
+                ->update(['del_time' => $time]);
+
+            PoPodetails::where('del_time',0)
+                ->where('main_id',$data['id'])
+                ->update(['del_time' => $time]);
+
+            DB::commit();
+        }catch (\Exception $exception){
+            DB::rollBack();
+            return [false,$exception->getMessage()];
+        }
+
+        return [true, ''];
+    }
+
+    // 新增采购入库单到本地
 
-            return [true, $tree];
+    public function purchaseOrderInAdd($data, $user)
+    {
+        list($status, $msg) = $this->purchaseOrderInRule($data, $user);
+        if (!$status) return [false, $msg];
+
+        try {
+            DB::beginTransaction();
 
+            $model = new RdRecord01();
+            $model->order_number = $this->generateBillNo([
+                'type' => RdRecord01::Order_type,
+                'login_type' => $user['login_type'],
+                'period' => date("Ym")
+            ]);
+            $model->order_time         = $data['order_time'];
+            $model->cBusType            = $data['cBusType'] ?? '普通采购';
+            $model->cPTCode             = $data['cPTCode'];
+            $model->cPTCodeTitle        = $data['cPTCodeTitle'];
+            $model->cVenCode            = $data['cVenCode'];
+            $model->cVenCodeTitle       = $data['cVenCodeTitle'];
+            // 存储采购订单号数组为 JSON
+            $model->cOrderCode = !empty($data['cOrderCode']) ? (array)$data['cOrderCode'] : [];
+            $model->warehouseCode       = $data['warehouseCode'];
+            $model->warehouseCodeTitle  = $data['warehouseCodeTitle'];
+            $model->cRdCode             = $data['cRdCode'];
+            $model->cRdCodeTitle        = $data['cRdCodeTitle'];
+            $model->bredvouch           = isset($data['bredvouch']) ? (int)$data['bredvouch'] : 0; // 0蓝 1红
+            $model->iTaxRate            = $data['iTaxRate'] ?? 13;
+            $model->nflat               = $data['nflat'] ?? 1;
+            $model->cexch_name          = $data['cexch_name'] ?? '人民币';
+            $model->mark                = $data['mark'] ?? '';
+            $model->login_type          = $user['login_type'];
+            $model->crt_id              = $user['userid'];
+            $model->save();
+
+            $this->saveOIDetail($model->id, $data);
+
+            DB::commit();
         } catch (\Throwable $exception) {
-            return [false, "获取供应商分类树失败: " . $exception->getMessage()];
+            DB::rollBack();
+            return [false, "新增采购入库单失败: " . $exception->getMessage()];
         }
+
+        return [true, ''];
     }
 
-    //U8 存货分类树结构
-    public function inventoryClassTree($data, $user)
+    public function purchaseOrderInEdit($data, $user)
     {
+        list($status, $msg) = $this->purchaseOrderInRule($data, $user, false);
+        if (!$status) return [false, $msg];
+
         try {
-            // 1. 从数据库获取所有存货分类
-            $classes = DB::connection('sqlsrv')
-                ->table('InventoryClass')
-                ->select('cInvCCode', 'cInvCName', 'iInvCGrade', 'bInvCEnd')
-                ->orderBy('cInvCCode', 'asc')
-                ->get();
-
-            if ($classes->isEmpty()) return [true, []];
-
-            // 2. 将集合转换为数组并以编码作为 Key,方便查找
-            $classList = [];
-            foreach ($classes as $item) {
-                $classList[$item->cInvCCode] = [
-                    'label'    => $item->cInvCName,
-                    'code'     => $item->cInvCCode,
-                    'grade'    => $item->iInvCGrade,
-                    'is_end'    => $item->bInvCEnd,
-                    'children' => []
-                ];
-            }
+            DB::beginTransaction();
+
+            $model = RdRecord01::where('id', $data['id'])->first();
+            if (empty($model)) return [false, '单据不存在'];
+
+            $model->order_time         = $data['order_time'];
+            $model->cBusType            = $data['cBusType'] ?? '普通采购';
+            $model->cPTCode             = $data['cPTCode'];
+            $model->cPTCodeTitle        = $data['cPTCodeTitle'];
+            $model->cVenCode            = $data['cVenCode'];
+            $model->cVenCodeTitle       = $data['cVenCodeTitle'];
+            $model->cOrderCode = !empty($data['cOrderCode']) ? (array)$data['cOrderCode'] : [];
+            $model->warehouseCode       = $data['warehouseCode'];
+            $model->warehouseCodeTitle  = $data['warehouseCodeTitle'];
+            $model->cRdCode             = $data['cRdCode'];
+            $model->cRdCodeTitle        = $data['cRdCodeTitle'];
+            $model->iTaxRate            = $data['iTaxRate'] ?? 13;
+            $model->nflat               = $data['nflat'] ?? 1;
+            $model->cexch_name          = $data['cexch_name'] ?? '人民币';
+            $model->mark                = $data['mark'] ?? '';
+            $model->save();
+
+            // 软删除老明细
+            RdRecords01::where('del_time', 0)
+                ->where('main_id', $data['id'])
+                ->update(['del_time' => time()]);
+
+            $this->saveOIDetail($model->id, $data);
+
+            DB::commit();
+        } catch (\Throwable $exception) {
+            DB::rollBack();
+            return [false, "编辑采购入库单失败: " . $exception->getMessage()];
+        }
+
+        return [true, ''];
+    }
+
+    public function purchaseOrderInRule(&$data, $user, $is_add = true)
+    {
+        if (!$is_add && empty($data['id'])) return [false, 'ID不能为空'];
+        $id = $data['id'] ?? 0;
+
+        if (empty($data['order_time'])) return [false, '单据日期不能为空'];
+        $orderTime = trim($data['order_time']);
+        if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $orderTime) || strtotime($orderTime) === false) {
+            return [false, '单据日期格式不正确,必须为 YYYY-MM-DD 格式'];
+        }
+        if (empty($data['cVenCode']) || empty($data['cVenCodeTitle'])) return [false, '供应商信息不能为空'];
+        if (empty($data['warehouseCode']) || empty($data['warehouseCodeTitle'])) return [false, '仓库信息不能为空'];
+        if (empty($data['cRdCode']) || empty($data['cRdCodeTitle'])) return [false, '收发类别不能为空'];
+
+        if(! isset($data['bredvouch'])) return [false, '蓝单|红单标识不存在'];
+        $bredvouch = $data['bredvouch']; // 0蓝单 1红单
+
+        // ==================== 核心逻辑:精准追溯用友采购订单及本地预占 ====================
+        if(empty($data['cOrderCode']) || !is_array($data['cOrderCode'])) return [false, '采购订单不能为空或类型错误'];
+
+        $u8PoDetailsMap = [];
+
+        $service = new U8ServerService($user);
+        $error = $service->getError();
+        if (!empty($error)) return [false, $error];
+
+        $cOrderCodes = array_filter(array_map('trim', $data['cOrderCode']));
+        if (empty($cOrderCodes)) return [false, '参照生成的采购订单号不能为空'];
+
+        // 1. 调用用友接口,获取最新采购订单的明细流(包含未入库量、已入库量、原订单量)
+        list($status, $u8PoDetails) = $service->getPurchaseOrderDetailsByCode($cOrderCodes);
+        if (!$status) return [false, $u8PoDetails];
+
+        foreach ($u8PoDetails as $u8Item) {
+            $u8PoDetailsMap[$u8Item['detail_id']] = $u8Item;
+        }
+
+        // 2. 统计本地已预占/已入库(code为空,未完全同步到用友)的入库数量
+        $localOccupiedQuery = DB::table('rd_record01 as m')
+            ->join('rd_records01 as d', 'd.main_id', '=', 'm.id')
+            ->where('m.del_time', 0)
+            ->where('d.del_time', 0)
+            ->where('m.code', ''); // 排除用友已落单的数据,防止重复扣减
 
-            // 3. 构建树形结构
-            $tree = [];
-            foreach ($classList as $code => &$node) {
-                // 获取当前分类的级次 (U8 逻辑通常根据编码长度判断父级)
-                // 比如 0101 的父级是 01
-                $parentCode = $this->getParentCode($code);
+        if (!$is_add) {
+            $localOccupiedQuery->where('m.id', '!=', $id);
+        }
 
-                if ($parentCode === null || !isset($classList[$parentCode])) {
-                    // 如果没有父级编码,或者父级编码不在列表里,说明是顶级分类
-                    $tree[] = &$node;
+        // 使用 JSON_CONTAINS 圈定本次涉及的订单号在本地的预占
+        $localOccupiedQuery->where(function ($query) use ($cOrderCodes) {
+            foreach ($cOrderCodes as $index => $code) {
+                if ($index === 0) {
+                    $query->whereRaw('JSON_CONTAINS(m.cOrderCode, ?)', ['"' . $code . '"']);
                 } else {
-                    // 将当前节点引用到父节点的 children 数组中
-                    $classList[$parentCode]['children'][] = &$node;
+                    $query->orWhereRaw('JSON_CONTAINS(m.cOrderCode, ?)', ['"' . $code . '"']);
                 }
             }
+        });
 
-            return [true, $tree];
+        $localOccupiedRows = $localOccupiedQuery->select(
+            'd.iPOsID',
+            DB::raw('SUM(d.quantity) as total_qty') // 蓝单为正,红单为负,直接聚合
+        )
+            ->groupBy('d.iPOsID')
+            ->get();
 
-        } catch (\Throwable $exception) {
-            return [false, "获取分类树失败: " . $exception->getMessage()];
+        $localOccupiedMap = [];
+        foreach ($localOccupiedRows as $row) {
+            $localOccupiedMap[$row->iPOsID] = (float)$row->total_qty;
+        }
+        // ====================================================================
+
+        if (empty($data['details'])) return [false, '表体明细不能为空'];
+        foreach ($data['details'] as $key => $value) {
+            $line = "第 " . ($key + 1) . "行";
+            if (empty($value['cInvCode'])) return [false, $line . '存货编码不能为空'];
+            if (empty($value['name'])) return [false, $line . '存货名称不能为空'];
+
+            $currentQty = floatval($value['quantity'] ?? 0);
+            if ($bredvouch === 0 && $currentQty <= 0) {
+                return [false, $line . '正数入库单(蓝单)存货数量必须大于0'];
+            }
+            if ($bredvouch === 1 && $currentQty >= 0) {
+                return [false, $line . '负数入库单(红单/退货)存货数量必须小于0'];
+            }
+
+            if(empty($value['iPOsID'])) return [false, '采购订单子表ID不能为空'];
+
+            // ==================== 混合单据逐行精细校验数量 ====================
+            $iPOsID = $value['iPOsID'];
+
+            if (!isset($u8PoDetailsMap[$iPOsID])) {
+                return [false, $line . "对应的采购订单明细在用友系统不可用或已被关闭,请核对!"];
+            }
+
+            $poCode = $u8PoDetailsMap[$iPOsID]['order_number'];     // 来源采购订单号
+            $poQty = (float)$u8PoDetailsMap[$iPOsID]['po_qty'];        // 订单总执行量
+            $u8ReceivedQty = (float)$u8PoDetailsMap[$iPOsID]['received_qty']; // 用友端已入库累计
+            $localOccupiedQty = $localOccupiedMap[$iPOsID] ?? 0;     // 本地中转在途入库累计
+
+            if ($bredvouch === 0) {
+                // 【蓝单场景】:控制不能超过未入库余量
+                // 可入库余量 = 订单总数 - 用友已入库 - 本地在途入库
+                $availableQty = $poQty - $u8ReceivedQty - $localOccupiedQty;
+                if ($currentQty > $availableQty) {
+                    return [false, $line . "【订单:{$poCode}】超过最大可入库量!用友订单待入库: " . ($poQty - $u8ReceivedQty) . ",本地在途预占: {$localOccupiedQty},实际可用余量: {$availableQty},当前输入: {$currentQty}"];
+                }
+            } else {
+                // 【红单退货场景】:控制退货绝对值不能大于总共已经成功入库的数量
+                // 总入库资产量 = 用友已确认入库 + 本地在途蓝单数量(若有本地在途红单则会冲减)
+                $totalInStockQty = $u8ReceivedQty + $localOccupiedQty;
+                if (abs($currentQty) > $totalInStockQty) {
+                    return [false, $line . "【订单:{$poCode}】退货数量超标!该产品系统累计总入库资产仅为: {$totalInStockQty},本次尝试退货: " . abs($currentQty)];
+                }
+            }
+        }
+
+        if (!$is_add) {
+            $order = RdRecord01::where('id', $data['id'])->where('del_time', 0)->first();
+            if (empty($order)) return [false, '单据信息不存在或已被删除'];
+            $order = $order->toArray();
+            if($order['bredvouch'] != $bredvouch) return [false, '编辑不允许修改红蓝单标识'];
+            list($status, $msg) = $this->checkState(U8State::type_three, $user, $order['order_number']);
+            if (!$status) return [false, $msg];
+        }
+
+        return [true, ''];
+    }
+
+    private function saveOIDetail($id, $data)
+    {
+        if (!empty($data['details'])) {
+            $unit = [];
+            foreach ($data['details'] as $value) {
+                $unit[] = [
+                    'main_id'     => $id,
+                    'iPOsID'      => $value['iPOsID'] ?? 0, // 核心外键:对应用友采购订单明细AutoID
+                    'cInvCode'    => $value['cInvCode'],
+                    'quantity'    => $value['quantity'],
+                    'price'       => $value['price'] ?? 0,
+                    'rate'        => $value['rate'] ?? 0,
+                    'name'        => $value['name'],
+                    'size'        => $value['size'] ?? '',
+                    'unit'        => $value['unit'] ?? '',
+                    'cBatch'        => $value['cBatch'] ?? '',
+                    'dMadeDate'        => $value['dMadeDate'] ?? '',
+                    'dVDate'        => $value['dVDate'] ?? '',
+                ];
+            }
+            if (!empty($unit)) RdRecords01::insert($unit);
         }
     }
 
-    /**
-     * 辅助函数:根据 U8 编码规则获取父级编码
-     * U8 的级次通常存储在 GradeDef 表,但通用逻辑是截取末尾
-     */
-    private function getParentCode($code)
+    private function getOIDetail($id)
     {
-        $len = strlen($code);
-        if ($len <= 2) return null; // 假设第一级是2位,小于等于2位则无父级
+        $data = RdRecords01::where('del_time', 0)
+            ->where('main_id', $id)
+            ->get()->toArray();
 
-        // 这里假设级次是 2-2-2-2 (最常见配置)
-        // 实际生产中,如果级次不固定,建议查询 GradeDef 表
-        return substr($code, 0, $len - 2);
+        return ['details' => $data];
     }
 
-    //U8 计量单位组(带默认主计量单位)
-    public function getUnitGroups($data, $user)
+    public function purchaseOrderInCommon($data, $user, $field = [])
     {
-        $list = DB::connection('sqlsrv')
-            ->select("
-        SELECT 
-            G.cGroupCode, 
-            G.cGroupName, 
-            G.iGroupType, 
-            U.cComUnitCode, 
-            U.cComUnitName,
-            U.iNumber
-        FROM ComputationGroup AS G
-        OUTER APPLY (
-            SELECT TOP 1 cComUnitCode, cComUnitName, iNumber
-            FROM ComputationUnit
-            WHERE cGroupCode = G.cGroupCode
-            ORDER BY 
-                bMainUnit DESC,         -- 1. 优先主计量
-                iNumber ASC,            -- 2. 序号最小 (若 NULL 会排在最前)
-                cComUnitCode ASC        -- 3. 编码最小
-        ) AS U
-    ");
+        $type = U8State::type_three;
+        $qx = $user['qx'];
 
-        return [true, $list];
+        $model = RdRecord01::from('rd_record01 as v')
+            ->leftJoin('u8_state as s', function ($join) use ($type, $user) {
+                $join->on('v.order_number', '=', 's.order_number')
+                    ->where('s.type', '=', $type)
+                    ->where('s.login_type', '=', $user['login_type'])
+                    ->where('s.del_time', '=', 0);
+            })
+            ->where('v.del_time', 0)
+            ->when(empty($qx), function ($query) use ($user) {
+                return $query->where('v.crt_id', $user['userid']);
+            })
+            ->select('v.*', DB::raw('IFNULL(s.state, -1) as state'), 's.result')
+            ->orderby('v.id', 'desc');
+
+        if (isset($data['state']) && $data['state'] !== '') {
+            $state_filter = $data['state'];
+            if ($state_filter == -1) {
+                $model->whereNull('s.id');
+            } else {
+                $model->where('s.state', $state_filter);
+            }
+        }
+
+        if (!empty($data['code'])) $model->where('v.code', 'like', '%' . $data['code'] . '%');
+        if (!empty($data['id'])) $model->where('v.id', $data['id']);
+        if (!empty($data['order_number'])) $model->where('v.order_number', 'like', '%' . $data['order_number'] . '%');
+        if (!empty($data['crt_time'][0]) && !empty($data['crt_time'][1])) {
+            $return = $this->changeDateToTimeStampAboutRange($data['crt_time']);
+            $model->where('v.crt_time', '>=', $return[0]);
+            $model->where('v.crt_time', '<=', $return[1]);
+        }
+
+        return $model;
     }
 
-    //U8 计量单位档案
-    public function getComputationUnitList($data, $user)
+    public function purchaseOrderInList($data, $user)
     {
-        $list = DB::connection('sqlsrv')
-            ->table('ComputationUnit as U')
-            ->select(
-                'U.cComUnitCode',   // 单位编码
-                'U.cComUnitName',   // 单位名称
-                'U.cGroupCode',     // 所属组编码
-                'U.bMainUnit',      // 是否主单位
-                'U.iNumber'         // 排序序号
-            )
-            ->orderBy('U.cGroupCode', 'ASC')
-            ->orderBy('U.iNumber', 'ASC') // 按照你要求的 iNumber 排序
-            ->get();
+        $model = $this->purchaseOrderInCommon($data, $user);
+        $list  = $this->limit($model, '', $data);
+        $list  = $this->fillPurchaseOrderInData($list, $user);
 
         return [true, $list];
     }
+
+    public function fillPurchaseOrderInData($data, $user)
+    {
+        if (empty($data['data'])) return $data;
+
+        $e_map = DDEmployee::whereIn('userid', array_unique(array_column($data['data'], 'crt_id')))
+            ->where('login_type', $user['login_type'])
+            ->pluck('name', 'userid')
+            ->toArray();
+        foreach ($data['data'] as $key => $value) {
+            $data['data'][$key]['crt_name']    = $e_map[$value['crt_id']] ?? "";
+            $data['data'][$key]['crt_time']    = $value['crt_time'] ? date('Y-m-d H:i:s', $value['crt_time']) : '';
+            $data['data'][$key]['state_title'] = U8State::state_name[$value['state']] ?? '';
+            $data['data'][$key]['bredvouch_title'] = RdRecord01::$bredvouch_title[$value['bredvouch']] ?? '';
+        }
+
+        return $data;
+    }
+
+    public function purchaseOrderInMyDetail($data, $user)
+    {
+        $id = $data['id'] ?? 0;
+        $order_number = $data['order_number'] ?? "";
+        if (empty($id) && empty($order_number)) return [false, '请选择数据'];
+
+        $customer = RdRecord01::where('del_time', 0)
+            ->when(!empty($id), function ($query) use ($id) {
+                return $query->where('id', $id);
+            })
+            ->when(!empty($order_number), function ($query) use ($order_number) {
+                return $query->where('order_number', $order_number);
+            })
+            ->where('login_type', $user['login_type'])
+            ->first();
+
+        if (empty($customer)) return [false, '采购入库单不存在或已被删除'];
+        $customer = $customer->toArray();
+        $customer['crt_name']   = DDEmployee::where('userid', $customer['crt_id'])->value('name') ?: '';
+        $customer['crt_time']   = $customer['crt_time'] ? date("Y-m-d H:i:s", $customer['crt_time']) : '';
+
+        $details  = $this->getOIDetail($customer['id']);
+        $customer = array_merge($customer, $details);
+
+        return [true, $customer];
+    }
+
+    public function purchaseOrderInDel($data, $user)
+    {
+        if (empty($data['id'])) return [false, '请选择数据!'];
+
+        try {
+            DB::beginTransaction();
+            $time = time();
+
+            $order = RdRecord01::where('id', $data['id'])->where('del_time', 0)->first();
+            if (empty($order)) return [false, '单据信息不存在或已被删除'];
+            $order = $order->toArray();
+
+            list($status, $msg) = $this->checkState(U8State::type_three, $user, $order['order_number']);
+            if (!$status) return [false, $msg];
+
+            RdRecord01::where('del_time', 0)->where('id', $data['id'])->update(['del_time' => $time]);
+            RdRecords01::where('del_time', 0)->where('main_id', $data['id'])->update(['del_time' => $time]);
+
+            DB::commit();
+        } catch (\Exception $exception) {
+            DB::rollBack();
+            return [false, $exception->getMessage()];
+        }
+
+        return [true, ''];
+    }
 }

+ 29 - 0
config/header/84.php

@@ -0,0 +1,29 @@
+<?php
+/**
+ * '菜单ID' => [
+ *     '字段英文名' =》 '字段中文名'
+ * ]
+ */
+
+return [
+    [
+        'key' =>'order_time',
+        'value' => '单据日期',
+    ],
+    [
+        'key' =>'order_number',
+        'value' => '流水号',
+    ],
+    [
+        'key' =>'cBusType',
+        'value' => '业务类型',
+    ],
+    [
+        'key' =>'cPTCodeTitle',
+        'value' => '采购类型',
+    ],
+    [
+        'key' =>'crt_name',
+        'value' => '制单人',
+    ],
+];

+ 37 - 0
config/header/85.php

@@ -0,0 +1,37 @@
+<?php
+/**
+ * '菜单ID' => [
+ *     '字段英文名' =》 '字段中文名'
+ * ]
+ */
+
+return [
+    [
+        'key' =>'order_time',
+        'value' => '单据日期',
+    ],
+    [
+        'key' =>'order_number',
+        'value' => '流水号',
+    ],
+    [
+        'key' =>'cBusType',
+        'value' => '业务类型',
+    ],
+    [
+        'key' =>'cPTCodeTitle',
+        'value' => '采购类型',
+    ],
+    [
+        'key' =>'cVenCodeTitle',
+        'value' => '供应商名称',
+    ],
+    [
+        'key' =>'mark',
+        'value' => '备注',
+    ],
+    [
+        'key' =>'crt_name',
+        'value' => '制单人',
+    ],
+];

+ 49 - 0
config/header/86.php

@@ -0,0 +1,49 @@
+<?php
+/**
+ * '菜单ID' => [
+ *     '字段英文名' =》 '字段中文名'
+ * ]
+ */
+
+return [
+    [
+        'key' =>'order_time',
+        'value' => '单据日期',
+    ],
+    [
+        'key' =>'bredvouch_title',
+        'value' => '单据类型',
+    ],
+    [
+        'key' =>'order_number',
+        'value' => '流水号',
+    ],
+    [
+        'key' =>'cBusType',
+        'value' => '业务类型',
+    ],
+    [
+        'key' =>'cPTCodeTitle',
+        'value' => '采购类型',
+    ],
+    [
+        'key' =>'cRdCodeTitle',
+        'value' => '收发类型',
+    ],
+    [
+        'key' =>'cVenCodeTitle',
+        'value' => '供应商名称',
+    ],
+    [
+        'key' =>'warehouseCodeTitle',
+        'value' => '仓库名称',
+    ],
+    [
+        'key' =>'mark',
+        'value' => '备注',
+    ],
+    [
+        'key' =>'crt_name',
+        'value' => '制单人',
+    ],
+];

+ 37 - 0
routes/api.php

@@ -112,6 +112,12 @@ Route::group(['middleware'=> ['checkLogin']],function ($route){
     $route->any('vendorU8List', 'Api\U8Controller@vendorU8List');
     //存货库存列表(用友)
     $route->any('stockU8List', 'Api\U8Controller@stockList');
+    //采购类型
+    $route->any('getPurchaseTypeList', 'Api\U8Controller@getPurchaseTypeList');
+    //存货档案
+    $route->any('inventoryU8List', 'Api\U8Controller@inventoryU8List');
+    //仓库档案
+    $route->any('warehouseU8List', 'Api\U8Controller@warehouseU8List');
     // U8数据获取 -----------------------------------------------------
 
     //存货新增编辑(到本地)
@@ -128,6 +134,37 @@ Route::group(['middleware'=> ['checkLogin']],function ($route){
     $route->any('vendorDetail', 'Api\U8Controller@vendorDetail');
     $route->any('vendorList', 'Api\U8Controller@vendorList');
 
+    //请购单新增编辑(到本地)
+    $route->any('purchaseRequisitionAdd', 'Api\U8Controller@purchaseRequisitionAdd');
+    $route->any('purchaseRequisitionEdit', 'Api\U8Controller@purchaseRequisitionEdit');
+    $route->any('purchaseRequisitionDel', 'Api\U8Controller@purchaseRequisitionDel');
+    $route->any('purchaseRequisitionMyDetail', 'Api\U8Controller@purchaseRequisitionMyDetail');
+    $route->any('purchaseRequisitionList', 'Api\U8Controller@purchaseRequisitionList');
+
+    //u8请购单
+    $route->any('purchaseRequisitionU8List', 'Api\U8Controller@purchaseRequisitionU8List');
+    //请购明细
+    $route->any('getRequisitionDetails', 'Api\U8Controller@getRequisitionDetails');
+
+    //采购订单新增编辑(到本地)
+    $route->any('purchaseOrderAdd', 'Api\U8Controller@purchaseOrderAdd');
+    $route->any('purchaseOrderEdit', 'Api\U8Controller@purchaseOrderEdit');
+    $route->any('purchaseOrderDel', 'Api\U8Controller@purchaseOrderDel');
+    $route->any('purchaseOrderMyDetail', 'Api\U8Controller@purchaseOrderMyDetail');
+    $route->any('purchaseOrderList', 'Api\U8Controller@purchaseOrderList');
+
+    //u8采购订单
+    $route->any('purchaseOrderU8List', 'Api\U8Controller@purchaseOrderU8List');
+    //u8采购订单明细
+    $route->any('getPurchaseOrderDetails', 'Api\U8Controller@getPurchaseOrderDetails');
+
+    //采购入库单新增编辑(到本地)
+    $route->any('purchaseOrderInAdd', 'Api\U8Controller@purchaseOrderInAdd');
+    $route->any('purchaseOrderInEdit', 'Api\U8Controller@purchaseOrderInEdit');
+    $route->any('purchaseOrderInDel', 'Api\U8Controller@purchaseOrderInDel');
+    $route->any('purchaseOrderInMyDetail', 'Api\U8Controller@purchaseOrderInMyDetail');
+    $route->any('purchaseOrderInList', 'Api\U8Controller@purchaseOrderInList');
+
     //获取钉钉人员列表
     $route->any('ddEmployeeList', 'Api\U8Controller@ddEmployeeList');
     $route->any('getField', 'Api\U8Controller@getField');