|
@@ -14,7 +14,6 @@ class UnifiedCostCalculationService
|
|
|
{
|
|
{
|
|
|
// 存储中间数据的数组
|
|
// 存储中间数据的数组
|
|
|
protected $monthlyCostDetails = []; // 成本v23_月度成本明细
|
|
protected $monthlyCostDetails = []; // 成本v23_月度成本明细
|
|
|
- protected $monthlyUtilities = []; // 成本_各月水电气
|
|
|
|
|
protected $allocationFactors = []; // 成本_各月分摊系数
|
|
protected $allocationFactors = []; // 成本_各月分摊系数
|
|
|
|
|
|
|
|
// 配置常量
|
|
// 配置常量
|
|
@@ -36,9 +35,9 @@ class UnifiedCostCalculationService
|
|
|
// 1. 清空旧数据
|
|
// 1. 清空旧数据
|
|
|
$this->clearOldData($month);
|
|
$this->clearOldData($month);
|
|
|
|
|
|
|
|
- // 2. 执行五项计算
|
|
|
|
|
- $this->calculateDirectLabor($param); // 直接人工
|
|
|
|
|
- $this->calculateDirectUtilities($param); // 直接水电
|
|
|
|
|
|
|
+ // 2. 执行五项计算(注意顺序!)
|
|
|
|
|
+ $this->calculateDirectLabor($param); // 直接人工(第一步,生成monthlyCostDetails)
|
|
|
|
|
+ $this->calculateDirectUtilities($param); // 直接水电(第二步,依赖calculateDirectLabor的结果)
|
|
|
$this->calculateIndirectMaterials($month); // 间接材料分摊
|
|
$this->calculateIndirectMaterials($month); // 间接材料分摊
|
|
|
$this->calculateIndirectLabor($month); // 间接人工分摊
|
|
$this->calculateIndirectLabor($month); // 间接人工分摊
|
|
|
$this->calculateApportionedUtilities($param); // 分摊水电
|
|
$this->calculateApportionedUtilities($param); // 分摊水电
|
|
@@ -51,7 +50,6 @@ class UnifiedCostCalculationService
|
|
|
Log::info("成本核算完成", [
|
|
Log::info("成本核算完成", [
|
|
|
'month' => $month,
|
|
'month' => $month,
|
|
|
'月度成本明细记录数' => count($this->monthlyCostDetails),
|
|
'月度成本明细记录数' => count($this->monthlyCostDetails),
|
|
|
- '水电记录数' => count($this->monthlyUtilities),
|
|
|
|
|
'分摊系数记录数' => count($this->allocationFactors)
|
|
'分摊系数记录数' => count($this->allocationFactors)
|
|
|
]);
|
|
]);
|
|
|
|
|
|
|
@@ -60,7 +58,6 @@ class UnifiedCostCalculationService
|
|
|
'message' => '成本核算完成',
|
|
'message' => '成本核算完成',
|
|
|
'stats' => [
|
|
'stats' => [
|
|
|
'monthly_cost_details' => count($this->monthlyCostDetails),
|
|
'monthly_cost_details' => count($this->monthlyCostDetails),
|
|
|
- 'utilities' => count($this->monthlyUtilities),
|
|
|
|
|
'allocation_factors' => count($this->allocationFactors)
|
|
'allocation_factors' => count($this->allocationFactors)
|
|
|
]
|
|
]
|
|
|
];
|
|
];
|
|
@@ -83,7 +80,6 @@ class UnifiedCostCalculationService
|
|
|
// 这里只记录要删除,实际删除操作在最后统一执行
|
|
// 这里只记录要删除,实际删除操作在最后统一执行
|
|
|
// 所有数据都缓存在内存中,最后统一插入
|
|
// 所有数据都缓存在内存中,最后统一插入
|
|
|
$this->monthlyCostDetails = [];
|
|
$this->monthlyCostDetails = [];
|
|
|
- $this->monthlyUtilities = [];
|
|
|
|
|
$this->allocationFactors = [];
|
|
$this->allocationFactors = [];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -165,36 +161,221 @@ class UnifiedCostCalculationService
|
|
|
{
|
|
{
|
|
|
$month = $param['month'];
|
|
$month = $param['month'];
|
|
|
$sysId = $param['sys_id'] ?? '';
|
|
$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. 删除旧数据
|
|
// 1. 删除旧数据
|
|
|
Db::name('成本v23_月度成本明细')->where('sys_ny', $month)->delete();
|
|
Db::name('成本v23_月度成本明细')->where('sys_ny', $month)->delete();
|
|
|
- Db::name('成本_各月水电气')->where('Sys_ny', $month)->delete();
|
|
|
|
|
Db::name('成本_各月分摊系数')->where('Sys_ny', $month)->delete();
|
|
Db::name('成本_各月分摊系数')->where('Sys_ny', $month)->delete();
|
|
|
|
|
|
|
|
// 2. 插入前检查数据结构
|
|
// 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)) {
|
|
if (!empty($this->allocationFactors)) {
|
|
|
$sql = Db::name('成本_各月分摊系数')->fetchSql(true)->insertAll($this->allocationFactors);
|
|
$sql = Db::name('成本_各月分摊系数')->fetchSql(true)->insertAll($this->allocationFactors);
|