CostCalculation.php 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951
  1. <?php
  2. namespace app\api\controller;
  3. use app\common\controller\Api;
  4. class CostCalculation extends Api
  5. {
  6. protected $noNeedLogin = ['*'];
  7. protected $noNeedRight = ['*'];
  8. // 车间常量
  9. const WORKSHOP_ROLLER_PRESS = '03、卷凹机组';
  10. const WORKSHOP_LIST_ALL = ['凹丝印车间', '胶印车间', '印后车间', '检验车间'];
  11. // 科目名称关键词
  12. const SUBJECT_WASTE_GAS = '废气处理';
  13. const SUBJECT_BOILER = '锅炉';
  14. const SUBJECT_HOT_WATER_BOILER = '热水锅炉';
  15. const SUBJECT_AIR_COMPRESSOR_A = '空压机A';
  16. const SUBJECT_AIR_COMPRESSOR_B = '空压机B';
  17. const SUBJECT_VACUUM_BLOWER_A = '真空鼓风机A';
  18. const SUBJECT_VACUUM_BLOWER_B = '真空鼓风机B';
  19. const SUBJECT_CENTRAL_AIR_CONDITIONER_A = '中央空调A';
  20. const SUBJECT_CENTRAL_AIR_CONDITIONER_B = '中央空调B';
  21. const SUBJECT_TOTAL_TO_APPORTION = '待分摊总额';
  22. /**
  23. * 统一的安全数值获取方法
  24. * 处理空字符串和null值,转换为0
  25. */
  26. protected function getSafeNumericValue($value)
  27. {
  28. if ($value === null || $value === '' || $value === false) {
  29. return 0;
  30. }
  31. return floatval($value);
  32. }
  33. /**
  34. * 安全的金额计算
  35. */
  36. protected function calculateSafeAmount($quantity, $unitPrice)
  37. {
  38. $safeQuantity = $this->getSafeNumericValue($quantity);
  39. $safeUnitPrice = $this->getSafeNumericValue($unitPrice);
  40. return $safeQuantity * $safeUnitPrice;
  41. }
  42. public function costCalculation()
  43. {
  44. if (!$this->request->isGet()) {
  45. $this->error('请求错误');
  46. }
  47. $param = $this->request->param();
  48. if (empty($param['month'])) {
  49. $this->error('请选择月份');
  50. }
  51. $month = $param['month'];
  52. // 计算车间水电气分摊(返回统计结果)
  53. $apportionmentResults = $this->apportionmentOne($month);
  54. // 格式化最终结果
  55. $formattedResults = $this->formatFinalResults($apportionmentResults,$month,$param['sys_id']);
  56. $machine = [];
  57. foreach ($formattedResults as $formattedResult) {
  58. $machine[] = $formattedResult['设备编号'];
  59. }
  60. $machineList = array_unique($machine);
  61. $machineWorkOrder = [];
  62. foreach ($machineList as $machine) {
  63. $machineWorkOrder[$machine] = $this->getMachineWorkOrder($machine, $month);
  64. }
  65. $apportionData = db('成本_各月分摊系数')->where(['Sys_ny' => $month])->select();
  66. if (!empty($apportionData)) {
  67. db('成本_各月分摊系数')->where(['Sys_ny' => $month])->delete();
  68. }
  69. $apportionSql = db('成本_各月分摊系数')->fetchSql(true)->insertAll($formattedResults);
  70. $apportionResults = db()->query($apportionSql);
  71. //查询车间机台色度数
  72. $machineTotal = $this->getMachineTotal($month);
  73. $data = [];
  74. foreach ($machineWorkOrder as $machineCode => $orders) {
  75. // 检查机台编号是否存在于第二个数组中
  76. if (!isset($machineTotal[$machineCode])) {
  77. continue; // 如果机台在分摊数组中不存在,跳过
  78. }
  79. $machineRates = $machineTotal[$machineCode]; // 获取该机台的费用单价
  80. // 遍历该机台下的所有工单
  81. foreach ($orders as $order) {
  82. $occupationHours = (float)$order['占用机时']; // 占用机时
  83. // 创建新记录(基础信息)
  84. $newRecord = [
  85. 'sczl_gdbh' => $order['工单编号'],
  86. 'sczl_yjno' => $order['印件号'],
  87. 'sczl_gxh' => $order['工序号'],
  88. 'sczl_jtbh' => $order['机台编号']
  89. ];
  90. // 动态添加所有科目分摊金额(基于第二个数组中的科目名称)
  91. foreach ($machineRates as $subject => $rate) {
  92. if ($subject === '待分摊总额') {
  93. $subject = '分摊水电';
  94. }
  95. $newRecord[$subject] = round($occupationHours * $rate, 2);
  96. $newRecord['直接水电'] = round($occupationHours * 0.69, 2);
  97. }
  98. $data[] = $newRecord;
  99. }
  100. }
  101. $i = 0;
  102. foreach ($data as $item) {
  103. $gdbh = $item['sczl_gdbh'];
  104. $yjno = $item['sczl_yjno'];
  105. $gxh = $item['sczl_gxh'];
  106. $jtbh = $item['sczl_jtbh'];
  107. unset($item['sczl_gdbh'], $item['sczl_yjno'], $item['sczl_gxh'], $item['sczl_jtbh']);
  108. $sql = db('成本v23_月度成本明细')
  109. ->where([
  110. 'sys_ny' => $month,
  111. 'sczl_gdbh' => $gdbh,
  112. 'sczl_yjno' => $yjno,
  113. 'sczl_gxh' => $gxh,
  114. 'sczl_jtbh' => $jtbh,
  115. ])
  116. ->fetchSql(true)
  117. ->update($item);
  118. $res = db()->query($sql);
  119. if ($res === false) {
  120. $i++;
  121. }
  122. }
  123. if ($i > 0) {
  124. $this->error('失败');
  125. }else{
  126. $this->success('成功');
  127. }
  128. }
  129. /**
  130. * 计算水电气分摊费用(优化版)
  131. */
  132. protected function apportionmentOne($month)
  133. {
  134. $utilityList = db('成本_各月水电气')
  135. ->where('Sys_ny', $month)
  136. ->whereLike('费用类型', '%分摊%')
  137. ->select();
  138. if (empty($utilityList)) {
  139. return [];
  140. }
  141. // 初始化统计数据结构
  142. $machineSummary = []; // 按机台统计
  143. $subjectSummary = []; // 按科目统计
  144. $workshopSummary = []; // 按车间统计
  145. $apportionmentResults = []; // 原始分摊结果
  146. $allMachineData = []; // 所有机台数据
  147. // 先处理所有分摊项目
  148. foreach ($utilityList as $item) {
  149. // 确保数值安全
  150. $item['耗电量'] = $this->getSafeNumericValue($item['耗电量']);
  151. $item['单位电价'] = $this->getSafeNumericValue($item['单位电价']);
  152. $item['耗气量'] = $this->getSafeNumericValue($item['耗气量']);
  153. $item['单位气价'] = $this->getSafeNumericValue($item['单位气价']);
  154. $result = $this->processUtilityItem($item, $month);
  155. if ($result) {
  156. $apportionmentResults[] = $result;
  157. // 合并所有机台数据
  158. $this->mergeMachineData($result['data'], $allMachineData, $item['科目名称']);
  159. }
  160. }
  161. // 按机台+科目进行汇总统计
  162. $this->summarizeByMachineAndSubject($allMachineData, $machineSummary, $subjectSummary, $workshopSummary);
  163. // 对统计结果进行排序
  164. ksort($machineSummary);
  165. return $machineSummary;
  166. }
  167. /**
  168. * 合并所有机台数据
  169. */
  170. protected function mergeMachineData($machineData, &$allMachineData, $subjectName)
  171. {
  172. if (empty($machineData)) {
  173. return;
  174. }
  175. foreach ($machineData as $machine) {
  176. $machineId = $machine['机台编号'] ?? '';
  177. $workshop = $machine['车间名称'] ?? '未知车间';
  178. $workOrder = $machine['工单编号'] ?? '';
  179. $processNo = $machine['工序号'] ?? '';
  180. $printNo = $machine['印件号'] ?? '';
  181. $machineTime = floatval($machine['占用机时'] ?? 0);
  182. $uniqid = $machine['Uniqid'] ?? '';
  183. if (empty($machineId)) {
  184. continue;
  185. }
  186. // 初始化机台数据
  187. if (!isset($allMachineData[$machineId])) {
  188. $allMachineData[$machineId] = [
  189. '机台编号' => $machineId,
  190. '车间名称' => $workshop,
  191. '占用机时' => $machineTime,
  192. '工单编号' => $workOrder,
  193. '工序号' => $processNo,
  194. '印件号' => $printNo,
  195. 'Uniqid' => $uniqid,
  196. '科目明细' => [],
  197. '工单列表' => [],
  198. '科目总计' => 0
  199. ];
  200. }
  201. // 更新机台基础信息(如果有更完整的信息)
  202. if (empty($allMachineData[$machineId]['工单编号']) && !empty($workOrder)) {
  203. $allMachineData[$machineId]['工单编号'] = $workOrder;
  204. }
  205. if (empty($allMachineData[$machineId]['工序号']) && !empty($processNo)) {
  206. $allMachineData[$machineId]['工序号'] = $processNo;
  207. }
  208. if (empty($allMachineData[$machineId]['印件号']) && !empty($printNo)) {
  209. $allMachineData[$machineId]['印件号'] = $printNo;
  210. }
  211. // 记录工单(去重)
  212. if (!empty($workOrder) && !in_array($workOrder, $allMachineData[$machineId]['工单列表'])) {
  213. $allMachineData[$machineId]['工单列表'][] = $workOrder;
  214. }
  215. // 合并科目金额
  216. $apportionmentTypes = ['分摊水电', '废气处理', '锅炉', '热水锅炉',
  217. '空压机A', '空压机B', '真空鼓风机A', '真空鼓风机B',
  218. '中央空调A', '中央空调B'];
  219. $machineTotal = 0;
  220. foreach ($apportionmentTypes as $type) {
  221. if (isset($machine[$type]) && floatval($machine[$type]) > 0) {
  222. $amount = floatval($machine[$type]);
  223. $machineTotal += $amount;
  224. // 初始化科目明细
  225. if (!isset($allMachineData[$machineId]['科目明细'][$type])) {
  226. $allMachineData[$machineId]['科目明细'][$type] = [
  227. 'subject_name' => $type,
  228. 'total_amount' => 0,
  229. 'source_count' => 0,
  230. 'source_subjects' => ''
  231. ];
  232. }
  233. // 累加金额
  234. $allMachineData[$machineId]['科目明细'][$type]['total_amount'] += $amount;
  235. $allMachineData[$machineId]['科目明细'][$type]['source_count']++;
  236. // 记录来源科目
  237. $allMachineData[$machineId]['科目明细'][$type]['source_subjects'] = $subjectName;
  238. }
  239. }
  240. // 更新机台总计
  241. $allMachineData[$machineId]['科目总计'] += $machineTotal;
  242. }
  243. }
  244. /**
  245. * 按机台+科目进行汇总统计
  246. */
  247. protected function summarizeByMachineAndSubject($allMachineData, &$machineSummary, &$subjectSummary, &$workshopSummary)
  248. {
  249. foreach ($allMachineData as $machineId => $machineInfo) {
  250. $workshop = $machineInfo['车间名称'];
  251. // 1. 按机台统计
  252. $machineSummary[$machineId] = [
  253. '机台编号' => $machineId,
  254. '车间名称' => $workshop,
  255. '工单数量' => count($machineInfo['工单列表']),
  256. '占用机时' => $machineInfo['占用机时'],
  257. '科目总计' => round($machineInfo['科目总计'], 2),
  258. '科目明细' => [],
  259. '工单列表' => $machineInfo['工单列表']
  260. ];
  261. // 处理科目明细
  262. foreach ($machineInfo['科目明细'] as $subjectType => $subjectDetail) {
  263. $amount = round($subjectDetail['total_amount'], 2);
  264. $machineSummary[$machineId]['科目明细'][$subjectType] = [
  265. 'amount' => $amount,
  266. 'source_count' => $subjectDetail['source_count'],
  267. 'source_subjects' => $subjectDetail['source_subjects'],
  268. 'percentage' => $machineInfo['科目总计'] > 0
  269. ? round(($subjectDetail['total_amount'] / $machineInfo['科目总计']) * 100, 2)
  270. : 0
  271. ];
  272. }
  273. // 2. 按科目统计
  274. foreach ($machineInfo['科目明细'] as $subjectType => $subjectDetail) {
  275. $amount = round($subjectDetail['total_amount'], 2);
  276. // 初始化科目统计
  277. if (!isset($subjectSummary[$subjectType])) {
  278. $subjectSummary[$subjectType] = [
  279. 'subject_name' => $subjectType,
  280. 'total_amount' => 0,
  281. 'machine_count' => 0,
  282. 'workshop_distribution' => [],
  283. 'machine_list' => []
  284. ];
  285. }
  286. // 累加科目总计
  287. $subjectSummary[$subjectType]['total_amount'] += $subjectDetail['total_amount'];
  288. $subjectSummary[$subjectType]['machine_count']++;
  289. // 按车间分布
  290. if (!isset($subjectSummary[$subjectType]['workshop_distribution'][$workshop])) {
  291. $subjectSummary[$subjectType]['workshop_distribution'][$workshop] = 0;
  292. }
  293. $subjectSummary[$subjectType]['workshop_distribution'][$workshop] += $subjectDetail['total_amount'];
  294. // 机台列表
  295. $subjectSummary[$subjectType]['machine_list'][] = [
  296. 'machine_id' => $machineId,
  297. 'workshop' => $workshop,
  298. 'amount' => $amount,
  299. 'percentage' => $subjectSummary[$subjectType]['total_amount'] > 0
  300. ? round(($subjectDetail['total_amount'] / $subjectSummary[$subjectType]['total_amount']) * 100, 2)
  301. : 0
  302. ];
  303. }
  304. // 3. 按车间统计
  305. if (!isset($workshopSummary[$workshop])) {
  306. $workshopSummary[$workshop] = [
  307. 'workshop_name' => $workshop,
  308. 'machine_count' => 0,
  309. 'total_amount' => 0,
  310. 'subject_distribution' => [],
  311. 'machine_list' => []
  312. ];
  313. }
  314. $workshopSummary[$workshop]['machine_count']++;
  315. $workshopSummary[$workshop]['total_amount'] += $machineInfo['科目总计'];
  316. // 车间内科目分布
  317. foreach ($machineInfo['科目明细'] as $subjectType => $subjectDetail) {
  318. if (!isset($workshopSummary[$workshop]['subject_distribution'][$subjectType])) {
  319. $workshopSummary[$workshop]['subject_distribution'][$subjectType] = 0;
  320. }
  321. $workshopSummary[$workshop]['subject_distribution'][$subjectType] += $subjectDetail['total_amount'];
  322. }
  323. // 车间内机台列表
  324. $workshopSummary[$workshop]['machine_list'][] = [
  325. 'machine_id' => $machineId,
  326. 'total_amount' => round($machineInfo['科目总计'], 2),
  327. 'subject_count' => count($machineInfo['科目明细']),
  328. 'work_order_count' => count($machineInfo['工单列表'])
  329. ];
  330. }
  331. // 对科目统计进行后处理
  332. $this->processSubjectSummary($subjectSummary);
  333. // 对车间统计进行后处理
  334. $this->processWorkshopSummary($workshopSummary);
  335. }
  336. /**
  337. * 处理科目统计
  338. */
  339. protected function processSubjectSummary(&$subjectSummary)
  340. {
  341. foreach ($subjectSummary as &$subject) {
  342. // 金额四舍五入
  343. $subject['total_amount'] = round($subject['total_amount'], 2);
  344. // 车间分布百分比
  345. foreach ($subject['workshop_distribution'] as $workshop => &$amount) {
  346. $amount = round($amount, 2);
  347. }
  348. // 按金额排序机台列表
  349. usort($subject['machine_list'], function($a, $b) {
  350. return $b['amount'] <=> $a['amount'];
  351. });
  352. // 计算机台平均金额
  353. $subject['avg_per_machine'] = $subject['machine_count'] > 0
  354. ? round($subject['total_amount'] / $subject['machine_count'], 2)
  355. : 0;
  356. }
  357. }
  358. /**
  359. * 处理车间统计
  360. */
  361. protected function processWorkshopSummary(&$workshopSummary)
  362. {
  363. foreach ($workshopSummary as &$workshop) {
  364. // 金额四舍五入
  365. $workshop['total_amount'] = round($workshop['total_amount'], 2);
  366. // 科目分布百分比
  367. $workshop['subject_percentage'] = [];
  368. foreach ($workshop['subject_distribution'] as $subjectType => $amount) {
  369. $roundedAmount = round($amount, 2);
  370. $workshop['subject_distribution'][$subjectType] = $roundedAmount;
  371. if ($workshop['total_amount'] > 0) {
  372. $workshop['subject_percentage'][$subjectType] =
  373. round(($roundedAmount / $workshop['total_amount']) * 100, 2);
  374. }
  375. }
  376. // 按金额排序机台列表
  377. usort($workshop['machine_list'], function($a, $b) {
  378. return $b['total_amount'] <=> $a['total_amount'];
  379. });
  380. // 计算机台平均金额
  381. $workshop['avg_per_machine'] = $workshop['machine_count'] > 0
  382. ? round($workshop['total_amount'] / $workshop['machine_count'], 2)
  383. : 0;
  384. // 统计科目种类数
  385. $workshop['subject_count'] = count($workshop['subject_distribution']);
  386. }
  387. }
  388. /**
  389. * 处理单个水电费用项
  390. */
  391. protected function processUtilityItem($item, $month)
  392. {
  393. $subjectName = $item['科目名称'];
  394. // 使用switch-like结构提高可读性
  395. $processMap = [
  396. self::SUBJECT_TOTAL_TO_APPORTION => 'processTotalApportionment',
  397. self::SUBJECT_WASTE_GAS => 'processWasteGas',
  398. self::SUBJECT_BOILER => 'processBoiler',
  399. self::SUBJECT_AIR_COMPRESSOR_A => 'processAirCompressorA',
  400. self::SUBJECT_AIR_COMPRESSOR_B => 'processAirCompressorB',
  401. self::SUBJECT_VACUUM_BLOWER_A => 'processVacuumBlowerA',
  402. self::SUBJECT_VACUUM_BLOWER_B => 'processVacuumBlowerB',
  403. self::SUBJECT_CENTRAL_AIR_CONDITIONER_A => 'processCentralAirConditionerA',
  404. self::SUBJECT_CENTRAL_AIR_CONDITIONER_B => 'processCentralAirConditionerB',
  405. self::SUBJECT_HOT_WATER_BOILER => 'processHotWaterBoiler',
  406. ];
  407. // 检查是否完全匹配
  408. if (isset($processMap[$subjectName])) {
  409. $method = $processMap[$subjectName];
  410. return $this->$method($item, $month);
  411. }
  412. // 检查是否包含关键词
  413. foreach ($processMap as $keyword => $method) {
  414. if (strpos($subjectName, $keyword) !== false) {
  415. // 特殊处理:如果包含"锅炉"但不包含"热水锅炉"
  416. if ($keyword === self::SUBJECT_BOILER && strpos($subjectName, self::SUBJECT_HOT_WATER_BOILER) !== false) {
  417. continue;
  418. }
  419. return $this->$method($item, $month);
  420. }
  421. }
  422. return null;
  423. }
  424. /**
  425. * 处理待分摊总额
  426. */
  427. protected function processTotalApportionment($item, $month)
  428. {
  429. $money = $this->calculateSafeAmount($item['耗电量'], $item['单位电价']);
  430. $data = $this->getMachineTime($item['部门名称'], $month);
  431. foreach ($data['machine'] as &$machine) {
  432. $machine['分摊水电'] = $this->calculateApportionment($money, $machine['占用机时'], $data['sist']);
  433. }
  434. return [
  435. 'type' => 'total_apportionment',
  436. 'data' => $data['machine']
  437. ];
  438. }
  439. /**
  440. * 处理废气处理
  441. */
  442. protected function processWasteGas($item, $month)
  443. {
  444. $electricityMoney = $this->calculateSafeAmount($item['耗电量'], $item['单位电价']);
  445. $gasMoney = $this->calculateSafeAmount($item['耗气量'], $item['单位气价']);
  446. $data = $this->getMachineTime(self::WORKSHOP_ROLLER_PRESS, $month);
  447. foreach ($data['machine'] as &$machine) {
  448. $machine['分摊水电'] = $this->calculateApportionment($electricityMoney, $machine['占用机时'], $data['sist']);
  449. $machine['废气处理'] = $this->calculateApportionment($gasMoney, $machine['占用机时'], $data['sist']);
  450. }
  451. return [
  452. 'type' => 'waste_gas',
  453. 'data' => $data['machine']
  454. ];
  455. }
  456. /**
  457. * 处理锅炉
  458. */
  459. protected function processBoiler($item, $month)
  460. {
  461. $electricityMoney = $this->calculateSafeAmount($item['耗电量'], $item['单位电价']);
  462. $gasMoney = $this->calculateSafeAmount($item['耗气量'], $item['单位气价']);
  463. $data = $this->getMachineTime(self::WORKSHOP_ROLLER_PRESS, $month);
  464. foreach ($data['machine'] as &$machine) {
  465. $machine['分摊水电'] = $this->calculateApportionment($electricityMoney, $machine['占用机时'], $data['sist']);
  466. $machine['锅炉'] = $this->calculateApportionment($gasMoney, $machine['占用机时'], $data['sist']);
  467. }
  468. return [
  469. 'type' => 'boiler',
  470. 'data' => $data['machine']
  471. ];
  472. }
  473. /**
  474. * 处理空压机A
  475. */
  476. protected function processAirCompressorA($item, $month)
  477. {
  478. return $this->processGeneralElectricEquipment($item, $month, self::SUBJECT_AIR_COMPRESSOR_A);
  479. }
  480. /**
  481. * 处理空压机B
  482. */
  483. protected function processAirCompressorB($item, $month)
  484. {
  485. return $this->processGeneralElectricEquipment($item, $month, self::SUBJECT_AIR_COMPRESSOR_B);
  486. }
  487. /**
  488. * 处理真空鼓风机A
  489. */
  490. protected function processVacuumBlowerA($item, $month)
  491. {
  492. return $this->processGeneralElectricEquipment($item, $month, self::SUBJECT_VACUUM_BLOWER_A);
  493. }
  494. /**
  495. * 处理真空鼓风机B
  496. */
  497. protected function processVacuumBlowerB($item, $month)
  498. {
  499. return $this->processGeneralElectricEquipment($item, $month, self::SUBJECT_VACUUM_BLOWER_B);
  500. }
  501. /**
  502. * 处理中央空调A
  503. */
  504. protected function processCentralAirConditionerA($item, $month)
  505. {
  506. return $this->processGeneralElectricEquipment($item, $month, self::SUBJECT_CENTRAL_AIR_CONDITIONER_A);
  507. }
  508. /**
  509. * 处理中央空调B
  510. */
  511. protected function processCentralAirConditionerB($item, $month)
  512. {
  513. return $this->processGeneralElectricEquipment($item, $month, self::SUBJECT_CENTRAL_AIR_CONDITIONER_B);
  514. }
  515. /**
  516. * 处理热水锅炉
  517. */
  518. protected function processHotWaterBoiler($item, $month)
  519. {
  520. return $this->processGeneralElectricEquipment($item, $month, '热水锅炉');
  521. }
  522. /**
  523. * 通用电气设备处理(适用于所有车间)
  524. */
  525. protected function processGeneralElectricEquipment($item, $month, $equipmentType)
  526. {
  527. $money = $this->calculateSafeAmount($item['耗电量'], $item['单位电价']);
  528. $data = $this->getMachineTime(self::WORKSHOP_LIST_ALL, $month);
  529. foreach ($data['machine'] as &$machine) {
  530. $machine[$equipmentType] = $this->calculateApportionment($money, $machine['占用机时'], $data['sist']);
  531. }
  532. return [
  533. 'type' => $equipmentType,
  534. 'data' => $data['machine']
  535. ];
  536. }
  537. /**
  538. * 计算分摊金额
  539. */
  540. protected function calculateApportionment($totalAmount, $machineTime, $totalTime)
  541. {
  542. if ($totalTime <= 0) {
  543. return 0;
  544. }
  545. return round($totalAmount * ($machineTime / $totalTime), 2);
  546. }
  547. /**
  548. * 查询车间机台通电机时数据(优化版)
  549. */
  550. protected function getMachineTime($workshop, $month)
  551. {
  552. $where = [
  553. 'a.sys_ny' => $month,
  554. 'b.sys_sbID' => ['<>','']
  555. ];
  556. // 构建车间查询条件
  557. if (is_array($workshop)) {
  558. $where['a.车间名称'] = ['in', $workshop];
  559. } else {
  560. if (strpos($workshop, '机组') !== false) {
  561. $where['b.设备编组'] = $workshop;
  562. } elseif (strpos($workshop, '车间') !== false) {
  563. $where['a.车间名称'] = $workshop;
  564. }
  565. }
  566. // 查询机台数据
  567. $machine = db('成本v23_月度成本明细')
  568. ->alias('a')
  569. ->join('设备_基本资料 b', 'a.sczl_jtbh = b.设备编号', 'left')
  570. ->field('rtrim(车间名称) as 车间名称,a.sczl_gdbh as 工单编号,a.sczl_yjno as 印件号,a.sczl_gxh as 工序号,a.sczl_jtbh as 机台编号,a.占用机时,a.Uniqid')
  571. ->where($where)
  572. ->select();
  573. // 查询总时长
  574. $totalTime = db('成本v23_月度成本明细')
  575. ->alias('a')
  576. ->join('设备_基本资料 b', 'a.sczl_jtbh = b.设备编号', 'left')
  577. ->where($where)
  578. ->value('sum(a.占用机时) as 占用机时', 0);
  579. return [
  580. 'machine' => $machine,
  581. 'sist' => $totalTime
  582. ];
  583. }
  584. /**
  585. * 统计分摊结果
  586. */
  587. protected function summarizeApportionment($result, $department, $subject,
  588. &$summaryByDepartment, &$summaryBySubject,
  589. &$summaryByDepartmentSubject)
  590. {
  591. $resultType = $result['type'];
  592. $machineData = $result['data'];
  593. if (empty($machineData)) {
  594. return;
  595. }
  596. // 清洗部门名称
  597. $cleanDepartment = trim($department);
  598. $cleanSubject = trim($subject);
  599. // 初始化统计键
  600. if (!isset($summaryByDepartment[$cleanDepartment])) {
  601. $summaryByDepartment[$cleanDepartment] = [];
  602. }
  603. if (!isset($summaryBySubject[$resultType])) {
  604. $summaryBySubject[$resultType] = [];
  605. }
  606. if (!isset($summaryByDepartmentSubject[$cleanDepartment])) {
  607. $summaryByDepartmentSubject[$cleanDepartment] = [];
  608. }
  609. if (!isset($summaryByDepartmentSubject[$cleanDepartment][$resultType])) {
  610. $summaryByDepartmentSubject[$cleanDepartment][$resultType] = [
  611. 'department' => $cleanDepartment,
  612. 'subject' => $cleanSubject,
  613. 'result_type' => $resultType,
  614. 'total_amount' => 0,
  615. 'machine_count' => 0,
  616. 'work_order_count' => 0
  617. ];
  618. }
  619. // 按车间和机台统计
  620. foreach ($machineData as $machine) {
  621. // 获取车间名称(已使用rtrim清洗过)
  622. $workshop = isset($machine['车间名称']) ? $machine['车间名称'] : '未知车间';
  623. // 统计按部门
  624. if (!isset($summaryByDepartment[$cleanDepartment][$workshop])) {
  625. $summaryByDepartment[$cleanDepartment][$workshop] = [
  626. 'total_amount' => 0,
  627. 'machine_count' => 0,
  628. 'subjects' => []
  629. ];
  630. }
  631. // 统计按科目
  632. if (!isset($summaryBySubject[$resultType][$workshop])) {
  633. $summaryBySubject[$resultType][$workshop] = [
  634. 'total_amount' => 0,
  635. 'machine_count' => 0,
  636. 'departments' => []
  637. ];
  638. }
  639. // 计算此机台的总分摊金额
  640. $machineTotal = 0;
  641. $apportionmentTypes = ['分摊水电', '废气处理', '锅炉', '热水锅炉',
  642. '空压机A', '空压机B', '真空鼓风机A', '真空鼓风机B',
  643. '中央空调A', '中央空调B'];
  644. foreach ($apportionmentTypes as $type) {
  645. if (isset($machine[$type])) {
  646. $amount = floatval($machine[$type]);
  647. $machineTotal += $amount;
  648. // 按部门+车间统计各科目金额
  649. if (!isset($summaryByDepartment[$cleanDepartment][$workshop]['subjects'][$type])) {
  650. $summaryByDepartment[$cleanDepartment][$workshop]['subjects'][$type] = 0;
  651. }
  652. $summaryByDepartment[$cleanDepartment][$workshop]['subjects'][$type] += $amount;
  653. // 按科目+车间统计各部门金额
  654. if (!in_array($cleanDepartment, $summaryBySubject[$resultType][$workshop]['departments'])) {
  655. $summaryBySubject[$resultType][$workshop]['departments'][] = $cleanDepartment;
  656. }
  657. }
  658. }
  659. // 更新统计信息
  660. if ($machineTotal > 0) {
  661. $summaryByDepartment[$cleanDepartment][$workshop]['total_amount'] += $machineTotal;
  662. $summaryByDepartment[$cleanDepartment][$workshop]['machine_count']++;
  663. $summaryBySubject[$resultType][$workshop]['total_amount'] += $machineTotal;
  664. $summaryBySubject[$resultType][$workshop]['machine_count']++;
  665. $summaryByDepartmentSubject[$cleanDepartment][$resultType]['total_amount'] += $machineTotal;
  666. $summaryByDepartmentSubject[$cleanDepartment][$resultType]['machine_count']++;
  667. // 统计工单数(去重)
  668. if (!isset($summaryByDepartmentSubject[$cleanDepartment][$resultType]['work_orders'])) {
  669. $summaryByDepartmentSubject[$cleanDepartment][$resultType]['work_orders'] = [];
  670. }
  671. if (isset($machine['工单编号'])) {
  672. $summaryByDepartmentSubject[$cleanDepartment][$resultType]['work_orders'][] = $machine['工单编号'];
  673. }
  674. }
  675. }
  676. // 计算工单数(去重)
  677. foreach ($summaryByDepartmentSubject[$cleanDepartment] as $type => &$data) {
  678. if (isset($data['work_orders'])) {
  679. $data['work_order_count'] = count(array_unique($data['work_orders']));
  680. unset($data['work_orders']);
  681. }
  682. }
  683. // 为部门统计添加汇总信息
  684. $this->addSummaryToDepartment($summaryByDepartment[$cleanDepartment]);
  685. // 为科目统计添加汇总信息
  686. $this->addSummaryToSubject($summaryBySubject[$resultType]);
  687. }
  688. /**
  689. * 为部门统计添加汇总信息
  690. */
  691. protected function addSummaryToDepartment(&$departmentData)
  692. {
  693. $totalAmount = 0;
  694. $totalMachines = 0;
  695. foreach ($departmentData as $workshop => $data) {
  696. if ($workshop === 'summary') continue;
  697. $totalAmount += $data['total_amount'];
  698. $totalMachines += $data['machine_count'];
  699. }
  700. $departmentData['summary'] = [
  701. 'total_amount' => round($totalAmount, 2),
  702. 'total_machines' => $totalMachines,
  703. 'workshop_count' => count($departmentData) - 1
  704. ];
  705. }
  706. /**
  707. * 为科目统计添加汇总信息
  708. */
  709. protected function addSummaryToSubject(&$subjectData)
  710. {
  711. $totalAmount = 0;
  712. $totalMachines = 0;
  713. $allDepartments = [];
  714. foreach ($subjectData as $workshop => $data) {
  715. if ($workshop === 'summary') continue;
  716. $totalAmount += $data['total_amount'];
  717. $totalMachines += $data['machine_count'];
  718. $allDepartments = array_merge($allDepartments, $data['departments']);
  719. }
  720. $subjectData['summary'] = [
  721. 'total_amount' => round($totalAmount, 2),
  722. 'total_machines' => $totalMachines,
  723. 'workshop_count' => count($subjectData) - 1,
  724. 'department_count' => count(array_unique($allDepartments))
  725. ];
  726. }
  727. /**
  728. * 格式化最终统计结果
  729. */
  730. protected function formatFinalResults($apportionmentResults,$month,$sys)
  731. {
  732. $data = [];
  733. foreach ($apportionmentResults as $key => $value) {
  734. foreach ($value['科目明细'] as $item) {
  735. $data[] = [
  736. 'Sys_ny' => $month,
  737. '科目名称' => $item['source_subjects'],
  738. '设备编号' => $key,
  739. '分摊系数' => 1,
  740. '分摊金额' => $item['amount'],
  741. 'Sys_id' => $sys,
  742. 'Sys_rq' => date('Y-m-d H:i:s',time()),
  743. ];
  744. }
  745. }
  746. return $data;
  747. }
  748. /**
  749. * 获取车间机台生产工单
  750. * @param $sist
  751. * @param $month
  752. * @return bool|\PDOStatement|string|\think\Collection
  753. * @throws \think\db\exception\DataNotFoundException
  754. * @throws \think\db\exception\ModelNotFoundException
  755. * @throws \think\exception\DbException
  756. */
  757. protected function getMachineWorkOrder($machine,$month)
  758. {
  759. $list = db('成本v23_月度成本明细')
  760. ->where([
  761. 'sys_ny' => $month,
  762. 'sczl_jtbh' => $machine,
  763. ])
  764. ->field([
  765. 'sczl_gdbh' => '工单编号',
  766. 'sczl_yjno' => '印件号',
  767. 'sczl_gxh' => '工序号',
  768. 'sczl_jtbh' => '机台编号',
  769. '占用机时',
  770. ])
  771. ->group('工单编号,印件号,工序号')
  772. ->select();
  773. return $list;
  774. }
  775. /**
  776. * 查询车间机台色度数
  777. * @param $month
  778. * @return bool|\PDOStatement|string|\think\Collection
  779. * @throws \think\db\exception\DataNotFoundException
  780. * @throws \think\db\exception\ModelNotFoundException
  781. * @throws \think\exception\DbException
  782. */
  783. protected function getMachineTotal($month)
  784. {
  785. $list = db('成本_各月分摊系数')
  786. ->alias('a')
  787. ->join('成本v23_月度成本明细 b', 'b.sys_ny = a.Sys_ny and b.sczl_jtbh = a.设备编号','LEFT')
  788. ->where([
  789. 'a.Sys_ny' => $month,
  790. 'b.车间名称' => ['in', self::WORKSHOP_LIST_ALL],
  791. ])
  792. ->field([
  793. 'b.sczl_jtbh' => '机台编号',
  794. 'sum(b.占用机时)' => '占用机时',
  795. 'a.分摊金额',
  796. 'a.科目名称',
  797. ])
  798. ->group('机台编号,a.科目名称')
  799. ->select();
  800. foreach ($list as $key => $item) {
  801. $list[$key]['金额'] = round($item['分摊金额']/$item['占用机时'], 2);
  802. }
  803. $data = [];
  804. foreach ($list as $item) {
  805. $machineCode = $item['机台编号'];
  806. $subjectName = explode('(',$item['科目名称']);
  807. $amount = $item['金额'];
  808. // 如果这个机台编号还没有在结果数组中,初始化它
  809. if (!isset($data[$machineCode])) {
  810. $data[$machineCode] = [];
  811. }
  812. // 将科目名称和金额添加到对应的机台编号下
  813. $data[$machineCode][$subjectName[0]] = $amount;
  814. }
  815. return $data;
  816. }
  817. }