'采购入库', self::two => '采购退货', self::three => '材料出库', self::four => '销售出库', self::five => '产成品入库', self::six => '销售退货', self::seven => '其他入', self::eight => '其他出', ]; public function settleU8Data($data){ if(empty($data['type'])) return [false, 'type类型不能为空']; if(! isset(self::type_all[$data['type']])) return [false, 'type类型错误']; $type = $data['type']; list($status, $msg) = $this->getToken(); // if(! $status) return [false, $msg]; $data['u8_data'] = $msg; if($type == self::one){ list($status, $msg) = $this->purchaseIn($data); }elseif ($type == self::two){ list($status, $msg) = $this->purchaseReturn($data); }elseif ($type == self::three){ list($status, $msg) = $this->materialOut($data); }elseif ($type == self::four){ list($status, $msg) = $this->saleOut($data); }elseif ($type == self::five){ list($status, $msg) = $this->productIn($data); }elseif ($type == self::six){ list($status, $msg) = $this->saleReturn($data); }elseif ($type == self::seven){ list($status, $msg) = $this->otherIn($data); }elseif ($type == self::eight){ list($status, $msg) = $this->otherOut($data); } return [$status, $msg]; } public function getToken(){ $key = "drb_u8_api"; $config = config('wms.drb'); // 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" => $config['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 purchaseIn1($data){ if(empty($data['orderId'])) return [false, '采购到货单ID不能为空']; if(empty($data['orderNo'])) return [false, '采购到货单单号不能为空']; if(empty($data['detail'])) return [false, '表体信息detail不能为空']; //获取采购到货单明细 $service = new U8ThirtyPartyDatabaseServerService(); $details_map = $service->getCGDHDetail1s($data['orderId']); if(empty($details_map)) return [false, '采购到货单明细不存在']; $existingLineNums = array_column($data['detail'], 'lineNum'); $maxLineNum = empty($existingLineNums) ? 0 : max($existingLineNums); $body = []; $seenLineNums = []; // 用于记录已经处理过的原始行号 foreach ($data['detail'] as $key => $value) { if(empty($value['lineNum'])) return [false, '行号不能为空']; if(! is_numeric($value['lineNum'])) return [false, '行号错误']; if(empty($value['materialCode'])) return [false, '存货编码不能为空']; if(empty($value['productDate']) || ! $this->validateProductDate($value['productDate'])) return [false, '生产日期为空或格式错误']; if(empty($value['failureDate']) || ! $this->validateProductDate($value['failureDate'])) return [false, '失效日期为空或格式错误']; if(empty($value['lot'])) return [false, '批号不能为空']; if(empty($value['iQuantity']) || ! is_numeric($value['iQuantity'])) return [false, '存货数量错误']; $currentLineNum = $value['lineNum']; // 2. 判断行号是否重复 if (in_array($currentLineNum, $seenLineNums)) { $maxLineNum++; $currentLineNum = $maxLineNum; $editProp = 'A'; // 或者根据你的需求设为空或其他标志 $o_tmp = $details_map[$value['materialCode']] ?? []; } else { $seenLineNums[] = $currentLineNum; $editProp = 'M'; } // 3. 组织最终数据 $body[] = [ 'ivouchrowno' =>$currentLineNum, 'dPDate' => $value['productDate'], 'dVDate' => $value['failureDate'], 'cBatch' => $value['lot'], 'iQuantity' => $value['iQuantity'], 'editprop' => $editProp, ]; } //调用所需 $host = $data['u8_data']['host']; $token = $data['u8_data']['token']; //采购到货单弃审 $header = ["Authorization: {$token}",'Content-Type:application/json']; $url = $host . "/api/PuArrVouch/UnVerify"; $json = [ "VouchId" => $data['orderId'], ]; $json = json_encode($json); 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']]; //采购到货单编辑并审核 $url = $host . "/api/PuArrVouch/Update"; $json_final[] = [ "Inum" => "PuArrVouch", "data" =>[ "iHead" => [ "cCode" => $data['orderNo'], "IsVerify" => true, "debug" => true, ], "iBody" => $body, ], ]; $json = json_encode($json_final); 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']]; return [true, '']; } /** * 采购到货单拆行/更新处理 */ public function purchaseIn($data) { if (empty($data['orderId'])) return [false, '采购到货单ID不能为空']; if (empty($data['orderNo'])) return [false, '采购到货单单号不能为空']; if (empty($data['detail'])) return [false, '表体信息detail不能为空']; // 1. 获取到货单明细 $service = new U8ThirtyPartyDatabaseServerService(); $result = $service->getCGDHDetails($data['orderId']); if (empty($result)) return [false, '采购到货单明细不存在']; // 取出第一行作为模板,保留 ID, cCode 等主表关联信息 $templateRow = reset($result); $mainId = $templateRow['ID']; // 2. 存货管控校验(批次/保质期) list($status, $msg) = $service->checkInventoryControl(array_column($data['detail'], 'materialCode')); if (!$status) return [false, $msg]; $insertData = []; $rowNo = 1; foreach ($data['detail'] as $value) { if (!isset($result[$value['materialCode']])) continue; $map = $result[$value['materialCode']]; // 获取原始行信息(单价、税率等) // 计算单价 $oldQty = (float)($map['iQuantity'] ?? 0); if ($oldQty <= 0) continue; $unitPrice = (float)$map['iOriSum'] / $oldQty; $unitMoney = (float)$map['iOriMoney'] / $oldQty; $unitLocalSum = (float)$map['iSum'] / $oldQty; $unitLocalMoney = (float)$map['iMoney'] / $oldQty; $newQty = (float)$value['iQuantity']; // 组织新行数据 $newRow = $map; // 清理旧行主键和业务累积状态(关键!) unset($newRow['Autoid']); $newRow['fInspectQuantity'] = 0; // 已报检量清零 $newRow['fValidQuantity'] = 0; // 合格量清零 $newRow['iQuantity'] = $newQty; $newRow['ivouchrowno'] = $rowNo++; // 重新排序行号 // 填充计算后的金额和批次日期 $newRow['iOriMoney'] = round($unitMoney * $newQty, 2); $newRow['iOriSum'] = round($unitPrice * $newQty, 2); $newRow['iOriTaxPrice'] = round(($unitPrice - $unitMoney) * $newQty, 2); $newRow['iMoney'] = round($unitLocalMoney * $newQty, 2); $newRow['iSum'] = round($unitLocalSum * $newQty, 2); $newRow['iTaxPrice'] = round(($unitLocalSum - $unitLocalMoney) * $newQty, 2); $newRow['cBatch'] = $value['lot']; $newRow['dPDate'] = $this->formatAndValidateDate($value['productDate']); $newRow['dVDate'] = $this->formatAndValidateDate($value['failureDate']); $insertData[] = $newRow; } // 3. 执行数据库操作:先删后插 list($status, $msg) = $service->rebuildDhDetails($mainId, $insertData); if (!$status) return [false, $msg]; //查询采购到货单 $order = $service->getCgOrder($data['orderId']); if(empty($order)) return [false, '采购到货单不存在']; //生成来料报检单 $inspect = [ "Inum" => "ArrInspect", "Data" => [ "iHead" => [ // 注意:这里使用的是主表的 ID "CSOURCEID" => $order['ID'], "CDEPCODE" => $order['cDepCode'], "DDATE" => date("Y-m-d"), "CCHECKTYPECODE" => 'ARR', ], "iBody" => [] ] ]; foreach ($order['details'] as $item) { $qty = (float)($item['iQuantity'] ?? 0); if ($qty <= 0) continue; $inspect["Data"]["iBody"][] = [ "SOURCEAUTOID" => $item['Autoid'], "ITESTSTYLE" => 0, "CINVCODE" => $item['cInvCode'], "FCHANGRATE" => (float)($item['iInvExchRate'] ?? 0), "FQUANTITY" => $qty, "CBATCH" => $item['cBatch'], 'DPRODATE' => $item['dPDate'], 'DVDATE' => $item['dVDate'], ]; } // 4. 封装成数组返回 $final_data = [$inspect]; //调用所需 $host = $data['u8_data']['host']; $token = $data['u8_data']['token']; //报检单 $header = ["Authorization: {$token}",'Content-Type:application/json']; $url = $host . "/api/QmArr/ArrInspectAdd"; $json = json_encode($final_data); 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']]; return [true, '']; } public function materialOut($data) { if (empty($data['orderId'])) return [false, '领料申请单ID不能为空']; if (empty($data['orderNo'])) return [false, '领料申请单单号不能为空']; if (empty($data['warehouseCode'])) return [false, '仓库不能为空']; if (empty($data['detail'])) return [false, '表体信息detail不能为空']; // 1. 获取领料申请单明细 $service = new U8ThirtyPartyDatabaseServerService(); $result = $service->getLlSQDetails($data['orderId']); if (empty($result)) return [false, '领料申请单明细不存在']; // 取出第一行作为模板,获取主表 ID $templateRow = reset($result); $mainId = $templateRow['ID']; // 2. 存货管控校验(批次/保质期) list($status, $msg) = $service->checkInventoryControl(array_column($data['detail'], 'materialCode')); if (!$status) return [false, $msg]; $insertData = []; $rowNo = 1; foreach ($data['detail'] as $value) { if (!isset($result[$value['materialCode']])) continue; // 获取原始行(保留生产订单关联 morderdid、仓库 cwhcode 等信息) $map = $result[$value['materialCode']]; $newQty = (float)$value['iQuantity']; // 组织新行数据 $newRow = $map; // 清理主键 unset($newRow['AutoID']); $newRow['iQuantity'] = $newQty; // 申请数量 $newRow['irowno'] = $rowNo++; // 重新排序行号 $newRow['cBatch'] = $value['lot']; // 批号 // 生产日期与失效日期 (U8 领料申请单通常字段名为 dMadeDate 和 dVDate 或 dmadedate) $newRow['dMadeDate'] = !empty($value['productDate']) ? $this->formatAndValidateDate($value['productDate']) : null; $newRow['dVDate'] = !empty($value['failureDate']) ? $this->formatAndValidateDate($value['failureDate']) : null; $insertData[] = $newRow; } // 3. 执行数据库操作:先删后插 list($status, $msg) = $service->rebuildLLDetails($mainId, $insertData); if (!$status) return [false, $msg]; //查询领料申请单 $order = $service->getLLOrder($data['orderId']); if(empty($order)) return [false, '领料单不存在']; //仓库区分出入库类别 if($data['warehouseCode'] == "01"){ $cRdCode = "0201"; }else{ $cRdCode = "0203"; } $materialOut = [ "Inum" => "MaterialOut", "Data" => [ "iHead" => [ "IsVerify" => true, "cWhCode" => $data['warehouseCode'], // 仓库 "cVouchType" => "11", "cRdCode" => $cRdCode, // 出入库类别 "cDepCode" => $order['cDepCode'], // 领用部门 "cSource" => "领料申请单", "cBusCode" => $order['cCode'], // 领料申请单单号 "cBusType" => "领料", "cMemo" => "接口生成", "dDate" => date("Y-m-d"), ], "iBody" => [] ] ]; foreach ($order['details'] as $index => $item) { // 这里的数量取值要对应你 getLLOrder 查出来的字段名,通常是 fQty $qty = $item['iQuantity']; if ($qty <= 0) continue; $materialOut["Data"]["iBody"][] = [ "iRowNo" => $index + 1, "cInvCode" => $item['cInvCode'], "cBatch" => $item['cBatch'], // 批号 "iQuantity" => $qty, // 实际出库数量 "iNQuantity" => $qty, // 实收数量 "iinvexchrate" => (float)($item['iinvexchrate'] ?? 1), "iMaIDs" => $item['AutoID'], "dMadeDate" => $item['dMadeDate'], // 生产日期 "dVDate" => $item['dVDate'], // 失效日期 ]; } // 封装成数组返回 $final_data = [$materialOut]; //调用所需 $host = $data['u8_data']['host']; $token = $data['u8_data']['token']; //材料出库单 $header = ["Authorization: {$token}",'Content-Type:application/json']; $url = $host . "/api/MaterialOut/Add"; $json = json_encode($final_data); 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']]; return [true, '']; } public function materialOut1($data){ if(empty($data['orderId'])) return [false, '领料申请单ID不能为空']; if(empty($data['orderNo'])) return [false, '领料申请单单号不能为空']; if(empty($data['detail'])) return [false, '表体信息detail不能为空']; $body = []; foreach ($data['detail'] as $key => $value){ if(empty($value['lineNum'])) return [false, '行号不能为空']; if(! is_numeric($value['lineNum'])) return [false, '行号错误']; if(empty($value['materialCode'])) return [false, '存货编码不能为空']; if(empty($value['productDate']) || ! $this->validateProductDate($value['productDate'])) return [false, '生产日期为空或格式错误']; if(empty($value['failureDate']) || ! $this->validateProductDate($value['failureDate'])) return [false, '失效日期为空或格式错误']; if(empty($value['lot'])) return [false, '批号不能为空']; $body[] = [ 'ivouchrowno' => $value['lineNum'], 'dPDate' => $value['productDate'], 'dVDate' => $value['failureDate'], 'cBatch' => $value['lot'], 'editprop' => 'M', ]; } //调用所需 $host = $data['u8_data']['host']; $token = $data['u8_data']['token']; //采购到货单弃审 $header = ["Authorization: {$token}",'Content-Type:application/json']; $url = $host . "/api/PuArrVouch/UnVerify"; $json = [ "VouchId" => $data['orderId'], ]; $json = json_encode($json); 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']]; //采购到货单编辑并审核 $url = $host . "/api/PuArrVouch/Update"; $json_final[] = [ "Inum" => "PuArrVouch", "data" =>[ "iHead" => [ "cCode" => $data['orderNo'], "IsVerify" => true, "debug" => true, ], "iBody" => $body, ], ]; $json = json_encode($json_final); 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']]; return [true, '']; } public function purchaseReturn($data){ if(empty($data['orderId'])) return [false, '采购退货单ID不能为空']; // 1. 获取到货单(退货单)及明细 $service = new U8ThirtyPartyDatabaseServerService(); $order = $service->getArrivalVouchById($data['orderId']); if(empty($order)) return [false, '采购退货单数据不存在']; // 获取 Token 相关信息 $host = $data['u8_data']['host'] ?? ""; $token = $data['u8_data']['token'] ?? ""; // 2. 组织单一仓库的红字采购入库单 $iBody = []; foreach ($order['details'] as $index => $item) { // 强制转为负数,生成红字入库单 $qty = abs((float)$item['iQuantity']) * -1; $iBody[] = [ "iRowNo" => $index + 1, "cInvCode" => $item['cInvCode'], "cBatch" => $item['cBatch'] ?? '', "iinvexchrate" => (float)($item['iinvexchrate'] ?? 1), "iQuantity" => $qty, // 负数 "iNQuantity" => $qty, // 负数 "iArrsId" => $item['iArrsId'], "dMadeDate" => $item['dPDate'], "dVDate" => $item['dVDate'], "iTaxRate" => $item['iTaxRate'] ?? 0, "iTaxUnitPrice"=> $item['iOriTaxCost'] ?? 0, ]; } if(empty($iBody)) return [false, '表体明细为空']; $final_data = [ [ "Inum" => "PurchaseIn", "Data" => [ "iHead" => [ "IsVerify" => true, "bIsRedVouch" => true, // 必须为红字 "bCalPrice" => true, // 自动计算金额 "cWhCode" => "01", "cRdCode" => $order['rd_code'], "cDepCode" => $order['depart_code'], "cARVCode" => $order['no'], // 关联来源单号 "cSource" => "采购到货单", // 即使是退货单,参照来源也写这个 "cBusType" => "普通采购", "cMemo" => "接口生成", "dDate" => date("Y-m-d"), "iExchRate"=> 1, ], "iBody" => $iBody ] ] ]; // 3. 调用 API $header = ["Authorization: {$token}", 'Content-Type:application/json']; $url = $host . "/api/PurchaseIn/Add"; $json = json_encode($final_data); 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']]; return [true, '']; } public function productIn($data){ if(empty($data['orderId'])) return [false, '产品报检单ID不能为空']; if(empty($data['orderNo'])) return [false, '产品报检单单号不能为空']; if(empty($data['detail'])) return [false, '表体信息detail不能为空']; // 1. 获取报检单明细 (建议 getBjOrder 返回以 cInvCode 为 key 的数组) $service = new U8ThirtyPartyDatabaseServerService(); $result = $service->getBjOrder($data['orderId']); if (empty($result)) return [false, '报检单明细不存在']; // 取出第一行作为模板,获取主表 ID $templateRow = reset($result); $mainId = $templateRow['ID']; // 2. 存货管控校验(批次/保质期) list($status, $msg) = $service->checkInventoryControl(array_column($data['detail'], 'materialCode')); if (!$status) return [false, $msg]; $insertData = []; $rowNo = 1; foreach ($data['detail'] as $value) { if (!isset($result[$value['materialCode']])) continue; // 获取原始行(保留来源单据关联,如采购到货单行 AutoID 等) $map = $result[$value['materialCode']]; $newQty = (float)$value['iQuantity']; // 组织新行数据 $newRow = $map; // 清理子表主键 unset($newRow['AUTOID']); // --- 核心字段修正 (报检单子表字段通常为大写) --- $newRow['FQUANTITY'] = $newQty; // 报检数量 $newRow['CBATCH'] = $value['lot']; // 批号 // 报检单的日期字段通常是 DPRODATE (生产日期) 和 DVDATE (失效日期) $newRow['DPRODATE'] = !empty($value['productDate']) ? $this->formatAndValidateDate($value['productDate']) : null; $newRow['DVDATE'] = !empty($value['failureDate']) ? $this->formatAndValidateDate($value['failureDate']) : null; $insertData[] = $newRow; } // 3. 执行数据库操作:先删后插 list($status, $msg) = $service->rebuildBjDetails($mainId, $insertData); if (!$status) return [false, $msg]; // $service = new U8ThirtyPartyDatabaseServerService(); // $result = $service->getBjOrder($data['orderId']); // // $tmp = $update = $insert = []; // foreach ($data['detail'] as $key => $value) { // if(empty($value['lineNum'])) return [false, '行号不能为空']; // if(! is_numeric($value['lineNum'])) return [false, '行号错误']; // if(empty($value['materialCode'])) return [false, '存货编码不能为空']; // if(empty($value['productDate'])) return [false, '生产日期不能为空']; // $return = $this->formatAndValidateDate($value['productDate']); // if(! $return) return [false, '生产日期格式错误']; // $productDate = $return; // if(empty($value['failureDate'])) return [false, '失效日期不能为空']; // $return = $this->formatAndValidateDate($value['failureDate']); // if(! $return) return [false, '生产日期格式错误']; // $failureDate= $return; // if(empty($value['lot'])) return [false, '批号不能为空']; // if(empty($value['iQuantity']) || ! is_numeric($value['iQuantity'])) return [false, '存货数量错误']; // // if(isset($result[$value['materialCode']])){ // $map = $result[$value['materialCode']]; // $update_detail = [ // 'CBATCH' => $value['lot'], // 'FQUANTITY' => $value['iQuantity'], // 'DPRODATE' => $productDate, // 'DVDATE' => $failureDate, // ]; // if(! isset($tmp[$value['materialCode']])){ // $update[$map['AUTOID']] = $update_detail; // $tmp[$value['materialCode']] = $value['materialCode']; // }else{ // $map['AUTOID'] = null; // $insert[] = array_merge($map, $update_detail); // } // } // } // // list($status,$msg) = $service->checkInventoryControl(array_values(array_column($data['detail'],'materialCode'))); // if(! $status) return [false, $msg]; // // list($status, $msg) = $service->updateBjOrder($update, $insert); // if(! $status) return [false, $msg]; return [true, '']; } public function saleOut1($data){ if(empty($data['orderId'])) return [false, '销售订单ID不能为空']; if(empty($data['orderNo'])) return [false, '销售订单号不能为空']; if(empty($data['detail'])) return [false, '表体信息detail不能为空']; //获取销售订单信息 $service = new U8ThirtyPartyDatabaseServerService(); $order = $service->getXsOrder($data['orderId']); if(empty($order)) return [false, '销售订单不存在']; $detail_map = []; foreach ($data['detail'] as $key => $value) { if(empty($value['lineNum'])) return [false, '行号不能为空']; if(! is_numeric($value['lineNum'])) return [false, '行号错误']; if(empty($value['materialCode'])) return [false, '存货编码不能为空']; if(empty($value['productDate'])) return [false, '生产日期不能为空']; $return = $this->formatAndValidateDate($value['productDate']); if(! $return) return [false, '生产日期格式错误']; $productDate = $return; if(empty($value['failureDate'])) return [false, '失效日期不能为空']; $return = $this->formatAndValidateDate($value['failureDate']); if(! $return) return [false, '生产日期格式错误']; $failureDate= $return; if(empty($value['lot'])) return [false, '批号不能为空']; if(empty($value['iQuantity']) || ! is_numeric($value['iQuantity'])) return [false, '存货数量错误']; $detail_map[$value['materialCode']][] = [ 'productDate' => $productDate, 'failureDate' => $failureDate, 'lot' => $value['lot'], 'iQuantity' => $value['iQuantity'], ]; } // 2. 组织发货单 (DispatchList) 结构 $tmp = [ "Inum" => "DispatchList", "Data" => [ "iHead" => [ "cBusType" => $order['cBusType'], // 业务类型 "cVouchType" => "05", // 销售发货单类型 "cSTCode" => $order['cSTCode'], // 销售类型 "cDepCode" => $order['cDepCode'], // 部门 "IsVerify" => true, // 是否自动审核 "cMemo" => "接口生成", "dDate" => date("Y-m-d"), "bCalPrice" => true, // 由接口计算价格 "PriceCalKey" => "iTaxUnitPrice", // 以含税单价为准计算 "cSoCode" => $order['cSOCode'], // 销售订单号 "cCusCode" => $order['cCusCode'], // 客户编码 "cinvoicecompany" => $order['cCusCode'], // 开票单位(通常取客户编码) ], "iBody" => [] ] ]; // 3. 遍历销售订单明细组织表体 $key = 0; // 初始化行号计数器 foreach ($order['details'] as $index => $item) { // 销售订单存货可能拆分出多行 $p_t = $detail_map[$item['cInvCode']] ?? []; if(empty($p_t)) continue; foreach ($p_t as $value){ $key++; // 每进入一次内层循环,行号加 1 $tmp["Data"]["iBody"][] = [ "iRowNo" => $key, // 直接使用累加后的 key "cWhCode" => "06", "iQuantity" => $value['iQuantity'], "iSOsID" => $item['iSOsID'], "cBatch" => $value['lot'], "dMDate" => $value['productDate'], "dvDate" => $value['failureDate'], "iTaxUnitPrice" => $item['iTaxUnitPrice'], "iTaxRate" => $item['iTaxRate'], ]; } } // 4. 封装成数组返回 $final_data = [$tmp]; //调用所需 $host = $data['u8_data']['host']; $token = $data['u8_data']['token']; //销售发货单 $header = ["Authorization: {$token}",'Content-Type:application/json']; $url = $host . "/api/Dispatch/Add"; $json = json_encode($final_data); 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']]; $first = $result['data'][0]; $id = $first['VouchId']; // $id = 1000000882; $fhOrder = $service->getFhOrder($id); if(empty($fhOrder)) return [false, '销售发货单获取失败']; // 2. 初始化销售出库单结构 $saleOut = [ "Inum" => "SaleOut", "Data" => [ "iHead" => [ "IsVerify" => true, // 自动审核 "cWhCode" => "06", // 仓库编码 "cRdCode" => "0299", // 出入库类别编码 "cVouchType" => "32", // 单据类型编码 "cMemo" => "接口生成", "cSource" => "发货单", "cSTCode" => $fhOrder['cSTCode'], // 销售类型 "DLCode" => $fhOrder['cDLCode'], // 关联的发货单号 "cDepCode" => $fhOrder['cDepCode'], // 部门 "dDate" => date("Y-m-d"), // 出库日期 ], "iBody" => [] ] ]; // 3. 遍历发货单明细组织表体 foreach ($fhOrder['details'] as $index => $item) { // 计算待出库数量 (总发货数 - 已出库数) $qty = (float)($item['iQuantity'] ?? 0); $outQty = (float)($item['fOutQuantity'] ?? 0); $pendingQty = $qty - $outQty; // 如果该行已全部出库,则跳过(可选逻辑) if ($pendingQty <= 0) continue; $saleOut["Data"]["iBody"][] = [ "iRowNo" => $index + 1, "cInvCode" => $item['cInvCode'] ?? "", "cPosition" => $item['cPosition'] ?? "", // 货位 "cBatch" => $item['cBatch'] ?? "", // 批号 "iinvexchrate" => (float)($item['iExchRate'] ?? 1), // 换算率 "iQuantity" => $pendingQty, // 本次出库数量 "iNQuantity" => $pendingQty, // 对应实收数量 "iDLsID" => $item['iDLsID'], // 核心:发货单子表ID "dMadeDate" => $item['dMDate'], // 生产 "dVDate" => $item['dvDate'], // 失效 "iUnitCost" => (float)($item['iUnitPrice'] ?? 0), // 无税单价 "iPrice" => round((float)($item['iUnitPrice'] ?? 0) * $pendingQty, 2), // 无税金额 ]; } // 4. 封装成数组 $final_data = [$saleOut]; $header = ["Authorization: {$token}",'Content-Type:application/json']; $url = $host . "/api/SaleOut/Add"; $json = json_encode($final_data); 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']]; return [true, '']; } public function saleOut($data){ if(empty($data['orderId'])) return [false, '销售订单ID不能为空']; if(empty($data['orderNo'])) return [false, '销售订单号不能为空']; if(empty($data['detail'])) return [false, '表体信息detail不能为空']; //获取销售订单信息 $service = new U8ThirtyPartyDatabaseServerService(); $order = $service->getXsOrder($data['orderId']); if(empty($order)) return [false, '销售订单不存在']; $orderItemMap = []; foreach ($order['details'] as $detail) { // 这里的 iTaxUnitPrice 是订单里的含税单价 $orderItemMap[$detail['cInvCode']] = [ 'iTaxUnitPrice' => $detail['iTaxUnitPrice'] ?? 0, 'iTaxRate' => $detail['iTaxRate'] ?? 13, 'iUnitPrice' => $detail['iUnitPrice'] ?? 0, ]; } $detail_map = []; foreach ($data['detail'] as $key => $value) { if(empty($value['lineNum'])) return [false, '行号不能为空']; if(! is_numeric($value['lineNum'])) return [false, '行号错误']; if(empty($value['materialCode'])) return [false, '存货编码不能为空']; if(empty($value['productDate'])) return [false, '生产日期不能为空']; $return = $this->formatAndValidateDate($value['productDate']); if(! $return) return [false, '生产日期格式错误']; $productDate = $return; if(empty($value['failureDate'])) return [false, '失效日期不能为空']; $return = $this->formatAndValidateDate($value['failureDate']); if(! $return) return [false, '生产日期格式错误']; $failureDate= $return; if(empty($value['lot'])) return [false, '批号不能为空']; if(empty($value['iQuantity']) || ! is_numeric($value['iQuantity'])) return [false, '存货数量错误']; $detail_map[$value['materialCode']][] = [ 'productDate' => $productDate, 'failureDate' => $failureDate, 'lot' => $value['lot'], 'iQuantity' => $value['iQuantity'], ]; } // 2. 组织发货单 (DispatchList) 结构 $tmp = [ "Inum" => "DispatchList", "Data" => [ "iHead" => [ "cVouchType" => "05", "cSTCode" => $order['cSTCode'] ?? "01", "cDepCode" => $order['cDepCode'] ?? "01", "IsVerify" => true, "cMemo" => "接口生成", "dDate" => date("Y-m-d"), "bCalPrice" => false, "PriceCalKey" => "iSum", "iExchRate" => $order['iExchRate'] ?? 1, "cexch_name" => $order['cexch_name'] ?? "人民币", "cCusCode" => $order['cCusCode'], "iTaxRate" => $order['iTaxRate'] ?? 13, "cinvoicecompany" => $order['cCusCode'], ], "iBody" => [] ] ]; // 3. 组织表体 $rowKey = 0; foreach ($detail_map as $invCode => $items) { // 获取该存货在订单里的价格信息 $priceInfo = $orderItemMap[$invCode]; foreach ($items as $value) { $rowKey++; $quantity = $value['iQuantity']; $unitPrice = $priceInfo['iTaxUnitPrice']; // 直接使用订单里的含税单价 // 计算价税合计:数量 * 含税单价 $sum = round($quantity * $unitPrice, 2); $tmp["Data"]["iBody"][] = [ "iRowNo" => $rowKey, "cInvCode" => $invCode, "iTaxRate" => $priceInfo['iTaxRate'], "cWhCode" => "06", "iQuantity" => $quantity, "iSum" => $sum, // 总金额 "iMoney" => $sum, "cBatch" => $value['lot'], "dMDate" => $value['productDate'], "dvDate" => $value['failureDate'], "iTaxUnitPrice" => $unitPrice, // 含税单价 "iUnitPrice" => $priceInfo['iUnitPrice'], // 原订单无税单价 ]; } } // 4. 封装成数组返回 $final_data = [$tmp]; //调用所需 $host = $data['u8_data']['host']; $token = $data['u8_data']['token']; //销售发货单 $header = ["Authorization: {$token}",'Content-Type:application/json']; $url = $host . "/api/Dispatch/Add"; $json = json_encode($final_data); 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']]; $first = $result['data'][0]; $id = $first['VouchId']; // $id = 1000000882; $fhOrder = $service->getFhOrder($id); if(empty($fhOrder)) return [false, '销售发货单获取失败']; // 2. 初始化销售出库单结构 $saleOut = [ "Inum" => "SaleOut", "Data" => [ "iHead" => [ "IsVerify" => true, // 自动审核 "cWhCode" => "06", // 仓库编码 "cRdCode" => "0299", // 出入库类别编码 "cVouchType" => "32", // 单据类型编码 "cMemo" => "接口生成", "cSource" => "发货单", "cSTCode" => $fhOrder['cSTCode'], // 销售类型 "DLCode" => $fhOrder['cDLCode'], // 关联的发货单号 "cDepCode" => $fhOrder['cDepCode'], // 部门 "dDate" => date("Y-m-d"), // 出库日期 ], "iBody" => [] ] ]; // 3. 遍历发货单明细组织表体 foreach ($fhOrder['details'] as $index => $item) { // 计算待出库数量 (总发货数 - 已出库数) $qty = (float)($item['iQuantity'] ?? 0); $outQty = (float)($item['fOutQuantity'] ?? 0); $pendingQty = $qty - $outQty; // 如果该行已全部出库,则跳过(可选逻辑) if ($pendingQty <= 0) continue; $saleOut["Data"]["iBody"][] = [ "iRowNo" => $index + 1, "cInvCode" => $item['cInvCode'] ?? "", "cPosition" => $item['cPosition'] ?? "", // 货位 "cBatch" => $item['cBatch'] ?? "", // 批号 "iinvexchrate" => (float)($item['iExchRate'] ?? 1), // 换算率 "iQuantity" => $pendingQty, // 本次出库数量 "iNQuantity" => $pendingQty, // 对应实收数量 "iDLsID" => $item['iDLsID'], // 核心:发货单子表ID "dMadeDate" => $item['dMDate'], // 生产 "dVDate" => $item['dvDate'], // 失效 "iUnitCost" => (float)($item['iUnitPrice'] ?? 0), // 无税单价 "iPrice" => round((float)($item['iUnitPrice'] ?? 0) * $pendingQty, 2), // 无税金额 ]; } // 4. 封装成数组 $final_data = [$saleOut]; $header = ["Authorization: {$token}",'Content-Type:application/json']; $url = $host . "/api/SaleOut/Add"; $json = json_encode($final_data); 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']]; return [true, '']; } public function otherIn($data) { // 1. 基础校验 if (empty($data['warehouseCode'])) return [false, '仓库编码不能为空']; if (empty($data['detail'])) return [false, '明细数据不能为空']; $iBody = []; foreach ($data['detail'] as $key => $value) { if(empty($value['lineNum'])) return [false, '行号不能为空']; if(! is_numeric($value['lineNum'])) return [false, '行号错误']; if(empty($value['materialCode'])) return [false, '存货编码不能为空']; if(empty($value['productDate'])) return [false, '生产日期不能为空']; $return = $this->formatAndValidateDate($value['productDate']); if(! $return) return [false, '生产日期格式错误']; $productDate = $return; if(empty($value['failureDate'])) return [false, '失效日期不能为空']; $return = $this->formatAndValidateDate($value['failureDate']); if(! $return) return [false, '生产日期格式错误']; $failureDate= $return; if(empty($value['lot'])) return [false, '批号不能为空']; if(empty($value['iQuantity']) || ! is_numeric($value['iQuantity'])) return [false, '存货数量错误']; $iBody[] = [ "iRowNo" => $key + 1, "cInvCode" => $value['materialCode'], // 存货编码 "cBatch" => $value['lot'] ?? "", // 批号 "iQuantity" => $value['iQuantity'], "iinvexchrate" => 0, "iNum" => 0, "dMadeDate" => $productDate, // 生产日期 "dVDate" => $failureDate, // 失效日期 ]; } // 2. 组织表头 (iHead) $iHead = [ "cWhCode" => $data['warehouseCode'], // 仓库编码 "cRdCode" => "0109", // 收发类别 其他入 "cDepCode" => "", // 部门 "IsVerify" => ! isset($data['IsVerify']) ?? false, // 是否自动审核 "cMemo" => "接口生成", "dDate" => $data['dDate'] ?? date("Y-m-d"), // 单据日期 ]; // 4. 封装成要求的数组结构 $final_data = [ [ "Inum" => "OtherIn", "Data" => [ "iHead" => $iHead, "iBody" => $iBody ] ] ]; // 5. 准备发送请求 $host = $data['u8_data']['host'] ?? ""; $token = $data['u8_data']['token'] ?? ""; $url = $host . "/api/OtherIn/Add"; $header = ["Authorization: {$token}", 'Content-Type:application/json']; // 执行提交 (假设你已经定义了 post_helper1) $json = json_encode($final_data); 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']]; return [true, $result]; } public function otherOut($data) { // 1. 基础校验 if (empty($data['warehouseCode'])) return [false, '仓库编码不能为空']; if (empty($data['detail'])) return [false, '明细数据不能为空']; $iBody = []; foreach ($data['detail'] as $key => $value) { if(empty($value['materialCode'])) return [false, '存货编码不能为空']; // 格式化生产日期 $productDate = null; if(!empty($value['productDate'])){ $productDate = $this->formatAndValidateDate($value['productDate']); if(!$productDate) return [false, '生产日期格式错误']; } // 格式化失效日期 $failureDate = null; if(!empty($value['failureDate'])){ $failureDate = $this->formatAndValidateDate($value['failureDate']); if(!$failureDate) return [false, '失效日期格式错误']; } if(empty($value['iQuantity']) || !is_numeric($value['iQuantity'])) return [false, '存货数量错误']; $iBody[] = [ "iRowNo" => $key + 1, "cInvCode" => $value['materialCode'], // 存货编码 "cBatch" => $value['lot'] ?? "", // 批号 "iQuantity" => $value['iQuantity'], "iinvexchrate" => 0, "dMadeDate" => $productDate, // 生产日期 "dVDate" => $failureDate, // 失效日期 ]; } // 2. 组织表头 (iHead) $iHead = [ "cWhCode" => $data['warehouseCode'], // 仓库编码 "cRdCode" => "0209", // 收发类别:其他出库 "cDepCode" => "", // 部门 "IsVerify" => isset($data['IsVerify']) ?? false, // 是否自动审核 "cMemo" => "接口生成", "dDate" => $data['dDate'] ?? date("Y-m-d"), // 单据日期 ]; // 4. 封装成要求的数组结构 - Inum 改为 OtherOut $final_data = [ [ "Inum" => "OtherOut", "Data" => [ "iHead" => $iHead, "iBody" => $iBody ] ] ]; // 5. 准备发送请求 $host = $data['u8_data']['host'] ?? ""; $token = $data['u8_data']['token'] ?? ""; // 地址改为 OtherOut $url = $host . "/api/OtherOut/Add"; $header = ["Authorization: {$token}", 'Content-Type:application/json']; // 执行提交 $json = json_encode($final_data); 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, "U8错误: " . $result['msg']]; return [true, $result]; } public function saleReturn1($data) { if(empty($data['orderId'])) return [false, '销售退货单ID不能为空']; // 1. 获取销售退货单/订单信息 $service = new U8ThirtyPartyDatabaseServerService(); $order = $service->getXsThOrder($data['orderId']); if(empty($order)) return [false, '销售退货单信息不存在']; $iBody = []; foreach ($order['details'] as $key => $value) { // 确保数量为负数(红字单据要求) $qty = (float)($value['iQuantity'] ?? 0); $redQty = $qty > 0 ? -$qty : $qty; $iBody[] = [ "iRowNo" => $key + 1, "cInvCode" => $value['cInvCode'], // 存货编码 "cPosition" => $value['cPosition'] ?? "", // 货位 "cBatch" => $value['cBatch'] ?? "", // 批号 "iinvexchrate" => (float)($value['iinvexchrate'] ?? 1), "iQuantity" => $redQty, // 红字数量 "iNQuantity" => $redQty, // 实退数量 "iNum" => (float)($value['iNum'] ?? 0), "iNNum" => (float)($value['iNum'] ?? 0), // 核心关联:如果是参照发货单退货,需要 iDLsID (发货单子表Autoid) "iDLsID" => $value['iDLsID'] ?? 0, "dMadeDate" => $value['dMDate'], // 生产日期 "dVDate" => $value['dvDate'], // 失效日期 ]; } // 2. 组织表头 (iHead) $iHead = [ "IsVerify" => $data['IsVerify'] ?? false, // 是否自动审核 "bIsRedVouch" => true, // 核心:必须为 true (红字单据) "cWhCode" => $order['cWhCode'], // 仓库 "cRdCode" => $order['cRdCode'], // 收发类别(如:销售出库/退货) "cMemo" => "接口生成", "cSource" => "发货单", // 来源类型 "cSTCode" => $order['cSTCode'], // 销售类型 "DLCode" => $order['cDLCode'], // 关联的发货单号 "dDate" => date("Y-m-d"), // 单据日期 ]; // 3. 封装成 SaleOut 结构 $final_data = [ [ "Inum" => "SaleOut", "Data" => [ "iHead" => $iHead, "iBody" => $iBody ] ] ]; // 4. 发送请求 $host = $data['u8_data']['host'] ?? ""; $token = $data['u8_data']['token'] ?? ""; $url = $host . "/api/SaleOut/Add"; $header = ["Authorization: {$token}", 'Content-Type:application/json']; $json = json_encode($final_data); 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']]; return [true, $result]; } public function saleReturn($data) { if(empty($data['orderId'])) return [false, '销售退货单ID不能为空']; // 1. 获取销售退货单信息 (DispatchList & DispatchLists) $service = new U8ThirtyPartyDatabaseServerService(); $order = $service->getXsThOrder($data['orderId']); if(empty($order)) return [false, '销售退货单信息不存在']; // --- 核心修改:按仓库分组 --- $groupDetails = []; foreach ($order['details'] as $item) { $whCode = $item['cWhCode'] ?? $order['cWhCode']; // 优先取明细里的仓库,没有则取主表的 $groupDetails[$whCode][] = $item; } $final_data = []; // 2. 遍历每个仓库分组,生成各自的单据 foreach ($groupDetails as $whCode => $details) { $iBody = []; foreach ($details as $index => $value) { $qty = (float)($value['iQuantity'] ?? 0); $redQty = $qty > 0 ? -$qty : $qty; // 强制红字 $iBody[] = [ "iRowNo" => $index + 1, "cInvCode" => $value['cInvCode'], "cPosition" => $value['cPosition'] ?? "", "cBatch" => $value['cBatch'] ?? "", "iinvexchrate" => (float)($value['iinvexchrate'] ?? 1), "iQuantity" => $redQty, "iNQuantity" => $redQty, "iNum" => (float)($value['iNum'] ?? 0), "iNNum" => (float)($value['iNum'] ?? 0), "iDLsID" => $value['iDLsID'] ?? 0, // 关键:关联发货单行ID "dMadeDate" => $value['dMDate'] ?? null, "dVDate" => $value['dvDate'] ?? null, ]; } // 组织该单据的表头 $iHead = [ "IsVerify" => true, "bIsRedVouch" => true, "cWhCode" => $whCode, // 当前分组的仓库 "cRdCode" => "0204", "cMemo" => "接口生成", "cSource" => "发货单", "cSTCode" => $order['cSTCode'], "DLCode" => $order['cDLCode'] ?? "", "dDate" => date("Y-m-d"), ]; // 放入大数组 $final_data[] = [ "Inum" => "SaleOut", "Data" => [ "iHead" => $iHead, "iBody" => $iBody ] ]; } // 3. 发送请求 $host = $data['u8_data']['host'] ?? ""; $token = $data['u8_data']['token'] ?? ""; $url = $host . "/api/SaleOut/Add"; $header = ["Authorization: {$token}", 'Content-Type:application/json']; $json = json_encode($final_data); 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']]; return [true, $result]; } //检验单生成产成品入库单 public function productInByZj1($data){ $record = $data['record']; $payload = $data['payload']; $id = $record['u8_id']; $type = $data['type']; if($type == 1){ $num = $payload['hg_quantity']; }else{ $num = $payload['rb_quantity']; } //获取单据 产品检验单 $service = new U8ThirtyPartyDatabaseServerService(); $order = $service->getJyOrder($id); if(empty($order)) return [false, '产品检验单不存在']; //获取单据 生产订单子表 $product_detail = $service->getScDetails($order['SOURCEID']); if(empty($product_detail)) return [false, '生产订单子表数据不存在']; //u8 token list($status, $msg) = $this->getToken(); if(! $status) return [false, $msg]; $tmp = [ "Inum" => "ProductIn", "Data" => [ "iHead" => [ "IsVerify" => true, "cWhCode" => "06", // 产成品库 "cRdCode" => '0103', // 入库类别 产成品入库 "cDepCode" => $order['CINSPECTDEPCODE'] ?? '', // 部门 "cMemo" => "接口生成", "cSource" => "产品检验单", "cBusType" => "成品入库", "cMPoCode" => $order['SOURCECODE'], // 生产订单号 "cChkCode" => $order['CCHECKCODE'], // 检验单号 "dDate" => date("Y-m-d"), "bIsRedVouch" => false, // 如果是红字入库请设为true "bCalPrice" => true, // 是否由接口计算金额 ], "iBody" => [] ] ]; //一个检验单只有一行 $tmp["Data"]["iBody"][] = [ "iRowNo" => 1, "cInvCode" => $order['cInvCode'] ?? '', "cAssUnit" => $order['CUNITID'] ?? '', "cPosition" => $order['cPosition'] ?? '', "cBatch" => $order['cBatch'] ?? '', "iinvexchrate" => $order['FCHANGRATE'] ?? 0, "iQuantity" => $num, // 数量 "iNQuantity" => $product_detail['Qty'], // 生产订单产品数量 "iMPoIds" => $order['SOURCEAUTOID'] ?? 0, // 生产订单子表ID "dMadeDate" => $order['DPRODATE'] ?? '', // 生产日期 "iMassDate" => $order['IMASSDATE'], // 保质期 "cMassUnit" => $order['CMASSUNIT'], // 保质期单位 "dVDate" => $order['DVDATE'] ?? '', // 失效日期 ]; $final_data = [$tmp]; //调用所需 $host = $msg['host'] ?? ""; $token = $msg['token'] ?? ""; //产成品入库单生成 $header = ["Authorization: {$token}",'Content-Type:application/json']; $url = $host . "/api/ProductIn/Add"; $json = json_encode($final_data); 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']]; return [true, '']; } public function productInByZj($data){ $record = $data['record']; $payload = $data['payload']; $id = $record['u8_id']; $type = $data['type']; // 确定入库数量 $num = ($type == 1) ? $payload['hg_quantity'] : $payload['rb_quantity']; // 1. 获取检验单数据(用于提取物料、批次、仓库等基本信息,即便不参照也需要这些数据) $service = new U8ThirtyPartyDatabaseServerService(); $order = $service->getJyOrder($id); if(empty($order)) return [false, '产品检验单不存在']; // 2. 获取 U8 Token list($status, $msg) = $this->getToken(); if(! $status) return [false, $msg]; // 3. 组织产成品入库单 (不参照模式) $tmp = [ "Inum" => "ProductIn", "Data" => [ "iHead" => [ "IsVerify" => true, // 自动审核 "cWhCode" => $order['CWHCODE'] ?? "06", // 产成品库 "cRdCode" => '0103', // 产成品入库类别编码 (根据U8实际修改,通常为12) "cDepCode" => $order['CINSPECTDEPCODE'], "cMemo" => "接口生成", "cSource" => "库存", // 关键:设为库存即为手动入库 "cBusType" => "成品入库", "dDate" => date("Y-m-d"), "bIsRedVouch" => false, "bCalPrice" => true, ], "iBody" => [ [ "iRowNo" => 1, "cInvCode" => $order['CINVCODE'] ?? '', "cBatch" => $order['CBATCH'] ?? '', "iinvexchrate" => $order['FCHANGRATE'] ?? 0, "iQuantity" => $num, // 入库数量 "iNQuantity" => $num, // 保持一致 "dMadeDate" => $order['DPRODATE'] ?? '', // 生产日期 "dVDate" => $order['DVDATE'] ?? '', // 失效日期 ] ] ] ]; $final_data = [$tmp]; // 4. 调用接口 $host = $msg['host'] ?? ""; $token = $msg['token'] ?? ""; $header = ["Authorization: {$token}", 'Content-Type:application/json']; $url = $host . "/api/ProductIn/Add"; $json = json_encode($final_data); 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']]; return [true, '']; } //检验单生成其他入库单 public function otherInByZj($data){ $record = $data['record']; $payload = $data['payload']; $id = $record['u8_id']; $num = $payload['hg_not_quantity']; //获取单据 检验单 $service = new U8ThirtyPartyDatabaseServerService(); $order = $service->getJyOrder($id); if(empty($order)) return [false, '检验单不存在']; //u8 token list($status, $msg) = $this->getToken(); if(! $status) return [false, $msg]; $tmp = [ "Inum" => "OtherIn", "Data" => [ "iHead" => [ "IsVerify" => true, "cWhCode" => "53", // 成品不良品库 "cRdCode" => '0109', // 入库类别 其他入库 "cDepCode" => '', // 部门 "cMemo" => "接口生成", "dDate" => date("Y-m-d"), ], "iBody" => [] ] ]; //一个检验单只有一行 $tmp["Data"]["iBody"][] = [ "iRowNo" => 1, "cInvCode" => $order['CINVCODE'] ?? '', "cAssUnit" => $order['CUNITID'] ?? '', "cPosition" => $order['cPosition'] ?? '', "cBatch" => $order['CBATCH'] ?? '', "iinvexchrate" => $order['FCHANGRATE'] ?? 0, "iQuantity" => $num, // 数量 "dMadeDate" => $order['DPRODATE'] ?? '', // 生产日期 "dVDate" => $order['DVDATE'] ?? '', ]; $final_data = [$tmp]; //调用所需 $host = $msg['host'] ?? ""; $token = $msg['token'] ?? ""; //产成品入库单生成 $header = ["Authorization: {$token}",'Content-Type:application/json']; $url = $host . "/api/OtherIn/Add"; $json = json_encode($final_data); 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']]; return [true, '']; } //检验单生产采购入库单 public function purchaseInByZj1($data) { $record = $data['record']; $payload = $data['payload']; $id = $record['u8_id']; // 这里的 ID 应该是检验单主表的 ID $type = $data['type']; if($type == 1){ $num = $payload['hg_quantity']; }else{ $num = $payload['rb_quantity']; } // 1. 获取检验单明细 (需要包含来源到货单子表ID: SOURCEAUTOID) $service = new U8ThirtyPartyDatabaseServerService(); $order = $service->getJyOrder2($id); if(empty($order)) return [false, '检验单不存在']; // 2. 获取 U8 Token list($status, $msg) = $this->getToken(); if(! $status) return [false, $msg]; // 3. 组织采购入库单 (PurchaseIn) 结构 $tmp = [ "Inum" => "PurchaseIn", "Data" => [ "iHead" => [ "IsVerify" => true, // 自动审核 "bCalPrice" => true, // 自动计算价格 "cWhCode" => $order['CWHCODE'], // 仓库编码 "cRdCode" => "0101", // 入库类别:原材料采购入库 "cSource" => "来料检验单", // 来源 "cBusType" => "普通采购", "cChkCode" => $order['CCHECKCODE'] ?? '', // 关联检验单号 "cMemo" => "接口生成", "dDate" => date("Y-m-d"), ], "iBody" => [] ] ]; // 4. 组织表体 $tmp["Data"]["iBody"][] = [ "iRowNo" => 1, "cInvCode" => $order['CINVCODE'] ?? '', "cPosition" => $order['cPosition'] ?? '', "cBatch" => $order['CBATCH'], "iinvexchrate" => (float)($order['FCHANGRATE'] ?? 1), "iQuantity" => $num, // 应收数量(入库数量) "iNQuantity" => $num, // 实收数量 "iArrsId" => $order['SOURCEAUTOID'], // 子表id "dMadeDate" => $order['DPRODATE'], // 生产日期 "dVDate" => $order['DVDATE'], // 失效日期 "iUnitCost" => $order['iCost'] ?? 0, "iPrice" => round(($order['iCost'] ?? 0) * $num, 2), "iTaxUnitPrice"=> $order['iOriTaxCost'] ?? 0, "iSum" => round(($order['iOriTaxCost'] ?? 0) * $num, 2), "iTaxRate" => $order['iTaxRate'] ?? 0, ]; $final_data = [$tmp]; // 5. 调用 API $host = $msg['host'] ?? ""; $token = $msg['token'] ?? ""; $header = ["Authorization: {$token}", 'Content-Type:application/json']; $url = $host . "/api/PurchaseIn/Add"; $json = json_encode($final_data); 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']]; return [true, '']; } public function purchaseInByZj($data) { $record = $data['record']; $payload = $data['payload']; $type = $data['type']; // 确定入库数量 $num = ($type == 1) ? $payload['hg_quantity'] : $payload['rb_quantity']; // 1. 获取基础数据 (即使不参照,我们也需要从检验单拿到物料、仓库、供应商等基本信息) $service = new U8ThirtyPartyDatabaseServerService(); $order = $service->getJyOrder2($record['u8_id']); if(empty($order)) return [false, '检验单不存在']; // 2. 获取 U8 Token list($status, $msg) = $this->getToken(); if(! $status) return [false, $msg]; // 3. 组织采购入库单 (不参照模式) $tmp = [ "Inum" => "PurchaseIn", "Data" => [ "iHead" => [ "IsVerify" => true, // 自动审核 "bCalPrice" => true, // 自动计算价格 "PriceCalKey" => "iOriTaxCost", // 以含税单价为准计算 "cWhCode" => "01", // 仓库 "cVenCode" => $order['CVENCODE'], // 供应商(不参照时必填) "cPTCode" => "01", // 采购类型:委外或普通 "cRdCode" => "0101", // 入库类别编码 "cDepCode" => $order['CDEPCODE'] ?? '', // 部门 "cBusType" => "普通采购", "cSource" => "库存", // 设为库存即为不参照模式 "cMemo" => "接口生成", "dDate" => date("Y-m-d"), "cExch_Name" => "人民币", "iExchRate" => 1, ], "iBody" => [ [ "iRowNo" => 1, "cInvCode" => $order['CINVCODE'], "cPosition" => $order['CPOSITION'] ?? '', "cBatch" => $order['CBATCH'] ?? '', "iQuantity" => $num, // 数量 "iNQuantity" => $num, // 实收数量 "iOriTaxCost" => $order['iOriTaxCost'], // 含税单价 "iTaxRate" => $order['iTaxRate'], // 税率 "dMadeDate" => $order['DPRODATE'], // 生产日期 "dVDate" => $order['DVDATE'], // 失效日期 // 注意:不参照时,不要传 iArrsId ] ] ] ]; $final_data = [$tmp]; // 4. 调用 API $host = $msg['host'] ?? ""; $token = $msg['token'] ?? ""; $header = ["Authorization: {$token}", 'Content-Type:application/json']; $url = $host . "/api/PurchaseIn/Add"; $json = json_encode($final_data); 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']]; 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]; } function validateProductDate($dateStr) { // SQL Server 常用的 datetime 格式包含 .v (毫秒) // 注意:这里的格式必须严格对应 " 2025-12-13 00:00:00.000" // 如果字符串开头有空格,格式字符串里也要留空格 $format = 'Y-m-d H:i:s.v'; $d = \DateTime::createFromFormat($format, $dateStr); // 检查是否转换成功,并且转换后的格式与原字符串完全一致 return $d && $d->format($format) === $dateStr; } /** * 校验并格式化日期 * 如果日期合法,返回格式化后的字符串;如果不合法,返回 false */ public function formatAndValidateDate($dateStr) { try { // DateTime 构造函数会自动识别多种日期格式 // trim($dateStr) 用于去除可能存在的首尾空格 $d = new \DateTime(trim($dateStr)); // 统一转换为 SQL Server 喜欢的格式: 2026-03-11 00:00:00.000 return $d->format('Y-m-d H:i:s.v'); } catch (\Exception $e) { // 如果传入的字符串无法解析为日期,会抛出异常 return false; } } }