SalaryCalculationService.php 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. <?php
  2. namespace app\service;
  3. use think\Db;
  4. use think\Log;
  5. use think\Exception;
  6. /**
  7. * 工资计算服务类
  8. */
  9. class SalaryCalculationService
  10. {
  11. /**
  12. * 执行工资计算主方法
  13. * @param array $params 计算参数
  14. * @return array 计算结果
  15. */
  16. public function calculateSalary(array $params): array
  17. {
  18. try {
  19. $startDate = $params['start_date'];
  20. $endDate = $params['end_date'];
  21. $attendanceMonth = $params['date'];
  22. // 1. 基础日期校验
  23. $startDateInRange = date('Ym', strtotime($startDate)) === $attendanceMonth;
  24. $endDateInRange = date('Ym', strtotime($endDate)) === $attendanceMonth;
  25. if (!$startDateInRange || !$endDateInRange) {
  26. return [
  27. 'success' => false,
  28. 'message' => '日期参数错误:开始/结束日期超出考勤年月范围'
  29. ];
  30. }
  31. // 2. 法定天数校验
  32. $clockingInDay = Db::name('人事_考勤资料')
  33. ->where('kqzl_ny', $params['date'])
  34. ->field('法定天数')
  35. ->order('UniqId desc')
  36. ->find();
  37. if (empty($clockingInDay)) {
  38. return ['success' => false, 'message' => '未查询到法定天数配置'];
  39. }
  40. $params['days'] = (int)$clockingInDay['法定天数'];
  41. // 3. 删除历史数据
  42. Db::name('绩效工资汇总')->where('sczl_rq', 'between', [$startDate, $endDate])->delete();
  43. // 4. 初始化最终数据容器
  44. $finalData = [];
  45. // ====================== 设备产量计酬数据处理 ======================
  46. $this->handleEquipmentProductionData($params, $finalData);
  47. // ====================== 拆片工序数据处理 ======================
  48. $this->handleChipProcessData($params, $finalData);
  49. // ====================== 手工检验工序数据处理 ======================
  50. $this->handleManualInspectionData($params, $finalData);
  51. // ====================== 包装计件工序数据处理 ======================
  52. $this->handlePackagingPieceworkData($params, $finalData);
  53. // 5. 批量插入数据(核心:补充原代码缺失的插入逻辑)
  54. if (empty($finalData)) {
  55. return ['success' => false, 'message' => '未计算出有效工资数据'];
  56. }
  57. // 补充通用字段
  58. foreach ($finalData as &$item) {
  59. $item['sys_ny'] = $attendanceMonth;
  60. $item['sys_rq'] = date('Y-m-d');
  61. $item['sys_id'] = uniqid();
  62. $item['法定天数'] = $params['days'];
  63. // 补充缺失的工资计算字段
  64. $item['个人计件工资'] = $this->calculatePieceworkWage($item);
  65. $item['个人加班工资'] = $this->calculateOvertimeWage($item, $params);
  66. $item['达标定额'] = $item['日定额'] * $params['days'];
  67. $item['UniqID'] = $this->getNextUniqId();
  68. }
  69. // 6. 批量插入数据库
  70. $insertResult = Db::name('绩效工资汇总')->insertAll($finalData);
  71. if (!$insertResult) {
  72. throw new Exception('批量插入绩效工资数据失败');
  73. }
  74. Log::info('工资计算完成', [
  75. 'start_date' => (string)$startDate,
  76. 'end_date' => (string)$endDate,
  77. 'total_rows' => (int)count($finalData),
  78. 'insert_rows' => (int)$insertResult
  79. ]);
  80. return [
  81. 'success' => true,
  82. 'message' => '工资计算完成',
  83. 'data' => [
  84. 'total_rows' => count($finalData),
  85. 'insert_rows' => $insertResult
  86. ]
  87. ];
  88. } catch (Exception $e) {
  89. Log::error('工资计算服务执行失败', [
  90. 'error' => (string)$e->getMessage(),
  91. 'trace' => (string)$e->getTraceAsString(),
  92. 'params' => json_encode($params, JSON_UNESCAPED_UNICODE) // 序列化复杂参数
  93. ]);
  94. return [
  95. 'success' => false,
  96. 'message' => '计算失败:' . $e->getMessage()
  97. ];
  98. }
  99. }
  100. /**
  101. * 获取绩效工资汇总下一个UniqID
  102. * @return int
  103. */
  104. private function getNextUniqId(): int
  105. {
  106. $lastUniqId = Db::name('绩效工资汇总')->field('UniqID')->order('UniqID desc')->find();
  107. return empty($lastUniqId) ? 1 : (int)$lastUniqId['UniqID'] + 1;
  108. }
  109. /**
  110. * 计算个人计件工资
  111. * @param array $item 单条数据
  112. * @return string
  113. */
  114. private function calculatePieceworkWage(array $item): string
  115. {
  116. if (empty($item['千件工价']) || empty($item['核算产量'])) {
  117. return '0.00';
  118. }
  119. // 千件工价 * 核算产量 / 1000
  120. $wage = (float)$item['千件工价'] * (float)$item['核算产量'] / 1000;
  121. return number_format($wage, 2);
  122. }
  123. /**
  124. * 计算个人加班工资
  125. * @param array $item 单条数据
  126. * @param array $params 全局参数
  127. * @return string
  128. */
  129. private function calculateOvertimeWage(array $item, array $params): string
  130. {
  131. // 示例逻辑:可根据实际业务调整
  132. $overtimeWage = 0.00;
  133. if ($item['工时占比'] > 1) {
  134. // 超出定额部分按1.5倍计算加班
  135. $overtimeRatio = $item['工时占比'] - 1;
  136. $overtimeWage = (float)$item['个人计件工资'] * $overtimeRatio * 1.5;
  137. }
  138. return number_format($overtimeWage, 2);
  139. }
  140. /**
  141. * 处理设备产量计酬数据
  142. * @param array $params 全局参数
  143. * @param array &$finalData 最终数据容器(引用传递)
  144. */
  145. private function handleEquipmentProductionData(array $params, array &$finalData)
  146. {
  147. $where = ['a.sczl_rq' => ['between', [$params['start_date'], $params['end_date']]]];
  148. // 查询印刷印后车间的机台
  149. $sist = ['胶印车间', '凹丝印车间', '印后车间', '检验车间'];
  150. $jtbhs = Db::name('设备_基本资料')
  151. ->where('sys_sbID', '<>', '')
  152. ->where('使用部门', 'in', $sist)
  153. ->column('设备编号');
  154. $fields = "a.sczl_gdbh,a.sczl_yjno,a.sczl_gxh,a.sczl_type as sczl_type,a.sczl_rq,a.sczl_jtbh,a.sczl_工价系数,a.sczl_ms,a.sczl_cl as 班组车头产量,a.sczl_Pgcl,a.sczl_zcfp,
  155. a.sczl_装版工时 as 装版工时,a.sczl_保养工时 as 保养工时,a.sczl_打样工时 as 打样工时,a.sczl_异常工时1 as 异常停机工时,a.sczl_设备运行工时 as 车头产量占用机时,
  156. a.sczl_bh1,a.sczl_bh2,a.sczl_bh3,a.sczl_bh4,a.sczl_bh5,a.sczl_bh6,a.sczl_bh7,a.sczl_bh8,a.sczl_bh9,a.sczl_bh10,
  157. a.sczl_rate1,a.sczl_rate2,a.sczl_rate3,a.sczl_rate4,a.sczl_rate5,a.sczl_rate6,a.sczl_rate7,a.sczl_rate8,a.sczl_rate9,a.sczl_rate10,
  158. a.sczl_废品率系数,a.UniqId,
  159. b.千件工价,b.日定额,b.补产标准,c.工价系数 as 工序难度系数,c.版距,c.印刷方式
  160. ,d1.员工姓名 as name1,d2.员工姓名 as name2,d3.员工姓名 as name3,d4.员工姓名 as name4,d5.员工姓名 as name5,d6.员工姓名 as name6,d7.员工姓名 as name7,d8.员工姓名 as name8
  161. ,d9.员工姓名 as name9,d10.员工姓名 as name10";
  162. $list = Db::name('设备_产量计酬')->alias('a')
  163. ->field($fields)
  164. ->join('dic_lzde b', 'a.sczl_dedh = b.sys_bh', 'LEFT')
  165. ->join('工单_工艺资料 c', 'a.sczl_gdbh = c.Gy0_gdbh AND a.sczl_yjno = c.Gy0_yjno AND a.sczl_gxh = c.Gy0_gxh', 'LEFT')
  166. ->where($where)
  167. ->where('a.sczl_jtbh', 'in', $jtbhs)
  168. ->order('a.sczl_rq')
  169. ->group('UniqId')
  170. ->select();
  171. foreach ($list as $value) {
  172. $num = 1;
  173. $value['班组车头产量'] = $value['班组车头产量'] - $value['sczl_zcfp'];
  174. $gxRate = 1.0000;
  175. // 计件产量计算逻辑
  176. if (substr($value['sczl_jtbh'], 0, 2) == 'JP') {// 检品机
  177. $gxRate = $value['sczl_废品率系数'] ?: 1;
  178. $value['班组车头产量'] = $value['班组车头产量'] * $value['sczl_Pgcl'];
  179. $byThePieceYield = round($value['班组车头产量'] * $gxRate);
  180. } elseif (in_array(substr($value['sczl_jtbh'], 0, 2), ['WY', 'DW']) || in_array(substr($value['sczl_jtbh'], 0, 3), ['YWY', 'YDW'])) {// 凹印机
  181. $gxRate = $this->calculateGxRate($value);
  182. if (str_contains($value['印刷方式'], '张') && $value['版距'] > 0) {
  183. $value['版距'] = $value['版距'] / 1000;
  184. $value['班组车头产量'] = $value['班组车头产量'] * $value['版距'];
  185. }
  186. $byThePieceYield = str_replace(',', '', round($value['班组车头产量'] * floatval($gxRate)));
  187. } else {// 其他设备
  188. if (in_array($value['sczl_jtbh'], ['YSY02#', 'YSY08#', 'YSY10#', 'SY03#'])) {
  189. $num = 1.1;
  190. }
  191. $gxRate = $this->calculateGxRate($value);
  192. $byThePieceYield = round($value['班组车头产量'] * floatval($gxRate) * $num);
  193. }
  194. // 补产产量/班组换算产量
  195. $afterProductionYield = ($value['装版工时'] + $value['保养工时'] + $value['打样工时']) * $value['补产标准'];
  196. // 核算产量
  197. $accountingYield = $byThePieceYield + $afterProductionYield;
  198. // 工时占比
  199. $manHourRate = $value['日定额'] > 0 ? number_format($accountingYield / $value['日定额'], 4) : '0.0000';
  200. // 循环处理10个员工维度
  201. for ($i = 1; $i < 11; $i++) {
  202. $bhKey = 'sczl_bh' . $i;
  203. $xmKey = 'name' . $i;
  204. $rateKey = 'sczl_rate' . $i;
  205. if (!empty($value[$bhKey]) && $value[$bhKey] != '0000') {
  206. $finalData[] = [
  207. 'sczl_gdbh' => $value['sczl_gdbh'],
  208. 'sczl_yjno' => $value['sczl_yjno'],
  209. 'sczl_gxh' => $value['sczl_gxh'],
  210. 'sczl_type' => $value['sczl_type'],
  211. 'sczl_rq' => $value['sczl_rq'],
  212. 'sczl_jtbh' => $value['sczl_jtbh'],
  213. '班组车头产量' => $value['班组车头产量'],
  214. '工价系数' => '0.0000',
  215. '工序难度系数' => $gxRate * $num,
  216. '装版工时' => $value['装版工时'],
  217. '保养工时' => $value['保养工时'],
  218. '打样工时' => $value['打样工时'],
  219. '异常停机工时' => $value['异常停机工时'],
  220. '车头产量占用机时' => $value['车头产量占用机时'],
  221. '日定额' => (int)$value['日定额'],
  222. '千件工价' => $value['千件工价'],
  223. '补产标准' => $value['补产标准'],
  224. '班组换算产量' => $afterProductionYield,
  225. '计时补差额工资' => '0.00',
  226. 'bh' => $value[$bhKey],
  227. 'xm' => $value[$xmKey],
  228. 'Rate' => $value[$rateKey],
  229. 'sczl_ms' => $value['sczl_ms'],
  230. '核算产量' => $accountingYield,
  231. '工时占比' => $manHourRate,
  232. ];
  233. }
  234. }
  235. }
  236. }
  237. /**
  238. * 处理拆片工序数据
  239. * @param array $params 全局参数
  240. * @param array &$finalData 最终数据容器(引用传递)
  241. */
  242. private function handleChipProcessData(array $params, array &$finalData)
  243. {
  244. $where = ['a.sczl_rq' => ['between', [$params['start_date'], $params['end_date']]]];
  245. $list = Db::name('db_sczl')->alias('a')
  246. ->field('a.sczl_gdbh, a.sczl_yjno, a.sczl_gxh, sczl_type, a.sczl_rq, a.sczl_jtbh,
  247. a.sczl_ms, a.sczl_cl as 班组车头产量, a.sczl_fp as sczl_zcfp, a.sczl_装版工时 as 装版工时, a.sczl_保养工时 as 保养工时,
  248. a.sczl_打样工时 as 打样工时, a.sczl_异常停机工时 as 异常停机工时, a.sczl_设备运行工时 as 车头产量占用机时, a.sczl_bh1,
  249. a.sczl_rate1, b.千件工价, b.日定额, b.补产标准,a.sczl_工价系数 as 工序难度系数,a.拆片联拼系数,a.拆片条小盒系数, d.员工姓名')
  250. ->join('dic_lzde b', 'a.sczl_dedh = b.sys_bh', 'left')
  251. ->join('工单_工艺资料 c', 'a.sczl_gdbh = c.Gy0_gdbh AND a.sczl_yjno = c.Gy0_yjno AND a.sczl_gxh = c.Gy0_gxh', 'left')
  252. ->join('人事_基本资料 d', 'a.sczl_bh1 = d.员工编号', 'left')
  253. ->where($where)
  254. ->select();
  255. foreach ($list as $value) {
  256. $num = 1;
  257. $value['班组车头产量'] = ($value['班组车头产量'] - $value['sczl_zcfp']) * $value['拆片联拼系数'] * $value['拆片条小盒系数'];
  258. if (in_array($value['sczl_jtbh'], ['YSY02#', 'YSY08#', 'YSY10#', 'SY03#'])) {
  259. $num = 1.1;
  260. }
  261. $gxRate = $value['工序难度系数'] ?: 1.0000;
  262. $byThePieceYield = round($value['班组车头产量'] * $gxRate * $num);
  263. $afterProductionYield = ($value['装版工时'] + $value['保养工时'] + $value['打样工时']) * $value['补产标准'];
  264. $accountingYield = $byThePieceYield + $afterProductionYield;
  265. $manHourRate = $value['日定额'] > 0 ? number_format($accountingYield / $value['日定额'], 4) : '0.0000';
  266. $finalData[] = [
  267. 'sczl_gdbh' => $value['sczl_gdbh'],
  268. 'sczl_yjno' => $value['sczl_yjno'],
  269. 'sczl_gxh' => $value['sczl_gxh'],
  270. 'sczl_type' => $value['sczl_type'],
  271. 'sczl_rq' => $value['sczl_rq'],
  272. 'sczl_jtbh' => $value['sczl_jtbh'],
  273. '班组车头产量' => $value['班组车头产量'],
  274. '工价系数' => '0.0000',
  275. '工序难度系数' => $gxRate * $num,
  276. '装版工时' => $value['装版工时'],
  277. '保养工时' => $value['保养工时'],
  278. '打样工时' => $value['打样工时'],
  279. '异常停机工时' => $value['异常停机工时'],
  280. '车头产量占用机时' => $value['车头产量占用机时'],
  281. '日定额' => (int)$value['日定额'],
  282. '千件工价' => $value['千件工价'],
  283. '补产标准' => $value['补产标准'],
  284. '班组换算产量' => $afterProductionYield,
  285. '计时补差额工资' => '0.00',
  286. 'bh' => $value['sczl_bh1'],
  287. 'xm' => $value['员工姓名'],
  288. 'Rate' => $value['sczl_rate1'],
  289. 'sczl_ms' => $value['sczl_ms'],
  290. '核算产量' => $accountingYield,
  291. '工时占比' => $manHourRate,
  292. ];
  293. }
  294. }
  295. /**
  296. * 处理手工检验工序数据
  297. * @param array $params 全局参数
  298. * @param array &$finalData 最终数据容器(引用传递)
  299. */
  300. private function handleManualInspectionData(array $params, array &$finalData)
  301. {
  302. $where = ['a.sczl_rq' => ['between', [$params['start_date'], $params['end_date']]]];
  303. $fields = "a.sczl_gdbh,a.sczl_yjgx,sczl_gxmc AS sczl_type,a.sczl_rq,a.sczl_cl AS 班组车头产量,
  304. sczl_废品率系数 AS 工序难度系数,a.sczl_bh0,a.sczl_bh1,a.sczl_bh2,a.sczl_bh3,a.sczl_bh4,a.sczl_bh5,a.sczl_bh6,
  305. a.sczl_bh7,a.sczl_bh8,a.sczl_bh9,a.sczl_bh10,a.sczl_bh11,b.千件工价,b.日定额,b.补产标准,d0.员工姓名 AS name0,
  306. d1.员工姓名 AS name1,d2.员工姓名 AS name2,d3.员工姓名 AS name3,d4.员工姓名 AS name4,d5.员工姓名 AS name5,
  307. d6.员工姓名 AS name6,d7.员工姓名 AS name7,d8.员工姓名 AS name8,d9.员工姓名 AS name9,d10.员工姓名 AS name10,
  308. d10.员工姓名 AS name11,d10.员工姓名 AS name12,a.sczl_cl0,a.sczl_cl1,a.sczl_cl2,a.sczl_cl3,a.sczl_cl4,a.sczl_cl5,a.sczl_cl6,
  309. a.sczl_cl7,a.sczl_cl8,a.sczl_cl9,a.sczl_cl10,a.sczl_cl11,a.sczl_cl12,a.sczl_fp0,a.sczl_fp1,a.sczl_fp2,a.sczl_fp3,
  310. a.sczl_fp4,a.sczl_fp5,a.sczl_fp6,a.sczl_fp7,a.sczl_fp8,a.sczl_fp9,a.sczl_fp10,a.sczl_fp11,a.sczl_fp12";
  311. $list = Db::name('db_手工检验')->alias('a')
  312. ->field($fields)
  313. ->join('dic_lzde b', 'a.sczl_dedh = b.sys_bh', 'LEFT')
  314. ->where($where)
  315. ->select();
  316. // 循环连接人事表(原代码的循环join移到这里,避免SQL语法错误)
  317. for ($i = 0; $i <= 12; $i++) {
  318. $list = $this->joinStaffTable($list, $i);
  319. }
  320. foreach ($list as $value) {
  321. for ($i = 0; $i <= 12; $i++) {
  322. if (!empty($value['sczl_bh' . $i])) {
  323. $value['sczl_yjno'] = (int)substr($value['sczl_yjgx'], 0, 2);
  324. $value['sczl_gxh'] = (int)substr($value['sczl_yjgx'], 3, 2);
  325. $value['班组车头产量'] = $value['sczl_cl' . $i] * $value['sczl_fp' . $i];
  326. $gxRate = $value['工序难度系数'] ?: 1.0000;
  327. $byThePieceYield = round($value['班组车头产量'] * $gxRate);
  328. $accountingYield = $byThePieceYield;
  329. $manHourRate = $value['日定额'] > 0 ? round($accountingYield / $value['日定额'], 4) : '0.0000';
  330. $finalData[] = [
  331. 'sczl_gdbh' => $value['sczl_gdbh'],
  332. 'sczl_yjno' => $value['sczl_yjno'],
  333. 'sczl_gxh' => $value['sczl_gxh'],
  334. 'sczl_type' => $value['sczl_type'],
  335. 'sczl_rq' => $value['sczl_rq'],
  336. 'sczl_jtbh' => '',
  337. '班组车头产量' => $value['班组车头产量'],
  338. '工价系数' => '0.0000',
  339. '工序难度系数' => $gxRate,
  340. '装版工时' => '0.00',
  341. '保养工时' => '0.00',
  342. '打样工时' => '0.00',
  343. '异常停机工时' => '0.00',
  344. '车头产量占用机时' => '0.00',
  345. '日定额' => (int)$value['日定额'],
  346. '千件工价' => $value['千件工价'],
  347. '补产标准' => $value['补产标准'],
  348. '班组换算产量' => '0',
  349. '计时补差额工资' => '0.00',
  350. 'bh' => $value['sczl_bh' . $i],
  351. 'xm' => $value['name' . $i],
  352. 'Rate' => '1.0000',
  353. 'sczl_ms' => '0.00',
  354. '核算产量' => $accountingYield,
  355. '工时占比' => $manHourRate,
  356. ];
  357. }
  358. }
  359. }
  360. }
  361. /**
  362. * 处理包装计件工序数据(补充原代码截断部分)
  363. * @param array $params 全局参数
  364. * @param array &$finalData 最终数据容器(引用传递)
  365. */
  366. private function handlePackagingPieceworkData(array $params, array &$finalData)
  367. {
  368. $where = ['a.sczl_rq' => ['between', [$params['start_date'], $params['end_date']]]];
  369. $list = Db::name('db_包装计件')->alias('a')
  370. ->field('a.sczl_gdbh1, a.sczl_gdbh2, a.sczl_gdbh3, a.sczl_gdbh4, a.sczl_gdbh5, a.sczl_gdbh6,
  371. a.sczl_yjGx1, a.sczl_yjGx2, a.sczl_yjGx3, a.sczl_yjGx4, a.sczl_yjGx5, a.sczl_yjGx6,
  372. rtrim(a.sczl_gxmc1) as gxmc1,rtrim(a.sczl_gxmc2) as gxmc2,rtrim(a.sczl_gxmc3) as gxmc3,rtrim(a.sczl_gxmc4) as gxmc4,rtrim(a.sczl_gxmc5) as gxmc5,rtrim(a.sczl_gxmc6) as gxmc6,
  373. a.sczl_cl1, a.sczl_cl2, a.sczl_cl3, a.sczl_cl4, a.sczl_cl5, a.sczl_cl6,
  374. a.sczl_返工产量1, a.sczl_返工产量2, a.sczl_返工产量3, a.sczl_返工产量4, a.sczl_返工产量5, a.sczl_返工产量6,
  375. a.sczl_Jtbh1,a.sczl_Jtbh2,a.sczl_Jtbh3,a.sczl_Jtbh4,a.sczl_Jtbh5,a.sczl_Jtbh6,
  376. a.sczl_dedh1,a.sczl_dedh2,a.sczl_dedh3,a.sczl_dedh4,a.sczl_dedh5,a.sczl_dedh6')
  377. ->where($where)
  378. ->select();
  379. // 循环处理6个维度的包装数据
  380. for ($i = 1; $i <= 6; $i++) {
  381. foreach ($list as $value) {
  382. $gdbhKey = 'sczl_gdbh' . $i;
  383. $yjGxKey = 'sczl_yjGx' . $i;
  384. $gxmcKey = 'gxmc' . $i;
  385. $clKey = 'sczl_cl' . $i;
  386. $reworkKey = 'sczl_返工产量' . $i;
  387. $jtbhKey = 'sczl_Jtbh' . $i;
  388. $dedhKey = 'sczl_dedh' . $i;
  389. if (empty($value[$gdbhKey])) continue;
  390. // 查询千件工价等配置
  391. $lzdeData = Db::name('dic_lzde')->where('sys_bh', $value[$dedhKey])->find();
  392. $dailyQuota = $lzdeData['日定额'] ?? 0;
  393. $piecePrice = $lzdeData['千件工价'] ?? 0;
  394. $supplementStandard = $lzdeData['补产标准'] ?? 0;
  395. // 产量计算(含返工产量)
  396. $totalYield = $value[$clKey] + $value[$reworkKey];
  397. $accountingYield = $totalYield;
  398. $manHourRate = $dailyQuota > 0 ? number_format($accountingYield / $dailyQuota, 4) : '0.0000';
  399. $finalData[] = [
  400. 'sczl_gdbh' => $value[$gdbhKey],
  401. 'sczl_yjno' => (int)substr($value[$yjGxKey], 0, 2) ?: 0,
  402. 'sczl_gxh' => (int)substr($value[$yjGxKey], 3, 2) ?: 0,
  403. 'sczl_type' => $value[$gxmcKey],
  404. 'sczl_rq' => $params['start_date'], // 可根据实际业务调整
  405. 'sczl_jtbh' => $value[$jtbhKey] ?? '',
  406. '班组车头产量' => $totalYield,
  407. '工价系数' => '0.0000',
  408. '工序难度系数' => 1.0000,
  409. '装版工时' => '0.00',
  410. '保养工时' => '0.00',
  411. '打样工时' => '0.00',
  412. '异常停机工时' => '0.00',
  413. '车头产量占用机时' => '0.00',
  414. '日定额' => (int)$dailyQuota,
  415. '千件工价' => $piecePrice,
  416. '补产标准' => $supplementStandard,
  417. '班组换算产量' => '0',
  418. '计时补差额工资' => '0.00',
  419. 'bh' => '', // 包装工序员工编号需根据实际业务补充
  420. 'xm' => '', // 包装工序员工姓名需根据实际业务补充
  421. 'Rate' => '1.0000',
  422. 'sczl_ms' => '包装计件',
  423. '核算产量' => $accountingYield,
  424. '工时占比' => $manHourRate,
  425. ];
  426. }
  427. }
  428. }
  429. /**
  430. * 计算工序难度系数
  431. * @param array $value 单条数据
  432. * @return float
  433. */
  434. private function calculateGxRate(array $value): float
  435. {
  436. $sczlRate = $value['sczl_工价系数'] ?: 0;
  437. $processRate = $value['工序难度系数'] ?: 0;
  438. if ($sczlRate <= 0) {
  439. return $processRate > 0 ? $processRate : 1.0000;
  440. }
  441. return $processRate > 0 ? number_format($sczlRate * $processRate, 3) : $sczlRate;
  442. }
  443. /**
  444. * 手动连接人事表数据(替代原SQL循环join,避免语法错误)
  445. * @param array $list 原查询结果
  446. * @param int $i 员工索引
  447. * @return array
  448. */
  449. private function joinStaffTable(array $list, int $i): array
  450. {
  451. $staffData = Db::name('人事_基本资料')->column('员工姓名', '员工编号');
  452. foreach ($list as &$item) {
  453. $bhKey = 'sczl_bh' . $i;
  454. $xmKey = 'name' . $i;
  455. $item[$xmKey] = $staffData[$item[$bhKey]] ?? '';
  456. }
  457. return $list;
  458. }
  459. }