U8ThirtyPartyDatabaseServerService.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. <?php
  2. namespace App\Service;
  3. use Illuminate\Support\Facades\DB;
  4. use Illuminate\Support\Facades\Log;
  5. class U8ThirtyPartyDatabaseServerService extends Service
  6. {
  7. protected $connectionName = 'u8_third_sqlserver';
  8. // Service 内部查询
  9. public function getPendingBills($config, $lastId)
  10. {
  11. try {
  12. $mainTable = $config['main'];
  13. $detailTable = $config['detail'];
  14. $mainKey = $config['main_key'];
  15. $foreignKey = $config['key'];
  16. $whereRaw = $config['whereRaw'];
  17. $main_field = $config['main_field'];
  18. $son_field = $config['son_field'];
  19. $limit = $config['limit'];
  20. // 1. 获取主表
  21. $mainRows = DB::connection($this->connectionName)
  22. ->table($mainTable)
  23. ->lock('WITH(NOLOCK)')
  24. ->where($mainKey, '>', $lastId) // 改用 ID
  25. ->whereRaw($whereRaw)
  26. ->select($main_field)
  27. ->orderBy($mainKey, 'ASC') // 按 ID 排序保证分页连续
  28. ->limit($limit)
  29. ->get();
  30. if ($mainRows->isEmpty()) return [true, []];
  31. if (empty($foreignKey) || empty($son_field)) {
  32. $array = $mainRows->map(function ($item) {
  33. return (array) $item;
  34. })->toArray();
  35. return [true, $array];
  36. }
  37. // 2. 批量获取子表
  38. $mainIds = $mainRows->pluck('id')->toArray();
  39. // $details = DB::connection($this->connectionName)
  40. // ->table($detailTable . ' as detail') // 给子表起别名
  41. // ->leftJoin('Inventory as inv', 'detail.cInvCode', '=', 'inv.cInvCode') // 关联存货表
  42. // ->lock('WITH(NOLOCK)')
  43. // ->whereIn('detail.' . $foreignKey, $mainIds) // 注意这里要指定表别名
  44. // ->select($son_field) // 这里会读取你配置里的新字段
  45. // ->get()
  46. // ->groupBy('id');
  47. $details = DB::connection($this->connectionName)
  48. ->table($detailTable. ' as detail')
  49. ->lock('WITH(NOLOCK)')
  50. ->whereIn($foreignKey, $mainIds)
  51. ->select($son_field)
  52. ->addSelect(DB::raw("ROW_NUMBER() OVER(PARTITION BY detail.{$foreignKey} ORDER BY detail.AutoID) as lineNum"))
  53. ->get()
  54. ->groupBy('id');
  55. // 3. 组合
  56. $result = $mainRows->map(function($main) use ($details, $foreignKey) {
  57. $res = (array)$main;
  58. $mainId = $res['id'];
  59. $res['details'] = isset($details[$mainId])
  60. ? $details[$mainId]->map(function($item) {
  61. return (array)$item; // 强制把子表对象转成数组
  62. })->values()->toArray()
  63. : [];
  64. return $res;
  65. })->toArray();
  66. return [true, $result];
  67. } catch (\Throwable $e) {
  68. Log::channel('apiLog')->info('查询失败', [
  69. "error" => $e->getMessage(),
  70. ]);
  71. return [false, $e->getMessage()];
  72. }
  73. }
  74. public function getBillSingle($config, $id)
  75. {
  76. try {
  77. $mainTable = $config['main'];
  78. $detailTable = $config['detail'];
  79. $mainKey = $config['main_key']; // 比如 ID
  80. $foreignKey = $config['key']; // 比如 id (子表关联主表的字段)
  81. $main_field = $config['main_field'];
  82. $son_field = $config['son_field'];
  83. // 1. 获取主表单条记录
  84. $mainRow = DB::connection($this->connectionName)
  85. ->table($mainTable)
  86. ->lock('WITH(NOLOCK)')
  87. ->where($mainKey, $id) // 精确匹配单据 ID
  88. ->select($main_field)
  89. ->first();
  90. if (!$mainRow) {
  91. return [false, "单据 ID:{$id} 未找到数据"];
  92. }
  93. $result = (array)$mainRow;
  94. // 2. 如果不需要子表,直接返回
  95. if (empty($foreignKey) || empty($son_field)) {
  96. return [true, $result];
  97. }
  98. // 3. 获取该单据对应的子表详情
  99. // 注意:U8 子表通常用 id 关联主表的 ID,这里使用配置中的 $foreignKey
  100. $details = DB::connection($this->connectionName)
  101. ->table($detailTable . ' as detail')
  102. ->lock('WITH(NOLOCK)')
  103. ->where($foreignKey, $id)
  104. ->select($son_field)
  105. // 自动生成行号,按 AutoID 排序
  106. // ->addSelect(DB::raw("ROW_NUMBER() OVER(ORDER BY detail.AutoID) as lineNum"))
  107. ->orderBy('detail.AutoID', 'ASC')
  108. ->get();
  109. // 4. 组合数据
  110. $result['details'] = $details->map(function ($item) {
  111. return (array)$item;
  112. })->toArray();
  113. return [true, $result];
  114. } catch (\Throwable $e) {
  115. Log::channel('apiLog')->info('查询单个单据失败', [
  116. "id" => $id,
  117. "error" => $e->getMessage(),
  118. ]);
  119. return [false, $e->getMessage()];
  120. }
  121. }
  122. public function getArrivalVouchById($orderId)
  123. {
  124. try {
  125. // 1. 获取主表 (PU_ArrivalVouch) 并关联 采购类型表 (PurchaseType)
  126. $main = DB::connection($this->connectionName)
  127. ->table('PU_ArrivalVouch as main')
  128. ->leftJoin('PurchaseType as pt', 'main.cPTCode', '=', 'pt.cPTCode') // 关联采购类型表
  129. ->lock('WITH(NOLOCK)')
  130. ->where('main.ID', $orderId)
  131. ->select([
  132. 'main.ID as id',
  133. 'main.cCode as no',
  134. 'main.cVenCode as supply_code',
  135. 'main.cDepCode as depart_code',
  136. 'main.dDate as order_date',
  137. 'main.cBusType as b_type',
  138. 'main.cPTCode as cg_type',
  139. 'pt.cRdCode as rd_code'
  140. ])
  141. ->first();
  142. if (!$main) {
  143. return [false, "到货单 ID:{$orderId} 不存在"];
  144. }
  145. $order = (array)$main;
  146. // 2. 获取子表 (PU_ArrivalVouchs)
  147. $details = DB::connection($this->connectionName)
  148. ->table('PU_ArrivalVouchs as detail')
  149. ->lock('WITH(NOLOCK)')
  150. ->where('ID', $orderId) // 子表里的 ID 关联主表的 ID
  151. ->select([
  152. 'detail.cInvCode',
  153. 'detail.iQuantity',
  154. 'detail.iQuantity as iNNum',
  155. 'detail.iinvexchrate',
  156. 'detail.cBatch',
  157. 'detail.dPDate',
  158. 'detail.dVDate',
  159. 'detail.Autoid as iArrsId',
  160. 'detail.ivouchrowno as iRowNo',
  161. 'detail.iOriTaxCost',
  162. 'detail.iTaxRate',
  163. // 'detail.cordercode',
  164. 'detail.cWhCode',
  165. ])
  166. ->orderBy('detail.ivouchrowno', 'ASC') // 按 U8 原始行号排序
  167. ->get();
  168. // 3. 组合数据并返回
  169. $order['details'] = $details->map(function ($item) {
  170. return (array)$item;
  171. })->toArray();
  172. return [true, $order];
  173. } catch (\Throwable $e) {
  174. \Log::error("获取到货单失败: " . $e->getMessage());
  175. return [false, "数据库查询异常: " . $e->getMessage()];
  176. }
  177. }
  178. /**
  179. * 获取存货档案(带分类名称)
  180. * @param array $config 配置项
  181. * @param mixed $lastId 上次分页的标识(这里用存货编码 cInvCode 或 自动增量标识)
  182. * @return array [bool, items]
  183. */
  184. public function getInventoryData1($config, $lastId = null)
  185. {
  186. try {
  187. $query = DB::connection('u8_third_sqlserver')
  188. ->table('Inventory as main')
  189. ->leftJoin('InventoryClass as sub', 'main.cInvCCode', '=', 'sub.cInvCCode')
  190. ->select([
  191. 'main.cInvCode as product_code',
  192. 'main.cInvName as product_name',
  193. 'main.cInvStd as product_size',
  194. 'main.cInvCCode as product_category_code',
  195. 'sub.cInvCName as product_category_name', // 直接联查分类名
  196. 'main.cComUnitCode as product_unit',
  197. 'main.fOutExcess as out_limit',
  198. 'main.cCurrencyName as common_name',
  199. 'main.fGrossW as grossWeight',
  200. 'main.dModifyDate as upd_time'
  201. ]);
  202. // 分页逻辑
  203. if ($lastId) {
  204. $query->where('main.cInvCode', '>', $lastId);
  205. }
  206. // 基础过滤条件
  207. if (!empty($config['whereRaw'])) {
  208. $query->whereRaw($config['whereRaw']);
  209. }
  210. $items = $query->orderBy('main.cInvCode', 'asc')
  211. ->limit($config['limit'])
  212. ->get();
  213. // 将 Collection 转为数组方便后续处理
  214. $items = json_decode(json_encode($items), true);
  215. return [true, $items];
  216. } catch (\Exception $e) {
  217. Log::channel('apiLog')->error("U8获取存货异常: " . $e->getMessage());
  218. return [false, []];
  219. }
  220. }
  221. public function getInventoryData($config, $lastCode = null)
  222. {
  223. try {
  224. $query = DB::connection('u8_third_sqlserver')
  225. ->table('Inventory as main')
  226. ->leftJoin('InventoryClass as sub', 'main.cInvCCode', '=', 'sub.cInvCCode')
  227. ->leftJoin('ComputationUnit as unit', 'main.cComUnitCode', '=', 'unit.cComUnitCode')
  228. ->select([
  229. 'main.cInvCode as product_code',
  230. 'main.cInvName as product_name',
  231. 'main.cInvStd as product_size',
  232. 'main.cInvCCode as product_category_code',
  233. 'sub.cInvCName as product_category_name', // 直接联查分类名
  234. 'main.cComUnitCode as product_unit',
  235. 'unit.cComUnitName as product_unit_title',
  236. // 'main.fOutExcess as out_limit',
  237. // 'main.cCurrencyName as common_name',
  238. 'main.fGrossW as grossWeight',
  239. // 关键点:将二进制 ufts 转换为 0x... 字符串
  240. DB::raw("master.sys.fn_varbintohexstr(main.pubufts) as ufts_str")
  241. ]);
  242. // 使用 product_code 做分页依据
  243. if ($lastCode) {
  244. $query->where('main.cInvCode', '>', $lastCode);
  245. }
  246. if (!empty($config['whereRaw'])) {
  247. $query->whereRaw($config['whereRaw']);
  248. }
  249. // 必须按编码排序,保证分页不重不漏
  250. $items = $query->orderBy('main.cInvCode', 'asc')
  251. ->limit($config['limit'])
  252. ->get();
  253. return [true, json_decode(json_encode($items), true)];
  254. } catch (\Exception $e) {
  255. Log::channel('apiLog')->error("U8获取存货异常: " . $e->getMessage());
  256. return [false, []];
  257. }
  258. }
  259. }