| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767 |
- <?php
- namespace App\Service;
- use Illuminate\Support\Facades\DB;
- use Illuminate\Support\Facades\Log;
- class U8ThirtyPartyDatabaseServerService extends Service
- {
- protected $connectionName = 'u8_third_sqlserver';
- /**
- * 获取一个具备“自愈”功能的数据库连接
- * 解决 Windows 环境下远程主机强迫关闭连接 (08S02) 的问题
- */
- private function safeDb()
- {
- $conn = DB::connection($this->connectionName);
- try {
- // 心跳探测:执行一个极轻量的查询
- $conn->getPdo()->query('SELECT 1');
- } catch (\Throwable $e) {
- // 捕获到任何连接异常(如 08S02 / 08001)
- Log::channel('apiLog')->warning("U8连接丢失,正在尝试重连...", [
- 'msg' => $e->getMessage()
- ]);
- // 彻底销毁旧连接句柄
- $conn->disconnect();
- DB::purge($this->connectionName);
- // 重新获取新连接
- $conn = DB::connection($this->connectionName);
- }
- return $conn;
- }
- // Service 内部查询
- public function getPendingBills($config, $lastId)
- {
- try {
- $db = $this->safeDb();
- $mainTable = $config['main'];
- $detailTable = $config['detail'];
- $mainKey = $config['main_key'];
- $foreignKey = $config['key'];
- $whereRaw = $config['whereRaw'];
- $main_field = $config['main_field'];
- $son_field = $config['son_field'];
- $limit = $config['limit'];
- // 1. 获取主表
- $mainRows = $db->table($mainTable)
- ->lock('WITH(NOLOCK)')
- ->where($mainKey, '>', $lastId) // 改用 ID
- ->whereRaw($whereRaw)
- ->select($main_field)
- ->orderBy($mainKey, 'ASC') // 按 ID 排序保证分页连续
- ->limit($limit)
- ->get();
- if ($mainRows->isEmpty()) return [true, []];
- if (empty($foreignKey) || empty($son_field)) {
- $array = $mainRows->map(function ($item) {
- return (array) $item;
- })->toArray();
- return [true, $array];
- }
- // 2. 批量获取子表
- $mainIds = $mainRows->pluck('id')->toArray();
- $details = $db->table($detailTable. ' as detail')
- ->lock('WITH(NOLOCK)')
- ->whereIn($foreignKey, $mainIds)
- ->select($son_field)
- ->addSelect(DB::raw("ROW_NUMBER() OVER(PARTITION BY detail.{$foreignKey} ORDER BY detail.AutoID) as lineNum"))
- ->get()
- ->groupBy('id');
- // 3. 组合
- $result = $mainRows->map(function($main) use ($details, $foreignKey) {
- $res = (array)$main;
- $mainId = $res['id'];
- $res['details'] = isset($details[$mainId])
- ? $details[$mainId]->map(function($item) {
- return (array)$item; // 强制把子表对象转成数组
- })->values()->toArray()
- : [];
- return $res;
- })->toArray();
- return [true, $result];
- } catch (\Throwable $e) {
- return [false, $e->getMessage()];
- }
- }
- public function getArrivalVouchById($orderId)
- {
- try {
- $db = $this->safeDb();
- // 1. 获取主表 (PU_ArrivalVouch) 并关联 采购类型表 (PurchaseType)
- $main = $db->table('PU_ArrivalVouch as main')
- ->leftJoin('PurchaseType as pt', 'main.cPTCode', '=', 'pt.cPTCode') // 关联采购类型表
- ->lock('WITH(NOLOCK)')
- ->where('main.ID', $orderId)
- ->select([
- 'main.ID as id',
- 'main.cCode as no',
- 'main.cVenCode as supply_code',
- 'main.cDepCode as depart_code',
- 'main.dDate as order_date',
- 'main.cBusType as b_type',
- 'main.cPTCode as cg_type',
- 'pt.cRdCode as rd_code'
- ])
- ->first();
- if (!$main) return [false, '采购退货单数据不存在'];
- $order = (array)$main;
- // 2. 获取子表 (PU_ArrivalVouchs)
- $details = $db->table('PU_ArrivalVouchs as detail')
- ->lock('WITH(NOLOCK)')
- ->where('ID', $orderId) // 子表里的 ID 关联主表的 ID
- ->select([
- 'detail.cInvCode',
- 'detail.iQuantity',
- 'detail.iQuantity as iNNum',
- 'detail.iinvexchrate',
- 'detail.cBatch',
- 'detail.dPDate',
- 'detail.dVDate',
- 'detail.Autoid as iArrsId',
- 'detail.ivouchrowno as iRowNo',
- 'detail.iOriTaxCost',
- 'detail.iTaxRate',
- // 'detail.cordercode',
- 'detail.cWhCode',
- ])
- ->orderBy('detail.ivouchrowno', 'ASC') // 按 U8 原始行号排序
- ->get();
- // 3. 组合数据并返回
- $order['details'] = $details->map(function ($item) {
- return (array)$item;
- })->toArray();
- return [true, $order];
- }catch (\Throwable $e) {
- return [false, $e->getMessage()];
- }
- }
- public function getInventoryData($config, $lastCode = null)
- {
- try {
- $db = $this->safeDb();
- $query = $db->table('Inventory as main')
- ->leftJoin('InventoryClass as sub', 'main.cInvCCode', '=', 'sub.cInvCCode')
- ->leftJoin('ComputationUnit as unit', 'main.cComUnitCode', '=', 'unit.cComUnitCode')
- ->select([
- 'main.cInvCode as product_code',
- 'main.cInvName as product_name',
- 'main.cInvStd as product_size',
- 'main.cInvCCode as product_category_code',
- 'sub.cInvCName as product_category_name', // 直接联查分类名
- 'main.cComUnitCode as product_unit',
- 'unit.cComUnitName as product_unit_title',
- // 'main.fOutExcess as out_limit',
- // 'main.cCurrencyName as common_name',
- 'main.fGrossW as grossWeight',
- 'main.bFree1 as param_one',
- 'main.bFree2 as param_two',
- 'main.bInvBatch as param_three',
- 'main.bInvQuality as param_four',
- // 关键点:将二进制 ufts 转换为 0x... 字符串
- DB::raw("master.sys.fn_varbintohexstr(main.pubufts) as ufts_str")
- ]);
- // 使用 product_code 做分页依据
- if ($lastCode) {
- $query->where('main.cInvCode', '>', $lastCode);
- }
- if (!empty($config['whereRaw'])) {
- $query->whereRaw($config['whereRaw']);
- }
- // 必须按编码排序,保证分页不重不漏
- $items = $query->orderBy('main.cInvCode', 'asc')
- ->limit($config['limit'])
- ->get();
- return [true, json_decode(json_encode($items), true)];
- } catch (\Throwable $e) {
- return [false, $e->getMessage()];
- }
- }
- //获取单个产品报检单的明细
- public function getBjOrder($id){
- try {
- $db = $this->safeDb();
- $array = $db->table('QMINSPECTVOUCHERS as detail')
- ->lock('WITH(NOLOCK)')
- ->where('detail.ID', $id)
- ->select('detail.*')
- ->get()
- ->map(function ($value) {
- return (array)$value;
- })
- ->keyBy('CINVCODE')
- ->toArray();
- return [true, $array];
- } catch (\Throwable $e) {
- return [false, $e->getMessage()];
- }
- }
- public function getJyOrder($id)
- {
- try {
- $db = $this->safeDb();
- // 1. 获取表头信息 (主表)
- $main = $db->table('QMCHECKVOUCHER')
- ->lock('WITH(NOLOCK)')
- ->where('ID', $id)
- ->first();
- if (!$main) return [false, '检验单不存在'];
- $main = (array)$main;
- return [true, $main];
- } catch (\Throwable $e) {
- return [false, $e->getMessage()];
- }
- }
- public function getScDetails($id)
- {
- try {
- $db = $this->safeDb();
- // 1. 获取表头信息 (主表)
- $main = $db->table('mom_orderdetail')
- ->lock('WITH(NOLOCK)')
- ->where('MoDid', $id)
- ->first();
- if (!$main) {
- return [false, '生成订单明细不存在']; // 或者返回空数组 []
- }
- $main = (array)$main;
- return [true, $main];
- } catch (\Throwable $e) {
- return [false, $e->getMessage()];
- }
- }
- //获取单个销售订单的信息
- public function getXsOrder($id)
- {
- try {
- $db = $this->safeDb();
- // 1. 获取销售订单主表信息 (SO_SOMain)
- $main = $db->table('SO_SOMain')
- ->lock('WITH(NOLOCK)')
- ->where('ID', $id)
- ->first();
- if (!$main) {
- return [false, '销售订单不存在'];
- }
- $main = (array)$main;
- // 2. 获取销售订单子表信息 (SO_SODetails)
- $details = $db->table('SO_SODetails')
- ->lock('WITH(NOLOCK)')
- ->where('ID', $id) // 子表通过 ID 关联主表
- ->get()
- ->map(function ($value) {
- return (array)$value;
- })
- ->toArray();
- // 3. 将子表数据放入 details 键中
- $main['details'] = $details;
- return [true, $main];
- } catch (\Throwable $e) {
- return [false, $e->getMessage()];
- }
- }
- public function getXsThOrder($id)
- {
- try {
- $db = $this->safeDb();
- // 1. 获取销售退货单主表信息 (DispatchList)
- $main = $db->table('DispatchList')
- ->lock('WITH(NOLOCK)')
- ->where('DLID', $id) // 注意:主键叫 DLID
- ->first();
- if (!$main) {
- return [false, '销售退货单不存在'];
- }
- $main = (array)$main;
- // 2. 获取销售退货单子表信息 (DispatchLists)
- $details =$db->table('DispatchLists')
- ->lock('WITH(NOLOCK)')
- ->where('DLID', $id) // 通过 DLID 关联
- ->get()
- ->map(function ($value) {
- return (array)$value;
- })
- ->toArray();
- // 3. 将子表数据放入 details 键中
- $main['details'] = $details;
- return [true, $main];
- } catch (\Throwable $e) {
- return [false, $e->getMessage()];
- }
- }
- public function getFhOrder($id)
- {
- try {
- $db = $this->safeDb();
- // 1. 获取销售发货单主表信息 (DispatchList)
- $main = $db->table('DispatchList')
- ->lock('WITH(NOLOCK)')
- ->where('DLID', $id) // U8发货单主键通常是 DLID
- ->first();
- if (!$main) {
- return [false, '销售发货单不存在'];
- }
- $main = (array)$main;
- // 2. 获取销售发货单子表信息 (DispatchLists)
- $details = $db->table('DispatchLists') // 注意这里是 DispatchLists
- ->lock('WITH(NOLOCK)')
- ->where('DLID', $id) // 子表通过 DLID 关联主表
- ->get()
- ->map(function ($value) {
- return (array)$value;
- })
- ->toArray();
- // 3. 将子表数据放入 details 键中
- $main['details'] = $details;
- return [true, $main];
- } catch (\Throwable $e) {
- return [false, $e->getMessage()];
- }
- }
- public function getCGDHDetails($id)
- {
- try {
- $db = $this->safeDb();
- // 2. 获取采购到货单子表信息 (PU_ArrivalVouchs)
- $details = $db->table('PU_ArrivalVouchs')
- ->lock('WITH(NOLOCK)')
- ->where('ID', $id) // 通过 ID 关联主表
- ->get()
- ->map(function ($value) {
- return (array)$value;
- });
- // 3. 将子表数据以 cInvCode 为 Key 进行组织
- // 注意:如果一张单据里有重复的存货编码,后面的行会覆盖前面的行
- $details = $details->keyBy('cInvCode')->toArray();
- return [true, $details];
- } catch (\Throwable $e) {
- return [false, $e->getMessage()];
- }
- }
- public function getLlSQDetails($id)
- {
- try {
- $db = $this->safeDb();
- // 1. 获取领料申请单子表信息 (MaterialAppVouchs)
- $details = $db->table('MaterialAppVouchs') // 领料申请单子表名
- ->lock('WITH(NOLOCK)')
- ->where('ID', $id) // 通过 ID 关联主表
- ->get()
- ->map(function ($value) {
- return (array)$value;
- });
- // 2. 将子表数据以 cInvCode 为 Key 进行组织
- // 提示:领料申请单中同一存货可能出现在不同行(如:对应不同的生产订单行)
- // 如果确定 cInvCode 唯一,可用 keyBy;如果不唯一,建议直接返回数组或 keyBy('AutoID')
- $details = $details->keyBy('cInvCode')->toArray();
- return [true, $details];
- } catch (\Throwable $e) {
- return [false, $e->getMessage()];
- }
- }
- public function updateDhOrder($update, $insert)
- {
- try {
- // 1. 先通过心跳探测获取一个可靠的连接
- $db = $this->safeDb();
- return $db->transaction(function () use ($update, $insert,$db) {
- // 1. 处理更新部分 (子表: PU_ArrivalVouchs)
- if (!empty($update)) {
- foreach ($update as $autoId => $fields) {
- $db->table('PU_ArrivalVouchs') // 修正为子表名
- ->where('Autoid', $autoId) // U8 习惯大写 A 小写 utoid,但 SQL 不敏感
- ->update($fields);
- }
- }
- // 2. 处理插入部分 (拆分行)
- if (!empty($insert)) {
- $mainId = $insert[0]['ID'] ?? null;
- if ($mainId) {
- // 获取全表最大 Autoid,确保全局唯一
- $maxRowID = $db->table('PU_ArrivalVouchs') // 修正为子表名
- ->max('Autoid') ?? 0;
- foreach ($insert as &$newRow) {
- $maxRowID++;
- $newRow['Autoid'] = $maxRowID;
- }
- // 使用批量插入
- $db->table('PU_ArrivalVouchs')
- ->insert($insert);
- }
- }
- return [true, '']; // 事务成功返回
- });
- } catch (\Throwable $e) {
- // 打印错误堆栈有助于调试
- return [false, "修改采购到货单失败: " . $e->getMessage()];
- }
- }
- public function getCgOrder($id)
- {
- try {
- $db = $this->safeDb();
- // 1. 获取采购到货单主表信息 (PU_ArrivalVouch)
- // 关键:关联键是 ID
- $main = $db->table('PU_ArrivalVouch')
- ->lock('WITH(NOLOCK)')
- ->where('ID', $id)
- ->first();
- if (!$main) {
- return [false, '采购到货单不存在'];
- }
- $main = (array)$main;
- // 2. 获取采购到货单子表信息 (PU_ArrivalVouchs)
- $details = $db->table('PU_ArrivalVouchs')
- ->lock('WITH(NOLOCK)')
- ->where('ID', $id) // 子表通过 ID 关联主表
- ->get()
- ->map(function ($value) {
- return (array)$value;
- })
- ->toArray();
- // 3. 将子表数据放入 details 键中
- $main['details'] = $details;
- return [true, $main];
- } catch (\Throwable $e) {
- return [false, $e->getMessage()];
- }
- }
- public function getJyOrder2($id)
- {
- try {
- $db = $this->safeDb();
- // 关联采购到货单子表 (PU_ArrivalVouchs) 获取金额字段
- $order = $db->table('QMCHECKVOUCHER as qm')
- ->leftJoin('PU_ArrivalVouchs as arr', 'qm.SOURCEAUTOID', '=', 'arr.Autoid')
- ->select(
- 'qm.*',
- 'arr.iCost', // 原币无税单价
- 'arr.iOriTaxCost', // 原币含税单价
- 'arr.iTaxRate' // 税率
- )
- ->where('qm.ID', $id) // 假设这是检验单主表ID
- ->first();
- return [true, $order ? (array)$order : []];
- } catch (\Throwable $e) {
- return [false, $e->getMessage()];
- }
- }
- public function updateLLOrder($update, $insert)
- {
- try {
- $db = $this->safeDb();
- return $db->transaction(function () use ($update, $insert, $db) {
- // 1. 处理更新部分 (子表: MaterialAppVouchs)
- if (!empty($update)) {
- foreach ($update as $autoId => $fields) {
- $db->table('MaterialAppVouchs') // 领料申请单子表
- ->where('autoid', $autoId) // 注意字段名在 U8 里可能是 autoid 或 AutoID
- ->update($fields);
- }
- }
- // 2. 处理插入部分 (拆分行/新增行)
- if (!empty($insert)) {
- // 获取当前领料申请单子表的最大 Autoid,确保手动分配不冲突
- $maxRowID = $db->table('MaterialAppVouchs')
- ->max('autoid') ?? 0;
- foreach ($insert as &$newRow) {
- $maxRowID++;
- // U8 的 autoid 通常必须手动指定
- $newRow['autoid'] = $maxRowID;
- }
- // 使用批量插入
- $db->table('MaterialAppVouchs')
- ->insert($insert);
- }
- return [true, ''];
- });
- } catch (\Throwable $e) {
- // 建议记录详细日志
- return [false, "修改领料申请单失败: " . $e->getMessage()];
- }
- }
- public function getLLOrder($id)
- {
- try {
- $db = $this->safeDb();
- // 关键:关联键是 ID
- $main = $db->table('MaterialAppVouch')
- ->lock('WITH(NOLOCK)')
- ->where('ID', $id)
- ->first();
- if (!$main) {
- return [false, '领料单不存在'];
- }
- $main = (array)$main;
- // 2. 获取采购到货单子表信息 (PU_ArrivalVouchs)
- $details = $db->table('MaterialAppVouchs')
- ->lock('WITH(NOLOCK)')
- ->where('ID', $id) // 子表通过 ID 关联主表
- ->get()
- ->map(function ($value) {
- return (array)$value;
- })
- ->toArray();
- // 3. 将子表数据放入 details 键中
- $main['details'] = $details;
- return [true, $main];
- } catch (\Throwable $e) {
- return [false, $e->getMessage()];
- }
- }
- public function checkInventoryControl($invCodes)
- {
- try {
- $db = $this->safeDb();
- if (empty($invCodes)) {
- return [false, '存货编码为空'];
- }
- // 1. 查询存货档案
- $list = $db->table('Inventory')
- ->whereIn('cInvCode', $invCodes)
- ->select(['cInvCode', 'cInvName', 'bInvBatch', 'bInvQuality'])
- ->get();
- $noBatch = []; // 未开启批次管理的
- $noExpiration = []; // 未开启保质期管理的
- $notFound = array_diff($invCodes, $list->pluck('cInvCode')->toArray()); // 数据库中不存在的
- foreach ($list as $item) {
- // 检查批次管理 (bInvBatch 为 0 表示未开启)
- if (empty($item->bInvBatch)) {
- $noBatch[] = $item->cInvCode . '(' . $item->cInvName . ')';
- }
- // 检查保质期管理 (bInvQuality 为 0 表示未开启)
- if (empty($item->bInvQuality)) {
- $noExpiration[] = $item->cInvCode . '(' . $item->cInvName . ')';
- }
- }
- // 2. 组织提示结果
- $messages = [];
- if (!empty($noBatch)) {
- $messages[] = "【未开启批次管理】: " . implode(', ', $noBatch);
- }
- if (!empty($noExpiration)) {
- $messages[] = "【未开启保质期管理】: " . implode(', ', $noExpiration);
- }
- if (!empty($notFound)) {
- $messages[] = "【档案不存在】: " . implode(', ', $notFound);
- }
- if (empty($messages)) {
- return [true, ''];
- }
- return [false, implode("\n", $messages)];
- } catch (\Throwable $e) {
- return [false, $e->getMessage()];
- }
- }
- public function rebuildDhDetails($mainId, $insertData)
- {
- try {
- $db = $this->safeDb();
- return $db->transaction(function () use ($mainId, $insertData,$db) {
- // 1. 删除旧明细
- $db->table('PU_ArrivalVouchs')
- ->where('ID', $mainId)
- ->delete();
- // 2. 获取新的起始 Autoid
- $maxAutoid = $db->table('PU_ArrivalVouchs')
- ->max('Autoid') ?? 0;
- // 3. 分配新 Autoid 并插入
- foreach ($insertData as &$row) {
- $maxAutoid++;
- $row['Autoid'] = $maxAutoid;
- }
- $db->table('PU_ArrivalVouchs')
- ->insert($insertData);
- return [true, ''];
- });
- } catch (\Throwable $e) {
- return [false, "重建明细失败: " . $e->getMessage()];
- }
- }
- public function rebuildLLDetails($mainId, $insertData)
- {
- try {
- $db = $this->safeDb();
- return $db->transaction(function () use ($mainId, $insertData,$db) {
- // 1. 删除旧明细 (领料申请单子表)
- $db->table('MaterialAppVouchs')
- ->where('ID', $mainId)
- ->delete();
- // 2. 获取新的起始 autoid
- $maxAutoid = $db->table('MaterialAppVouchs')
- ->max('AutoID') ?? 0;
- // 3. 分配新 autoid 并插入
- foreach ($insertData as &$row) {
- $maxAutoid++;
- $row['AutoID'] = $maxAutoid;
- }
- $db->table('MaterialAppVouchs')
- ->insert($insertData);
- return [true, ''];
- });
- } catch (\Throwable $e) {
- return [false, "重组领料申请单失败: " . $e->getMessage()];
- }
- }
- public function rebuildBjDetails($mainId, $insertData)
- {
- try {
- $db = $this->safeDb();
- return $db->transaction(function () use ($mainId, $insertData, $db) {
- // 1. 删除旧明细
- $db->table('QMINSPECTVOUCHERS')
- ->where('ID', $mainId)
- ->delete();
- $maxAutoid = $db->table('QMINSPECTVOUCHERS')
- ->max('Autoid') ?? 0;
- // 过滤掉不可插入的字段,特别是 UFTS
- foreach ($insertData as $key => $row) {
- $maxAutoid++;
- // 彻底清理:移除 UFTS 字段,防止插入报错及 JSON 转换报错
- unset($row['UFTS']);
- $row['Autoid'] = $maxAutoid;
- $insertData[$key] = $row;
- }
- // 4. 批量插入
- $db->table('QMINSPECTVOUCHERS')
- ->insert($insertData);
- return [true, '操作成功'];
- });
- } catch (\Throwable $e) {
- // 这里返回错误信息时,确保不包含二进制内容
- return [false, "重组报检单失败: " . $e->getMessage()];
- }
- }
- }
|