U8ServerService.php 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939
  1. <?php
  2. namespace App\Service;
  3. use App\Model\DDEmployee;
  4. use App\Model\FieldData;
  5. use App\Model\Inventory;
  6. use App\Model\Record;
  7. use App\Model\Vendor;
  8. use Illuminate\Support\Facades\DB;
  9. class U8ServerService extends Service
  10. {
  11. protected $databaseService;
  12. /**
  13. * @var string|null
  14. */
  15. protected $error;
  16. /**
  17. * U8ServerService constructor.
  18. */
  19. public function __construct($loginUser = [])
  20. {
  21. $service = new U8DatabaseServerService($loginUser);
  22. $this->databaseService = $service->db;
  23. $this->error = $service->error;
  24. }
  25. /**
  26. * 获取错误信息
  27. *
  28. * @return string|null
  29. */
  30. public function getError()
  31. {
  32. return $this->error;
  33. }
  34. public function purchaseOrder($data, $user){
  35. $qx = $user['qx'];
  36. $order_date = $data['order_date'] ?? [];
  37. $order_date = array_filter($order_date);
  38. $order_number = $data['order_number'] ?? "";
  39. $model = $this->databaseService->table('PO_Pomain as a')
  40. ->leftJoin('Vendor as c', 'c.cVenCode', 'a.cVenCode')
  41. ->when(empty($qx), function ($query) use($user){
  42. return $query->where('a.cMaker',$user['username']);
  43. })
  44. ->when(! empty($order_number), function ($query) use($order_number){
  45. return $query->where('a.cPOID','LIKE', '%'.$order_number.'%');
  46. })
  47. ->when(! empty($order_date), function ($query) use($order_date){
  48. $start = date('Y-m-d H:i:s.000', $order_date[0]);
  49. $end = date('Y-m-d H:i:s.000', $order_date[1]);
  50. return $query->whereBetween('a.dPODate', [$start, $end]);
  51. })
  52. ->where(function ($query) {
  53. $query->where('a.iverifystateex', 0)
  54. ->OrwhereNull('a.iverifystateex');
  55. })
  56. ->select('a.cMaker as crt_name', 'a.cBusType as business_type','a.cPOID as order_number',DB::raw("CONVERT(varchar(10), a.dPODate, 120) as order_date"),'c.cVenName as supplier_title')
  57. ->orderBy('a.POID','desc');
  58. $list = $this->limit($model,'',$data);
  59. $list = $this->fillAll($list, 1, $user['login_type']);
  60. return [true , $list];
  61. }
  62. public function purchaseOrderDetail($data, $user){
  63. if(empty($data['order_number'])) return [false, '采购单号不能为空'];
  64. $order = $this->databaseService->table('PO_Pomain as a')
  65. ->leftJoin('Vendor as c', 'c.cVenCode', 'a.cVenCode')
  66. ->where('cPOID', $data['order_number'])
  67. // ->where('a.cMaker',$user['username'])
  68. // ->where('a.iverifystateex',0)
  69. ->select('a.cMaker as crt_name', 'a.cBusType as business_type','a.cPOID as order_number',DB::raw("CONVERT(varchar(10), a.dPODate, 120) as order_date"),'c.cVenName as supplier_title','a.POID as id')
  70. ->first();
  71. if(empty($order)) return [false, '采购单不存在'];
  72. $order = (array) $order;
  73. $detail = $this->databaseService->table('PO_Podetails as a')
  74. ->leftJoin('Inventory as b', 'b.cInvCode', 'a.cInvCode')
  75. ->leftJoin('ComputationUnit as c', 'c.cComunitCode', 'b.cComUnitCode')
  76. ->where('a.POID', $order['id'])
  77. ->select('b.cInvName as product_title','b.cInvCode as product_code','c.cComUnitName as unit_title',DB::raw("LTRIM(STR(a.iQuantity, 20, 2)) as quantity"),DB::raw("LTRIM(STR(a.iSum, 20, 2)) as amount"))
  78. ->get();
  79. // 转为数组的数组
  80. $detail = array_map(function ($item) {
  81. return (array) $item;
  82. }, $detail->toArray());
  83. $order['detail'] = $detail;
  84. return [true, $order];
  85. }
  86. public function purchaseRequisition($data, $user){
  87. $qx = $user['qx'];
  88. $order_date = $data['order_date'] ?? [];
  89. $order_date = array_filter($order_date);
  90. $order_number = $data['order_number'] ?? "";
  91. $model = $this->databaseService->table('PU_AppVouch as a')
  92. ->leftJoin('Person as c', 'c.cPersonCode', 'a.cPersonCode')
  93. ->when(empty($qx), function ($query) use($user){
  94. return $query->where('a.cMaker',$user['username']);
  95. })
  96. ->when(! empty($order_number), function ($query) use($order_number){
  97. return $query->where('a.cCode','LIKE', '%'.$order_number.'%');
  98. })
  99. ->when(! empty($order_date), function ($query) use($order_date){
  100. $start = date('Y-m-d H:i:s.000', $order_date[0]);
  101. $end = date('Y-m-d H:i:s.000', $order_date[1]);
  102. return $query->whereBetween('a.dDate', [$start, $end]);
  103. })
  104. ->where(function ($query) {
  105. $query->where('a.iverifystateex', 0)
  106. ->OrwhereNull('a.iverifystateex');
  107. })
  108. ->select('a.cMaker as crt_name', DB::raw("COALESCE(c.cPersonName, '') as purchase_name"),'a.cBusType as business_type','a.cCode as order_number',DB::raw("CONVERT(varchar(10), a.dDate, 120) as order_date"))
  109. ->orderBy('a.ID','desc');
  110. $list = $this->limit($model,'',$data);
  111. $list = $this->fillAll($list, 2, $user['login_type']);
  112. return [true , $list];
  113. }
  114. public function purchaseRequisitionDetail($data, $user){
  115. if(empty($data['order_number'])) return [false, '采购请购单号不能为空'];
  116. $order = $this->databaseService->table('PU_AppVouch as a')
  117. ->leftJoin('Person as c', 'c.cPersonCode', 'a.cPersonCode')
  118. // ->where('a.cMaker',$user['username'])
  119. // ->where('a.iverifystateex',0)
  120. ->where('cCode', $data['order_number'])
  121. ->select('a.cMaker as crt_name', DB::raw("COALESCE(c.cPersonName, '') as purchase_name"),'a.cBusType as business_type','a.cCode as order_number',DB::raw("CONVERT(varchar(10), a.dDate, 120) as order_date"),'a.ID as id')
  122. ->first();
  123. if(empty($order)) return [false, '采购请购单不存在'];
  124. $order = (array) $order;
  125. $detail = $this->databaseService->table('PU_AppVouchs as a')
  126. ->leftJoin('Inventory as b', 'b.cInvCode', 'a.cInvCode')
  127. ->leftJoin('ComputationUnit as c', 'c.cComunitCode', 'b.cComUnitCode')
  128. ->where('a.ID', $order['id'])
  129. ->select('b.cInvName as product_title','b.cInvCode as product_code','c.cComUnitName as unit_title',DB::raw("CONVERT(varchar(10), a.dRequirDate, 120) as need_arrived_date"),DB::raw("LTRIM(STR(a.fQuantity, 20, 2)) as quantity"))
  130. ->get();
  131. // 转为数组的数组
  132. $detail = array_map(function ($item) {
  133. return (array) $item;
  134. }, $detail->toArray());
  135. $order['detail'] = $detail;
  136. return [true, $order];
  137. }
  138. public function purchaseInOrder($data, $user){
  139. $qx = $user['qx'];
  140. $order_date = $data['order_date'] ?? [];
  141. $order_date = array_filter($order_date);
  142. $order_number = $data['order_number'] ?? "";
  143. $model = $this->databaseService->table('RdRecord01 as a')
  144. ->leftJoin('Vendor as c', 'c.cVenCode', 'a.cVenCode')
  145. ->when(empty($qx), function ($query) use($user){
  146. return $query->where('a.cMaker',$user['username']);
  147. })
  148. ->when(! empty($order_number), function ($query) use($order_number){
  149. return $query->where('a.cCode','LIKE', '%'.$order_number.'%');
  150. })
  151. ->when(! empty($order_date), function ($query) use($order_date){
  152. $start = date('Y-m-d H:i:s.000', $order_date[0]);
  153. $end = date('Y-m-d H:i:s.000', $order_date[1]);
  154. return $query->whereBetween('a.dDate', [$start, $end]);
  155. })
  156. ->whereNull('a.cHandler')
  157. ->select('a.cMaker as crt_name', 'c.cVenName as supplier_title','a.cCode as order_number',DB::raw("CONVERT(varchar(10), a.dDate, 120) as order_date"))
  158. ->orderBy('a.ID','desc');
  159. $list = $this->limit($model,'',$data);
  160. $list = $this->fillAll($list, 3, $user['login_type']);
  161. return [true , $list];
  162. }
  163. public function purchaseInOrderDetail($data, $user){
  164. if(empty($data['order_number'])) return [false, '付款申请单号不能为空'];
  165. $order = $this->databaseService->table('RdRecord01 as a')
  166. ->leftJoin('Vendor as c', 'c.cVenCode', 'a.cVenCode')
  167. // ->where('a.cOperator',$user['username'])
  168. // ->whereNull('a.cCheckMan')
  169. ->where('cCode', $data['order_number'])
  170. ->select('a.cMaker as crt_name', 'c.cVenName as supplier_title','a.cCode as order_number',DB::raw("CONVERT(varchar(10), a.dDate, 120) as order_date"))
  171. ->first();
  172. if(empty($order)) return [false, '采购入库单不存在'];
  173. $order = (array) $order;
  174. $detail = $this->databaseService->table('RdRecords01 as a')
  175. ->leftJoin('Inventory as b', 'b.cInvCode', 'a.cInvCode')
  176. ->leftJoin('ComputationUnit as c', 'c.cComunitCode', 'b.cComUnitCode')
  177. ->where('a.ID', $order['id'])
  178. ->select('b.cInvName as product_title','c.cComUnitName as unit_title')
  179. ->get();
  180. // 转为数组的数组
  181. $detail = array_map(function ($item) {
  182. return (array) $item;
  183. }, $detail->toArray());
  184. // 使用 array_column 提取所有 amount 并求和
  185. $order['total_amount'] = number_format(array_sum(array_column($detail, 'amount')), 2, '.', '');
  186. $order['detail'] = $detail;
  187. return [true, $order];
  188. }
  189. public function inventoryDetail($data, $user){
  190. if(empty($data['order_number'])) return [false, '流水单号不能为空'];
  191. $order = Inventory::where('del_time',0)
  192. ->where('order_number', $data['order_number'])
  193. ->first();
  194. if(empty($order)) return [false, '存货不存在'];
  195. $order = (array) $order;
  196. return [true, $order];
  197. }
  198. public function vendorDetail($data, $user){
  199. if(empty($data['order_number'])) return [false, '流水单号不能为空'];
  200. $order = Vendor::where('del_time',0)
  201. ->where('order_number', $data['order_number'])
  202. ->first();
  203. if(empty($order)) return [false, '供应商不存在'];
  204. $order = (array) $order;
  205. return [true, $order];
  206. }
  207. public function getOrderDetails($data,$user){
  208. $type = $data['type'];
  209. if($type == 1){
  210. // 采购单
  211. [$success, $order] = $this->purchaseOrderDetail($data,$user);
  212. }elseif ($type == 2){
  213. // 请购单
  214. [$success, $order] = $this->purchaseRequisitionDetail($data,$user);
  215. }elseif ($type == 3){
  216. // 采购入库
  217. [$success, $order] = $this->purchaseInOrderDetail($data,$user);
  218. }elseif ($type == 4){
  219. // 存货
  220. [$success, $order] = $this->inventoryDetail($data,$user);
  221. }elseif ($type == 5){
  222. // 供应商
  223. [$success, $order] = $this->vendorDetail($data,$user);
  224. }
  225. return [$success, $order];
  226. }
  227. private function fillAll($list, $type, $login_type){
  228. if(empty($list['data'])) return $list;
  229. $map = Record::where('del_time',0)
  230. ->where('type', $type)
  231. ->where('login_type', $login_type)
  232. ->whereIn('order_number',array_column($list['data'],'order_number'))
  233. ->pluck('id','order_number')
  234. ->toArray();
  235. foreach ($list['data'] as $key => $value){
  236. $is_create = 0;
  237. if(isset($map[$value->order_number])) $is_create = 1;
  238. $list['data'][$key]->is_create = $is_create;
  239. }
  240. return $list;
  241. }
  242. public function stockList($data, $user)
  243. {
  244. try {
  245. $field_list = [];
  246. $employee = DDEmployee::where('userid', $user['userid'])->where('login_type', $user['login_type'])->first();
  247. $qx = $employee['qx'] ?? 0;
  248. if(empty($qx)) {
  249. $field_list = FieldData::where('userid', $user['userid'])
  250. ->where('login_type', $user['login_type'])
  251. ->where('type', FieldData::STATE_ZERO)
  252. ->pluck('key')
  253. ->all();
  254. }
  255. // 1. 构建基础查询:关联现存量表和存货档案表
  256. $query = $this->databaseService->table('CurrentStock as S')
  257. ->select([
  258. 'S.cWhCode', // 仓库编码
  259. 'W.cWhName', // 仓库名称
  260. 'S.cInvCode', // 存货编码
  261. 'I.cInvName', // 存货名称
  262. 'I.cInvStd', // 规格型号
  263. 'I.cInvCCode', // 分类编码
  264. // --- 数量字段对齐你的结构 ---
  265. 'S.iQuantity', // 结存数量 (账面现存量)
  266. 'S.fAvaQuantity', // 可用数量
  267. 'S.fOutQuantity', // 待发货数量 (待出)
  268. 'S.fInQuantity', // 待入库数量 (待入)
  269. 'S.fStopQuantity', // 冻结数量
  270. // --- 批次与日期 ---
  271. 'S.cBatch', // 批号
  272. 'S.dMdate', // 生产日期
  273. 'S.dVDate', // 失效日期
  274. ])
  275. ->join('Inventory as I', 'S.cInvCode', '=', 'I.cInvCode')
  276. ->leftJoin('Warehouse as W', 'S.cWhCode', '=', 'W.cWhCode')
  277. ->leftJoin('InventoryClass as IC', 'I.cInvCCode', '=', 'IC.cInvCCode');
  278. // 2. 过滤条件:存货名称 (支持模糊查询)
  279. if (!empty($data['material_title'])) {
  280. $query->where('I.cInvName', 'like', '%' . $data['material_title'] . '%');
  281. }
  282. // 2. 过滤条件:存货编码 (支持模糊查询)
  283. if (!empty($data['material_code'])) {
  284. $query->where('S.cInvCode', 'like', '%' . $data['material_code'] . '%');
  285. }
  286. // 3. 过滤条件:存货分类 (支持左匹配,即选大类查出所有子类)
  287. if (!empty($data['category_code'])) {
  288. // U8 分类是级次结构,用 like '01%' 可以查出 01 开头的所有子类
  289. $query->where('I.cInvCCode', 'like', $data['category_code'] . '%');
  290. }
  291. // 6. 排序
  292. $query->orderBy('S.cInvCode', 'asc')->orderBy('S.cWhCode', 'asc');
  293. // 7. 调用你定义的分页方法
  294. $columns = ['*'];
  295. $result = $this->limit($query, $columns, $data);
  296. // 注意这里的 &$item,加了 & 符号才能直接修改原数组里的内容
  297. foreach ($result['data'] as &$item) {
  298. $numFields = ['iQuantity', 'fAvaQuantity', 'fOutQuantity', 'fInQuantity', 'fStopQuantity'];
  299. foreach ($numFields as $field) {
  300. if (isset($item->$field)) {
  301. $item->$field = (float)$item->$field;
  302. }
  303. }
  304. $item->dMdate = $item->dMdate ? date('Y-m-d', strtotime($item->dMdate)) : '';
  305. $item->dVDate = $item->dVDate ? date('Y-m-d', strtotime($item->dVDate)) : '';
  306. // 脱敏处理
  307. if (!empty($field_list)) {
  308. foreach ($field_list as $blackField) {
  309. if (isset($item->$blackField)) {
  310. $item->$blackField = '*****';
  311. }
  312. }
  313. }
  314. }
  315. unset($item); // 销毁引用
  316. return [true, $result];
  317. } catch (\Throwable $exception) {
  318. return [false, "查询库存失败: " . $exception->getMessage()];
  319. }
  320. }
  321. public function vendorU8List($data, $user)
  322. {
  323. // 1. 构建基础查询
  324. $query = $this->databaseService->table('Vendor as V')
  325. ->select([
  326. 'V.cVenCode', // 供应商编码
  327. 'V.cVenName', // 供应商名称
  328. 'V.cVenAbbName', // 供应商简称
  329. 'V.cVCCode', // 分类编码
  330. 'VC.cVCName', // 分类名称 (来自 VendorClass)
  331. 'V.cVenAddress', // 地址
  332. 'V.cVenPhone', // 电话
  333. 'V.dVenDevDate', // 发展日期
  334. 'V.cCreatePerson', // 创建人
  335. 'V.bVenTax', // 是否计税
  336. 'V.iId' // 内部ID
  337. ])
  338. // 关联供应商分类表获取分类名称
  339. ->leftJoin('VendorClass as VC', 'V.cVCCode', '=', 'VC.cVCCode');
  340. // 2. 增加搜索逻辑 (可选)
  341. if (!empty($data['keyword'])) {
  342. $keyword = $data['keyword'];
  343. $query->where(function($q) use ($keyword) {
  344. $q->where('V.cVenCode', 'like', "%{$keyword}%")
  345. ->orWhere('V.cVenName', 'like', "%{$keyword}%")
  346. ->orWhere('V.cVenAbbName', 'like', "%{$keyword}%");
  347. });
  348. }
  349. // 3. 排序 (默认按编码排序)
  350. $query->orderBy('V.cVenCode', 'ASC');
  351. // 4. 调用你定义的分页方法
  352. // 注意:limit 方法内部会执行 paginate 并将结果填充到 $data
  353. $columns = ['*']; // select 已经在上面定义过了,这里传 * 即可
  354. $result = $this->limit($query, $columns, $data);
  355. return [true, $result];
  356. }
  357. public function vendorClassTree($data, $user)
  358. {
  359. try {
  360. // 1. 获取所有供应商分类 (表名: VendorClass)
  361. $classes = $this->databaseService->table('VendorClass')
  362. ->select('cVCCode', 'cVCName', 'iVCGrade', 'bVCEnd') // 编码、名称、级次
  363. ->orderBy('cVCCode', 'asc')
  364. ->get();
  365. if ($classes->isEmpty()) {
  366. return [true, []];
  367. }
  368. // 2. 格式化数据,以编码为 Key
  369. $classList = [];
  370. foreach ($classes as $item) {
  371. $classList[$item->cVCCode] = [
  372. 'label' => $item->cVCName,
  373. 'value' => $item->cVCCode, // 前端通常需要 value 字段
  374. 'code' => $item->cVCCode,
  375. 'grade' => $item->iVCGrade,
  376. 'is_end' => $item->bVCEnd,
  377. 'children' => []
  378. ];
  379. }
  380. // 3. 构建引用树
  381. $tree = [];
  382. foreach ($classList as $code => &$node) {
  383. // 获取父级编码
  384. $parentCode = $this->getParentCode($code);
  385. if ($parentCode === null || !isset($classList[$parentCode])) {
  386. // 顶级节点
  387. $tree[] = &$node;
  388. } else {
  389. // 挂载到父节点
  390. $classList[$parentCode]['children'][] = &$node;
  391. }
  392. }
  393. return [true, $tree];
  394. } catch (\Throwable $exception) {
  395. return [false, "获取供应商分类树失败: " . $exception->getMessage()];
  396. }
  397. }
  398. /**
  399. * 辅助函数:根据 U8 编码规则获取父级编码
  400. * U8 的级次通常存储在 GradeDef 表,但通用逻辑是截取末尾
  401. */
  402. private function getParentCode($code)
  403. {
  404. $len = strlen($code);
  405. if ($len <= 2) return null; // 假设第一级是2位,小于等于2位则无父级
  406. // 这里假设级次是 2-2-2-2 (最常见配置)
  407. // 实际生产中,如果级次不固定,建议查询 GradeDef 表
  408. return substr($code, 0, $len - 2);
  409. }
  410. //U8 存货分类树结构
  411. public function inventoryClassTree($data, $user)
  412. {
  413. try {
  414. // 1. 从数据库获取所有存货分类
  415. $classes = $this->databaseService->table('InventoryClass')
  416. ->select('cInvCCode', 'cInvCName', 'iInvCGrade', 'bInvCEnd')
  417. ->orderBy('cInvCCode', 'asc')
  418. ->get();
  419. if ($classes->isEmpty()) return [true, []];
  420. // 2. 将集合转换为数组并以编码作为 Key,方便查找
  421. $classList = [];
  422. foreach ($classes as $item) {
  423. $classList[$item->cInvCCode] = [
  424. 'label' => $item->cInvCName,
  425. 'code' => $item->cInvCCode,
  426. 'grade' => $item->iInvCGrade,
  427. 'is_end' => $item->bInvCEnd,
  428. 'children' => []
  429. ];
  430. }
  431. // 3. 构建树形结构
  432. $tree = [];
  433. foreach ($classList as $code => &$node) {
  434. // 获取当前分类的级次 (U8 逻辑通常根据编码长度判断父级)
  435. // 比如 0101 的父级是 01
  436. $parentCode = $this->getParentCode($code);
  437. if ($parentCode === null || !isset($classList[$parentCode])) {
  438. // 如果没有父级编码,或者父级编码不在列表里,说明是顶级分类
  439. $tree[] = &$node;
  440. } else {
  441. // 将当前节点引用到父节点的 children 数组中
  442. $classList[$parentCode]['children'][] = &$node;
  443. }
  444. }
  445. return [true, $tree];
  446. } catch (\Throwable $exception) {
  447. return [false, "获取分类树失败: " . $exception->getMessage()];
  448. }
  449. }
  450. //U8 计量单位组(带默认主计量单位)
  451. public function getUnitGroups($data, $user)
  452. {
  453. $list = $this->databaseService->select("
  454. SELECT
  455. G.cGroupCode,
  456. G.cGroupName,
  457. G.iGroupType,
  458. U.cComUnitCode,
  459. U.cComUnitName,
  460. U.iNumber
  461. FROM ComputationGroup AS G
  462. OUTER APPLY (
  463. SELECT TOP 1 cComUnitCode, cComUnitName, iNumber
  464. FROM ComputationUnit
  465. WHERE cGroupCode = G.cGroupCode
  466. ORDER BY
  467. bMainUnit DESC, -- 1. 优先主计量
  468. iNumber ASC, -- 2. 序号最小 (若 NULL 会排在最前)
  469. cComUnitCode ASC -- 3. 编码最小
  470. ) AS U
  471. ");
  472. return [true, $list];
  473. }
  474. //U8 计量单位档案
  475. public function getComputationUnitList($data, $user)
  476. {
  477. $list = $this->databaseService->table('ComputationUnit as U')
  478. ->select(
  479. 'U.cComUnitCode', // 单位编码
  480. 'U.cComUnitName', // 单位名称
  481. 'U.cGroupCode', // 所属组编码
  482. 'U.bMainUnit', // 是否主单位
  483. 'U.iNumber' // 排序序号
  484. )
  485. ->orderBy('U.cGroupCode', 'ASC')
  486. ->orderBy('U.iNumber', 'ASC') // 按照你要求的 iNumber 排序
  487. ->get();
  488. return [true, $list];
  489. }
  490. //U8 存货新增到用友
  491. public function inventoryAddToU8($data, $user){
  492. $inventory = Inventory::where('del_time', 0)
  493. ->where('id', $data['id'])
  494. ->first();
  495. if(empty($inventory)) return [false, '存货记录不存在或已被删除'];
  496. $inventory = $inventory->toArray();
  497. if($inventory['status'] != Inventory::STATE_TWO) return [false, '存货记录未审核通过'];
  498. $title = $inventory['title'];
  499. $category_code = $inventory['category_code'];
  500. if(! empty($data['code'])){
  501. //用户传入
  502. $no = $inventory['code'];
  503. $flag_title = "重填";
  504. }else{
  505. //生成编码
  506. list($status, $msg) = $this->generate('inventory','1005');
  507. if(! $status) return [false, $msg];
  508. $no = $msg;
  509. $flag_title = "重试";
  510. }
  511. $inventoryData = [
  512. 'cInvCode' => $no,
  513. 'cInvName' => $title,
  514. 'cInvCCode' => $category_code,
  515. 'cInvStd' => $inventory['size'] ?? null, // 规格型号
  516. 'bSale' => $inventory['bSale'], //内销
  517. 'bExpSale' => $inventory['bExpSale'], //外销
  518. 'bPurchase' => $inventory['bPurchase'], // 采购
  519. 'bSelf' => $inventory['bSelf'], // 自制
  520. 'bComsume' => $inventory['bComsume'], // 生产耗材
  521. 'iGroupType' => $inventory['unit_group_type'], // 计量单位组类别
  522. 'cGroupCode' => $inventory['unit_group_code'], //计量单位组
  523. 'cComUnitCode' => $inventory['unit_code'], // 主计量单位
  524. 'cShopUnit' => $inventory['unit_code'], // 零售计量单位
  525. 'iImpTaxRate' => $inventory['iImpTaxRate'], // 进项税率
  526. 'iTaxRate' => $inventory['iTaxRate'], // 销项税率
  527. 'dSDate' => date("Y-m-d 00:00:00.000"), // 启用日期
  528. 'cEnterprise' => $inventory['vendor_code_title'] ?? null,
  529. 'iSupplyType' => '0', // 供应类型
  530. 'fConvertRate' => '1.0', // 转换因子
  531. 'bInTotalCost' => '1', // 成本累计否
  532. 'cPlanMethod' => 'R',
  533. 'cSRPolicy' => 'PE',
  534. 'bBomMain' => '0', // 允许BOM母件
  535. 'bBomSub' => '0', // 允许BOM子件
  536. 'bProductBill' => '0', // 允许生产订单
  537. 'iPlanDefault' => '1',
  538. 'iAllocatePrintDgt' => '4',
  539. 'bService' => '0',
  540. 'bAccessary' => '0',
  541. 'iInvAdvance' => '0.0',
  542. 'bInvQuality' => '0',
  543. 'bInvBatch' => '0',
  544. 'bInvEntrust' => '0',
  545. 'bInvOverStock' => '0',
  546. 'bFree1' => '0',
  547. 'bFree2' => '0',
  548. 'bInvType' => '0',
  549. 'bFree3' => '0',
  550. 'bFree4' => '0',
  551. 'bFree5' => '0',
  552. 'bFree6' => '0',
  553. 'bFree7' => '0',
  554. 'bFree8' => '0',
  555. 'bFree9' => '0',
  556. 'bFree10' => '0',
  557. 'cCreatePerson' => 'demo',
  558. 'cModifyPerson' => 'demo', // 变更
  559. 'dModifyDate' => date("Y-m-d H:i:s.000"),
  560. 'bFixExch' => '0',
  561. 'bTrack' => '0',
  562. 'bSerial' => '0',
  563. 'bBarCode' => '0',
  564. 'bSolitude' => '0',
  565. 'bSpecialties' => '0',
  566. 'bPropertyCheck' => '0',
  567. 'iRecipeBatch' => '0',
  568. 'bPromotSales' => '0',
  569. 'bPlanInv' => '0',
  570. 'bProxyForeign' => '0',
  571. 'bATOModel' => '0',
  572. 'bCheckItem' => '0',
  573. 'bPTOModel' => '0',
  574. 'bEquipment' => '0',
  575. 'bMPS' => '0',
  576. 'bROP' => '0',
  577. 'bRePlan' => '0',
  578. 'bBillUnite' => '0',
  579. 'bCutMantissa' => '0',
  580. 'bConfigFree1' => '0',
  581. 'bConfigFree2' => '0',
  582. 'bConfigFree3' => '0',
  583. 'bConfigFree4' => '0',
  584. 'bConfigFree5' => '0',
  585. 'bConfigFree6' => '0',
  586. 'bConfigFree7' => '0',
  587. 'bConfigFree8' => '0',
  588. 'bConfigFree9' => '0',
  589. 'bConfigFree10' => '0',
  590. 'bPeriodDT' => '0',
  591. 'bOutInvDT' => '0',
  592. 'bBackInvDT' => '0',
  593. 'bDTWarnInv' => '0',
  594. 'bImportMedicine' => '0',
  595. 'bFirstBusiMedicine' => '0',
  596. 'bForeExpland' => '0',
  597. 'bInvModel' => '0',
  598. 'bKCCutMantissa' => '0',
  599. 'bReceiptByDT' => '0',
  600. 'bCheckBSATP' => '0',
  601. 'bCheckFree1' => '0',
  602. 'bCheckFree2' => '0',
  603. 'bCheckFree3' => '0',
  604. 'bCheckFree4' => '0',
  605. 'bCheckFree5' => '0',
  606. 'bCheckFree6' => '0',
  607. 'bCheckFree7' => '0',
  608. 'bCheckFree8' => '0',
  609. 'bCheckFree9' => '0',
  610. 'bCheckFree10' => '0',
  611. 'iCheckATP' => '0',
  612. 'bPiece' => '0',
  613. 'bSrvItem' => '0',
  614. 'bSrvFittings' => '0',
  615. 'bSpecialOrder' => '0',
  616. 'bTrackSaleBill' => '0',
  617. 'bCheckBatch' => '0',
  618. 'bMngOldpart' => '0',
  619. ];
  620. $inventorySubData = [
  621. 'cInvSubCode' => $no,
  622. 'iSurenessType' => '1',
  623. 'bIsAttachFile' => '0',
  624. 'bInByProCheck' => '1',
  625. 'iRequireTrackStyle' => '0',
  626. 'iExpiratDateCalcu' => '0',
  627. 'iBOMExpandUnitType' => '1',
  628. 'iDrawType' => $inventory['iDrawType'] ?? 0, // 领用方式
  629. 'fInvCIQExch' => $inventory['customs_change_rate'] ?? 1, // 海关换算率
  630. 'bInvKeyPart' => '1',
  631. 'iAcceptEarlyDays' => '999',
  632. 'dInvCreateDatetime' => date("Y-m-d H:i:s.000"),
  633. 'bPUQuota' => '0',
  634. 'bInvROHS' => '0',
  635. 'bPrjMat' => '0',
  636. 'bInvAsset' => '0',
  637. 'bSrvProduct' => '0',
  638. 'iAcceptDelayDays' => '0',
  639. 'bSCkeyProjections' => '0',
  640. 'iSupplyPeriodType' => '1',
  641. 'iAvailabilityDate' => '1',
  642. 'bImport' => '0',
  643. 'bCheckSubitemCost' => '1',
  644. 'fRoundFactor' => '0.0',
  645. 'bConsiderFreeStock' => '1',
  646. 'bSuitRetail' => '0',
  647. 'bFeatureMatch' => '0',
  648. 'bProduceByFeatureAllocate' => '0',
  649. 'bMaintenance' => '0',
  650. 'iMaintenanceCycleUnit' => '0',
  651. 'bCoupon' => '0',
  652. 'bStoreCard' => '0',
  653. 'bProcessProduct' => '0',
  654. 'bProcessMaterial' => '0',
  655. // 所有的价格自由项默认设为 '0'
  656. 'bPurPriceFree1' => '0', 'bPurPriceFree2' => '0', 'bPurPriceFree3' => '0', 'bPurPriceFree4' => '0', 'bPurPriceFree5' => '0',
  657. 'bPurPriceFree6' => '0', 'bPurPriceFree7' => '0', 'bPurPriceFree8' => '0', 'bPurPriceFree9' => '0', 'bPurPriceFree10' => '0',
  658. 'bOMPriceFree1' => '0', 'bOMPriceFree2' => '0', 'bOMPriceFree3' => '0', 'bOMPriceFree4' => '0', 'bOMPriceFree5' => '0',
  659. 'bOMPriceFree6' => '0', 'bOMPriceFree7' => '0', 'bOMPriceFree8' => '0', 'bOMPriceFree9' => '0', 'bOMPriceFree10' => '0',
  660. 'bSalePriceFree1' => '0', 'bSalePriceFree2' => '0', 'bSalePriceFree3' => '0', 'bSalePriceFree4' => '0', 'bSalePriceFree5' => '0',
  661. 'bSalePriceFree6' => '0', 'bSalePriceFree7' => '0', 'bSalePriceFree8' => '0', 'bSalePriceFree9' => '0', 'bSalePriceFree10' => '0',
  662. // 所有的控制自由项默认设为 '0'
  663. 'bControlFreeRange1' => '0', 'bControlFreeRange2' => '0', 'bControlFreeRange3' => '0', 'bControlFreeRange4' => '0', 'bControlFreeRange5' => '0',
  664. 'bControlFreeRange6' => '0', 'bControlFreeRange7' => '0', 'bControlFreeRange8' => '0', 'bControlFreeRange9' => '0', 'bControlFreeRange10' => '0',
  665. // 所有的批次属性默认设为 '0'
  666. 'bBatchProperty1' => '0', 'bBatchProperty2' => '0', 'bBatchProperty3' => '0', 'bBatchProperty4' => '0', 'bBatchProperty5' => '0',
  667. 'bBatchProperty6' => '0', 'bBatchProperty7' => '0', 'bBatchProperty8' => '0', 'bBatchProperty9' => '0', 'bBatchProperty10' => '0',
  668. 'bBondedInv' => '0',
  669. 'bBatchCreate' => '0',
  670. ];
  671. try {
  672. $this->databaseService->beginTransaction();
  673. $exists = $this->databaseService->table('Inventory')
  674. ->where('cInvCode', $inventoryData['cInvCode'])
  675. ->lockForUpdate() // 锁定该行,防止并发冲突
  676. ->exists();
  677. if ($exists) return [false, '存货编码已存在,请' . $flag_title];
  678. $this->databaseService->table('Inventory')->insert($inventoryData);
  679. $this->databaseService->table('Inventory_sub')->insert($inventorySubData);
  680. $this->databaseService->commit();
  681. } catch (\Throwable $exception) {
  682. $this->databaseService->rollBack();
  683. return [false, "创建用友失败: " . $exception->getMessage()];
  684. }
  685. return [true, ''];
  686. }
  687. //U8 供应商新增
  688. public function vendorAddToU8($data, $user){
  689. $vendor = Vendor::where('del_time', 0)
  690. ->where('id', $data['id'])
  691. ->first();
  692. if(empty($vendor)) return [false, '供应商记录不存在或已被删除'];
  693. $vendor = $vendor->toArray();
  694. if($vendor['status'] != Vendor::STATE_TWO) return [false, '供应商记录未审核通过'];
  695. if(! empty($vendor['code'])){
  696. //用户传入
  697. $no = $vendor['code'];
  698. $flag_title = "重填";
  699. }else{
  700. //生成编码
  701. list($status, $msg) = $this->generate('vendor');
  702. if(! $status) return [false, $msg];
  703. $no = $msg;
  704. $flag_title = "重试";
  705. }
  706. $vendorData = [
  707. 'cVenCode' => $no,
  708. 'cVenName' => $vendor['title'],
  709. 'cVenAbbName' => $vendor['easy_title'],
  710. 'cVCCode' => $vendor['category_code'],
  711. 'dVenDevDate' => date("Y-m-d 00:00:00.000"),
  712. 'iVenDisRate' => '0.0',
  713. 'iVenCreLine' => '0.0',
  714. 'iVenCreDate' => '0',
  715. 'cVenHeadCode' => $no,
  716. 'iAPMoney' => '0.0',
  717. 'iLastMoney' => '0.0',
  718. 'iLRMoney' => '0.0',
  719. 'iFrequency' => '0',
  720. 'bVenTax' => '1',
  721. 'cCreatePerson' => 'demo',
  722. 'cModifyPerson' => 'demo',
  723. 'dModifyDate' => date("Y-m-d H:i:s.000"),
  724. 'iGradeABC' => '-1',
  725. 'bLicenceDate' => '0',
  726. 'bBusinessDate' => '0',
  727. 'bProxyDate' => '0',
  728. 'bPassGMP' => '0',
  729. 'bVenCargo' => '1', // 采购
  730. 'bProxyForeign' => '0', // 委外
  731. 'bVenService' => '0', // 服务
  732. 'bVenOverseas' => '0', // 国外
  733. 'cVenExch_name' => '人民币',
  734. 'iVenGSPType' => '0',
  735. 'iVenGSPAuth' => '-1',
  736. 'bVenAccPeriodMng' => '0',
  737. 'bVenHomeBranch' => '0',
  738. 'dVenCreateDatetime' => date("Y-m-d H:i:s.000"),
  739. 'bIsVenAttachFile' => '0',
  740. 'bRetail' => '0',
  741. ];
  742. try {
  743. $this->databaseService->beginTransaction();
  744. $exists = $this->databaseService->table('Vendor')
  745. ->where('cVenCode', $vendorData['cVenCode'])
  746. ->lockForUpdate() // 锁定该行,防止并发冲突
  747. ->exists();
  748. if ($exists) return [false, '供应商编码已存在,请' . $flag_title];
  749. $this->databaseService->table('Vendor')->insert($vendorData);
  750. $this->databaseService->commit();
  751. } catch (\Throwable $exception) {
  752. $this->databaseService->rollBack();
  753. return [false, "创建供应商失败: " . $exception->getMessage()];
  754. }
  755. return [true, ''];
  756. }
  757. // 生成编码
  758. public function generate($type, $classCode = "")
  759. {
  760. try {
  761. // 1. 确定对象映射
  762. $cardNumber = ($type === 'inventory') ? 'inventory' : 'Vendor';
  763. $cardNumber_name = ($type === 'inventory') ? '存货' : '供应商';
  764. $table = ($type === 'inventory') ? 'Inventory' : 'Vendor';
  765. $codeField = ($type === 'inventory') ? 'cInvCode' : 'cVenCode';
  766. // 2. 获取 U8 规则定义
  767. $rule = $this->databaseService->table('VoucherNumber')
  768. ->where('CardNumber', $cardNumber)
  769. ->first();
  770. if (!$rule) return [false, "未找到 {$cardNumber_name} 的规则定义"];
  771. /**
  772. * 3. 动态解析前缀 (Prefix1, Prefix2, Prefix3)
  773. * U8 的规则通常存放在 PrefixRule 或 Prefix 字段中
  774. */
  775. $prefix = "";
  776. for ($i = 1; $i <= 3; $i++) {
  777. $ruleField = "Prefix{$i}Rule";
  778. $valField = "Prefix{$i}";
  779. // 检查规则描述
  780. $ruleDesc = $rule->$ruleField ?? ''; // 例如 "存货分类编码" 或 "GYS"
  781. $staticVal = $rule->$valField ?? '';
  782. if (str_contains($ruleDesc, '分类') || str_contains($staticVal, '分类')) {
  783. // 如果规则提到“分类”,则填入传入的分类编码
  784. $prefix .= $classCode;
  785. } elseif (!empty($ruleDesc)) {
  786. // 如果规则是具体的字符(如 "GYS"),直接拼接
  787. $prefix .= $ruleDesc;
  788. } elseif (!empty($staticVal) && $staticVal !== '手工输入' && $staticVal !== '存货分类编码') {
  789. // 如果静态值不是提示语,则作为前缀
  790. $prefix .= $staticVal;
  791. }
  792. }
  793. // 4. 获取流水号配置 (Glide)
  794. $glideLen = $rule->GlideLen > 0 ? $rule->GlideLen : 4;
  795. $startNum = $rule->iStartNumber ?? 1;
  796. // 5. 查找当前最大编码
  797. $expectedLen = strlen($prefix) + $glideLen;
  798. $lastCode = $this->databaseService->table($table)
  799. ->where($codeField, 'like', $prefix . '%')
  800. ->whereRaw("LEN($codeField) = $expectedLen")
  801. ->orderBy($codeField, 'desc')
  802. ->value($codeField);
  803. // 6. 生成编码
  804. if (!$lastCode) {
  805. // 初始:前缀 + 起始值补零
  806. $finalCode = $prefix . str_pad($startNum, $glideLen, '0', STR_PAD_LEFT);
  807. } else {
  808. // 截取流水号自增
  809. $lastSerial = substr($lastCode, -$glideLen);
  810. $nextSerial = ++$lastSerial;
  811. // 溢出检查
  812. if (strlen($nextSerial) > $glideLen) {
  813. return [false, "流水号已溢出"];
  814. }
  815. $finalCode = $prefix . str_pad($nextSerial, $glideLen, '0', STR_PAD_LEFT);
  816. }
  817. return [true, $finalCode];
  818. } catch (\Throwable $e) {
  819. return [false, "生成失败: " . $e->getMessage()];
  820. }
  821. }
  822. }