unknown 1 miesiąc temu
rodzic
commit
b0050a21db
1 zmienionych plików z 214 dodań i 38 usunięć
  1. 214 38
      application/service/UnifiedCostCalculationService.php

+ 214 - 38
application/service/UnifiedCostCalculationService.php

@@ -14,7 +14,6 @@ class UnifiedCostCalculationService
 {
     // 存储中间数据的数组
     protected $monthlyCostDetails = [];  // 成本v23_月度成本明细
-    protected $monthlyUtilities = [];    // 成本_各月水电气
     protected $allocationFactors = [];   // 成本_各月分摊系数
 
     // 配置常量
@@ -36,9 +35,9 @@ class UnifiedCostCalculationService
             // 1. 清空旧数据
             $this->clearOldData($month);
 
-            // 2. 执行五项计算
-            $this->calculateDirectLabor($param);        // 直接人工
-            $this->calculateDirectUtilities($param);    // 直接水电
+            // 2. 执行五项计算(注意顺序!)
+            $this->calculateDirectLabor($param);        // 直接人工(第一步,生成monthlyCostDetails)
+            $this->calculateDirectUtilities($param);    // 直接水电(第二步,依赖calculateDirectLabor的结果)
             $this->calculateIndirectMaterials($month);  // 间接材料分摊
             $this->calculateIndirectLabor($month);      // 间接人工分摊
             $this->calculateApportionedUtilities($param); // 分摊水电
@@ -51,7 +50,6 @@ class UnifiedCostCalculationService
             Log::info("成本核算完成", [
                 'month' => $month,
                 '月度成本明细记录数' => count($this->monthlyCostDetails),
-                '水电记录数' => count($this->monthlyUtilities),
                 '分摊系数记录数' => count($this->allocationFactors)
             ]);
 
@@ -60,7 +58,6 @@ class UnifiedCostCalculationService
                 'message' => '成本核算完成',
                 'stats' => [
                     'monthly_cost_details' => count($this->monthlyCostDetails),
-                    'utilities' => count($this->monthlyUtilities),
                     'allocation_factors' => count($this->allocationFactors)
                 ]
             ];
@@ -83,7 +80,6 @@ class UnifiedCostCalculationService
         // 这里只记录要删除,实际删除操作在最后统一执行
         // 所有数据都缓存在内存中,最后统一插入
         $this->monthlyCostDetails = [];
-        $this->monthlyUtilities = [];
         $this->allocationFactors = [];
     }
 
@@ -165,36 +161,221 @@ class UnifiedCostCalculationService
     {
         $month = $param['month'];
         $sysId = $param['sys_id'] ?? '';
-        $monthStr = substr($month, 0, 4) . '-' . substr($month, 4, 2);
 
-        $sist = ['胶印车间', '凹丝印车间', '印后车间'];
-        $list = Db::name('设备_产量计酬')
-            ->alias('a')
-            ->join('设备_基本资料 b', 'a.sczl_jtbh = b.设备编号')
-            ->where('a.sczl_rq', 'like', $monthStr . '%')
-            ->where('b.sys_sbID', '<>', '')
-            ->where('b.使用部门', 'in', $sist)
-            ->field('a.sczl_jtbh,sum(a.sczl_设备运行工时) as 通电工时,b.使用部门,rtrim(b.设备名称) as 设备名称')
-            ->order('b.使用部门,a.sczl_jtbh')
-            ->group('a.sczl_jtbh')
-            ->select();
+        // 检查是否已有直接人工数据
+        if (empty($this->monthlyCostDetails)) {
+            Log::error("直接水电计算需要先计算直接人工数据");
+            throw new Exception("请先执行直接人工计算");
+        }
 
-        $now = date('Y-m-d H:i:s');
-        foreach ($list as $v) {
-            $this->monthlyUtilities[] = [
-                'Sys_ny' => $month,
-                '部门名称' => $v['使用部门'] ?? '',
-                '费用类型' => '直接',
-                '设备编号' => $v['sczl_jtbh'] ?? '',
-                '科目名称' => $v['设备名称'] ?? '',
-                '耗电量' => floatval($v['通电工时']) ?? 0,
-                '单位电价' => 0.69,
-                '耗气量' => 0,
-                '单位气价' => 0,
-                'Sys_id' => $sysId,
-                'Sys_rq' => $now,
+        try {
+            // 1. 从成本_各月水电气表查询直接水电费用数据
+            $utilityData = Db::name('成本_各月水电气')
+                ->where('Sys_ny', $month)
+                ->where('费用类型', '直接')
+                ->field('设备编号, 部门名称, 科目名称, 耗电量, 单位电价, 耗气量, 单位气价')
+                ->select();
+
+            if (empty($utilityData)) {
+                Log::info("{$month}月份未找到直接水电费用数据");
+                return;
+            }
+
+            Log::info("找到直接水电费用数据条数: " . count($utilityData));
+
+            // 2. 计算每个机台的总水电费金额
+            $machineUtilities = [];
+            foreach ($utilityData as $item) {
+                $machineCode = $item['设备编号'] ?? '';
+                if (empty($machineCode)) {
+                    continue;
+                }
+
+                // 计算电费
+                $electricityCost = floatval($item['耗电量'] ?? 0) * floatval($item['单位电价'] ?? 0);
+
+                // 计算气费
+                $gasCost = floatval($item['耗气量'] ?? 0) * floatval($item['单位气价'] ?? 0);
+
+                // 总费用
+                $totalCost = round($electricityCost + $gasCost, 2);
+
+                if (!isset($machineUtilities[$machineCode])) {
+                    $machineUtilities[$machineCode] = [
+                        '机器编号' => $machineCode,
+                        '部门名称' => $item['部门名称'] ?? '',
+                        '总费用' => 0,
+                        '电费' => 0,
+                        '气费' => 0,
+                    ];
+                }
+
+                $machineUtilities[$machineCode]['总费用'] += $totalCost;
+                $machineUtilities[$machineCode]['电费'] += $electricityCost;
+                $machineUtilities[$machineCode]['气费'] += $gasCost;
+            }
+
+            Log::info("机台水电费统计: " . json_encode($machineUtilities, JSON_UNESCAPED_UNICODE));
+
+            // 3. 获取本月所有工单的机台运行时间
+            $workOrderHours = $this->getMachineWorkHours($month);
+
+            if (empty($workOrderHours)) {
+                Log::warning("{$month}月份未找到工单运行时间数据");
+                return;
+            }
+
+            // 4. 计算每个机台的总运行时间
+            $machineTotalHours = [];
+            foreach ($workOrderHours as $workOrder) {
+                $machineCode = $workOrder['sczl_jtbh'] ?? '';
+                $hours = floatval($workOrder['占用机时'] ?? 0);
+
+                if (empty($machineCode) || $hours <= 0) {
+                    continue;
+                }
+
+                if (!isset($machineTotalHours[$machineCode])) {
+                    $machineTotalHours[$machineCode] = 0;
+                }
+                $machineTotalHours[$machineCode] += $hours;
+            }
+
+            // 5. 计算每个工单应分摊的水电费
+            $allocationResults = $this->allocateUtilitiesToWorkOrders($machineUtilities, $workOrderHours, $machineTotalHours);
+
+            // 6. 将分配结果更新到monthlyCostDetails中
+            $this->updateDirectUtilitiesToCostDetails($allocationResults);
+
+            Log::info("直接水电费分配完成,更新工单数: " . count($allocationResults));
+
+        } catch (\Exception $e) {
+            Log::error("计算直接水电费失败: " . $e->getMessage());
+            throw new Exception("直接水电费计算失败: " . $e->getMessage());
+        }
+    }
+
+    /**
+     * 获取机台生产工单的运行时间
+     * 从已计算的数据中获取,因为成本v23_月度成本明细表中尚未插入数据
+     */
+    protected function getMachineWorkHours(string $month): array
+    {
+        if (empty($this->monthlyCostDetails)) {
+            Log::warning("月度成本明细数据为空,无法获取机台运行时间");
+            return [];
+        }
+
+        $workHours = [];
+
+        foreach ($this->monthlyCostDetails as $detail) {
+            $machineCode = $detail['sczl_jtbh'] ?? '';
+            $hours = floatval($detail['占用机时'] ?? 0);
+
+            if (empty($machineCode) || $hours <= 0) {
+                continue;
+            }
+
+            $workHours[] = [
+                'sczl_gdbh' => $detail['sczl_gdbh'] ?? '',
+                'sczl_yjno' => $detail['sczl_yjno'] ?? '',
+                'sczl_gxh' => $detail['sczl_gxh'] ?? '',
+                'sczl_jtbh' => $machineCode,
+                '占用机时' => $hours,
+                '车间名称' => $detail['车间名称'] ?? '',
             ];
         }
+
+        Log::info("从月度成本明细数据中获取机台运行时间,记录数: " . count($workHours));
+
+        return $workHours;
+    }
+
+    /**
+     * 将水电费按照工时比例分配到各个工单
+     */
+    protected function allocateUtilitiesToWorkOrders(array $machineUtilities, array $workOrderHours, array $machineTotalHours): array
+    {
+        $allocationResults = [];
+
+        foreach ($workOrderHours as $workOrder) {
+            $machineCode = $workOrder['sczl_jtbh'] ?? '';
+            $hours = floatval($workOrder['占用机时'] ?? 0);
+
+            // 如果机台没有水电费数据,跳过
+            if (empty($machineCode) || !isset($machineUtilities[$machineCode]) || $machineUtilities[$machineCode]['总费用'] <= 0) {
+                continue;
+            }
+
+            // 如果机台总运行时间为0,跳过
+            if (!isset($machineTotalHours[$machineCode]) || $machineTotalHours[$machineCode] <= 0) {
+                Log::warning("机台 {$machineCode} 总运行时间为0,无法分摊");
+                continue;
+            }
+
+            // 计算该工单应分摊的金额
+            $allocationRatio = $hours / $machineTotalHours[$machineCode];
+            $allocatedAmount = round($machineUtilities[$machineCode]['总费用'] * $allocationRatio, 2);
+
+            // 构建唯一标识(用于查找对应的monthlyCostDetails记录)
+            $uniqueKey = $this->getWorkOrderUniqueKey($workOrder);
+
+            $allocationResults[$uniqueKey] = [
+                'unique_key' => $uniqueKey,
+                'sczl_gdbh' => $workOrder['sczl_gdbh'] ?? '',
+                'sczl_yjno' => $workOrder['sczl_yjno'] ?? '',
+                'sczl_gxh' => $workOrder['sczl_gxh'] ?? '',
+                'sczl_jtbh' => $machineCode,
+                '占用机时' => $hours,
+                '分摊比例' => $allocationRatio,
+                '分摊金额' => $allocatedAmount,
+                '机台总费用' => $machineUtilities[$machineCode]['总费用'],
+                '机台总工时' => $machineTotalHours[$machineCode],
+            ];
+        }
+
+        return $allocationResults;
+    }
+
+    /**
+     * 获取工单唯一标识
+     */
+    protected function getWorkOrderUniqueKey(array $workOrder): string
+    {
+        return sprintf(
+            '%s-%s-%s-%s',
+            $workOrder['sczl_gdbh'] ?? '',
+            $workOrder['sczl_yjno'] ?? '',
+            $workOrder['sczl_gxh'] ?? '',
+            $workOrder['sczl_jtbh'] ?? ''
+        );
+    }
+
+    /**
+     * 将分配的水电费更新到monthlyCostDetails中
+     */
+    protected function updateDirectUtilitiesToCostDetails(array $allocationResults): void
+    {
+        if (empty($allocationResults) || empty($this->monthlyCostDetails)) {
+            Log::warning("水电费分配结果或成本明细数据为空,无法更新");
+            return;
+        }
+
+        $updatedCount = 0;
+        $totalAllocatedAmount = 0;
+
+        foreach ($this->monthlyCostDetails as &$costDetail) {
+            $uniqueKey = $this->getWorkOrderUniqueKey($costDetail);
+
+            if (isset($allocationResults[$uniqueKey])) {
+                $allocatedAmount = $allocationResults[$uniqueKey]['分摊金额'];
+                $costDetail['直接水电'] = $allocatedAmount;
+                $totalAllocatedAmount += $allocatedAmount;
+                $updatedCount++;
+            }
+        }
+
+        Log::info("已更新直接水电费的工单数量: {$updatedCount}, 分配总金额: {$totalAllocatedAmount}");
     }
 
     /**
@@ -738,7 +919,6 @@ class UnifiedCostCalculationService
 
         // 1. 删除旧数据
         Db::name('成本v23_月度成本明细')->where('sys_ny', $month)->delete();
-        Db::name('成本_各月水电气')->where('Sys_ny', $month)->delete();
         Db::name('成本_各月分摊系数')->where('Sys_ny', $month)->delete();
 
         // 2. 插入前检查数据结构
@@ -835,10 +1015,6 @@ class UnifiedCostCalculationService
             }
         }
 
-        if (!empty($this->monthlyUtilities)) {
-            $sql = Db::name('成本_各月水电气')->fetchSql(true)->insertAll($this->monthlyUtilities);
-            Db::query($sql);
-        }
 
         if (!empty($this->allocationFactors)) {
             $sql = Db::name('成本_各月分摊系数')->fetchSql(true)->insertAll($this->allocationFactors);