false, 'message' => '参数错误']; } $where = ['a.sczl_rq' => ['between', [$params['startDay'] . ' 00:00:00', $params['endDay'] . ' 23:59:59']]]; $filds = "a.sczl_gdbh as 工单编号,a.sczl_gxmc as 工序名称,a.sczl_cl as 产量,a.sczl_rq as 日期, a.sczl_dedh as 定额代号,d.日定额 as 日定额,a.工价系数,a.保养工时,a.装版工时,a.异常工时,a.设备运行工时,a.role,a.sczl_jtbh,b.Gd_cpdh,b.Gd_cpmc,a.price"; $list = db('设备_糊盒报工资料') ->alias('a') ->join('工单_基本资料 b', 'a.sczl_gdbh = b.Gd_gdbh ', 'left') ->join('dic_lzde d', 'a.sczl_dedh = d.sys_bh', 'left') ->field($filds) ->where($where) ->group('a.Uid') ->select(); $pieceData = []; foreach ($list as $v) { $result = $this->salaryCalculationClass($v['role']); if ($this->isManualMachine($v['sczl_jtbh'])) { $wageList = $this->calculateManualPieceWages($v, $result); } else { $wageList = $this->calculateRegularPieceWages($v, $result); } foreach ($wageList as $wageItem) { $pieceData[] = $this->buildSalarySummaryRow([ 'sczl_gdbh' => $v['工单编号'], 'sczl_gxmc' => $v['工序名称'], 'sczl_rq' => $v['日期'], 'sczl_cl' => $v['产量'], 'sczl_dedh' => $v['定额代号'], '工价系数' => $v['工价系数'], '保养工时' => $v['保养工时'], '装版工时' => $v['装版工时'], '异常工时' => $v['异常工时'], '设备运行工时' => $v['设备运行工时'], 'sczl_jtbh' => $v['sczl_jtbh'], 'cpdh' => $v['Gd_cpdh'], 'cpmc' => $v['Gd_cpmc'], 'bh' => $wageItem['bh'], 'rate' => $wageItem['rate'], 'name' => $wageItem['name'], 'salary' => $wageItem['wage'], 'price' => $v['price'], 'sys_id' => $params['sys_id'] ?? '', ]); } } $teamres = $this->teamTimekeepCalculation($params['month']); $timekeepres = $this->calculateTimekeepSalary($params['month']); $timekeepData = $this->mergeTimekeepSalaryData($teamres, $timekeepres); $timekeepInsert = []; foreach ($timekeepData as $item) { $remark = $item['remark'] ?? ''; if (!empty($item['type'])) { $remark = $remark !== '' ? $item['type'] . ',' . $remark : $item['type']; } $timekeepInsert[] = $this->buildSalarySummaryRow([ 'sczl_rq' => $item['sczl_rq'] . ' 00:00:00', 'bh' => $item['bh'], 'name' => $item['姓名'], 'time_salary' => $item['salary'], 'time_price' => $item['price'], 'time_duration' => $item['duration'], 'remark' => $remark, 'sys_id' => $params['sys_id'] ?? '', ]); } $insertData = array_merge($pieceData, $timekeepInsert); if (empty($insertData)) { return ['success' => false, 'message' => '无可保存的工资数据']; } db('糊盒工资汇总')->where('sczl_rq', 'like', $params['month'] . '%')->delete(); $sql = db('糊盒工资汇总')->fetchSql(true)->insertAll($insertData); $res = db()->query($sql); if ($res === false) { return ['success' => false, 'message' => '工资数据保存失败']; } return [ 'success' => true, 'message' => '成功', 'piece_count' => count($pieceData), 'timekeep_count' => count($timekeepInsert), 'total_count' => count($insertData), ]; } catch (\Exception $e) { return ['success' => false, 'message' => '糊盒工资计算失败: ' . $e->getMessage()]; } } protected function salaryCalculationClass($role) { // 构建查询对象 $query = db('糊盒报工班组')->alias('a')->where('a.id', $role); // 构建字段列表 $fieldParts = []; // 添加 bh 和 rate 字段 for ($i = 1; $i <= 30; $i++) { $fieldParts[] = "a.bh{$i}"; $fieldParts[] = "a.rate{$i}"; } // 添加 JOIN 和员工姓名字段 for ($i = 1; $i <= 30; $i++) { $table = 'b' . $i; $fieldParts[] = "{$table}.员工姓名 as 员工姓名{$i}"; $query->join("人事_基本资料 {$table}", "a.bh{$i} = {$table}.员工编号", 'left'); } // 设置字段 $query->field(implode(',', $fieldParts)); return $query->find(); } /** * 判断是否手工机台 * @param string $jtbh * @return bool */ protected function isManualMachine($jtbh) { return stripos((string)$jtbh, 'SG') !== false; } /** * 普通机台计件工资 * @param array $report * @param array $classResult * @return array */ protected function calculateRegularPieceWages(array $report, array $classResult) { $wageList = []; $salary = (float)$report['产量'] * (float)$report['price']; for ($i = 1; $i <= 30; $i++) { $bh = trim($classResult['bh' . $i] ?? ''); if ($bh === '' || $bh === '0000') { continue; } $wageList[] = [ 'bh' => $bh, 'name' => $classResult['员工姓名' . $i] ?? '', 'rate' => $classResult['rate' . $i] ?? '', 'wage' => floatval(number_format($salary * (float)$classResult['rate' . $i], 2, '.', '')), ]; } return $wageList; } /** * 手工机台计件超产工资 * @param array $report * @param array $classResult * @return array */ protected function calculateManualPieceWages(array $report, array $classResult) { $employees = []; for ($i = 1; $i <= 30; $i++) { $bh = trim($classResult['bh' . $i] ?? ''); if ($bh === '' || $bh === '0000') { continue; } $employees[] = [ 'bh' => $bh, 'name' => $classResult['员工姓名' . $i] ?? '', 'rate' => $classResult['rate' . $i] ?? '', ]; } if (empty($employees)) { return []; } $hireDates = db('人事_基本资料') ->whereIn('员工编号', array_column($employees, 'bh')) ->column('聘用日期', '员工编号'); $totalOutput = (float)$report['产量']; $dailyQuota = (float)$report['日定额']; if ($dailyQuota <= 0) { $dailyQuota = (float)$report['定额代号']; } $unitPrice = (float)$report['price']; $reportDate = $report['日期']; $totalCount = count($employees); $countGt3 = 0; $count8to15 = 0; $countGt15 = 0; $allPiece = true; foreach ($employees as &$employee) { $workDays = $this->getEmployeeTenureDays($employee['bh'], $reportDate, $hireDates); $employee['work_days'] = $workDays; if ($workDays > 3) { $countGt3++; } if ($workDays >= 8 && $workDays <= 15) { $count8to15++; } if ($workDays > 15) { $countGt15++; } if ($workDays <= 7) { $allPiece = false; } } unset($employee); $wageList = []; if ($allPiece) { $overPerPerson = $totalCount > 0 ? max(0, ($totalOutput - $dailyQuota * $totalCount) * $unitPrice / $totalCount) : 0; foreach ($employees as $employee) { $wageList[] = [ 'bh' => $employee['bh'], 'name' => $employee['name'], 'rate' => $employee['rate'], 'wage' => floatval(number_format($overPerPerson, 2, '.', '')), ]; } return $wageList; } $value1 = $countGt3 > 0 ? max(0, ($totalOutput - $dailyQuota * $countGt3) * $unitPrice) : 0; $halfShare = $countGt3 > 0 ? $value1 / $countGt3 / 2 : 0; $value2 = max(0, $value1 - $halfShare * $count8to15); $gt15Share = $countGt15 > 0 ? $value2 / $countGt15 : 0; foreach ($employees as $employee) { $workDays = $employee['work_days']; if ($workDays <= 7) { $wage = 0; } elseif ($workDays >= 8 && $workDays <= 15) { $wage = $halfShare; } elseif ($workDays > 15) { $wage = $gt15Share; } else { $wage = 0; } $wageList[] = [ 'bh' => $employee['bh'], 'name' => $employee['name'], 'rate' => $employee['rate'], 'wage' => floatval(number_format($wage, 2, '.', '')), ]; } return $wageList; } /** * 计算员工上班天数 * @param string $bh * @param string $reportDate * @param array $hireDates * @return int */ protected function getEmployeeTenureDays($bh, $reportDate, array $hireDates) { if (empty($hireDates[$bh])) { return 0; } $hireTime = strtotime(date('Y-m-d', strtotime($hireDates[$bh]))); $reportTime = strtotime(date('Y-m-d', strtotime($reportDate))); if ($hireTime === false || $reportTime === false || $reportTime < $hireTime) { return 0; } return (int)floor(($reportTime - $hireTime) / 86400) + 1; } /** * 班组计时工资计算 * @param string $month 月份 * @return array 班组计时工资数据 */ protected function teamTimekeepCalculation($month) { $bhFields = []; for ($i = 1; $i <= 30; $i++) { $bhFields[] = 'bh' . $i; } $list = db('糊盒班组计时') ->field(array_merge(['sczl_rq', 'type', 'duration', 'price', 'remark'], $bhFields)) ->where('sczl_rq', 'like', $month . '%') ->select(); if (empty($list)) { return []; } $employeeIds = []; foreach ($list as $row) { for ($i = 1; $i <= 30; $i++) { $bh = isset($row['bh' . $i]) ? trim($row['bh' . $i]) : ''; if ($bh !== '' && $bh !== '0000') { $employeeIds[$bh] = true; } } } $employeeNames = []; if (!empty($employeeIds)) { $employees = db('人事_基本资料') ->whereIn('员工编号', array_keys($employeeIds)) ->field('员工编号, rtrim(员工姓名) as 姓名') ->select(); foreach ($employees as $employee) { $employeeNames[$employee['员工编号']] = $employee['姓名']; } } $data = []; foreach ($list as $row) { $employees = []; for ($i = 1; $i <= 30; $i++) { $bh = isset($row['bh' . $i]) ? trim($row['bh' . $i]) : ''; if ($bh !== '' && $bh !== '0000') { $employees[] = $bh; } } if (empty($employees)) { continue; } $employeeCount = count($employees); $salaryPerEmployee = ((float)$row['duration'] * (float)$row['price']) / $employeeCount; $ymd = date('Ymd', strtotime($row['sczl_rq'])); foreach ($employees as $bh) { $name = $employeeNames[$bh] ?? ''; $key = $ymd . '-' . $bh . '-' . $name . '-' . $row['price']; $durationPerEmployee = (float)$row['duration'] / $employeeCount; if (isset($data[$key])) { $data[$key]['duration'] = floatval(number_format((float)$data[$key]['duration'] + $durationPerEmployee, 2, '.', '')); $data[$key]['salary'] = floatval(number_format($data[$key]['salary'] + $salaryPerEmployee, 2, '.', '')); if ($row['type'] !== '' && strpos($data[$key]['type'], $row['type']) === false) { $data[$key]['type'] = trim($data[$key]['type'] . ',' . $row['type'], ','); } if ($row['remark'] !== '' && strpos($data[$key]['remark'], $row['remark']) === false) { $data[$key]['remark'] = trim($data[$key]['remark'] . ',' . $row['remark'], ','); } continue; } $data[$key] = [ 'sczl_rq' => date('Y-m-d', strtotime($row['sczl_rq'])), 'type' => $row['type'], 'duration' => floatval(number_format($durationPerEmployee, 2, '.', '')), 'price' => $row['price'], 'remark' => $row['remark'], 'bh' => $bh, '姓名' => $name, 'salary' => floatval(number_format($salaryPerEmployee, 2, '.', '')), ]; } } return $data; } /** * 计算糊盒计时工资 * @param string $month 月份 * @return array 糊盒计时工资数据 */ protected function calculateTimekeepSalary($month) { $list = db('糊盒报工机时') ->field(['wgjs_rq', 'wgjs_bh1', 'wgjs_js1', 'wgjs_yy1', 'wgjs_je1', 'wgjs_bh2', 'wgjs_js2', 'wgjs_yy2', 'wgjs_je2', 'wgjs_bh3', 'wgjs_js3', 'wgjs_yy3', 'wgjs_je3', 'wgjs_bh4', 'wgjs_js4', 'wgjs_yy4', 'wgjs_je4', 'wgjs_bh5', 'wgjs_js5', 'wgjs_yy5', 'wgjs_je5', 'wgjs_bh6', 'wgjs_js6', 'wgjs_yy6', 'wgjs_je6']) ->where('wgjs_rq', 'like', $month . '%') ->select(); if (empty($list)) { return []; } $employeeIds = []; foreach ($list as $row) { for ($i = 1; $i <= 6; $i++) { $bh = isset($row['wgjs_bh' . $i]) ? trim($row['wgjs_bh' . $i]) : ''; if ($bh !== '') { $employeeIds[$bh] = true; } } } $employeeNames = []; if (!empty($employeeIds)) { $employees = db('人事_基本资料') ->whereIn('员工编号', array_keys($employeeIds)) ->field('员工编号, rtrim(员工姓名) as 姓名') ->select(); foreach ($employees as $employee) { $employeeNames[$employee['员工编号']] = $employee['姓名']; } } $data = []; foreach ($list as $row) { $ymd = date('Ymd', strtotime($row['wgjs_rq'])); $sczl_rq = date('Y-m-d', strtotime($row['wgjs_rq'])); for ($i = 1; $i <= 6; $i++) { $bh = isset($row['wgjs_bh' . $i]) ? trim($row['wgjs_bh' . $i]) : ''; if ($bh === '') { continue; } $duration = isset($row['wgjs_js' . $i]) ? (float)$row['wgjs_js' . $i] : 0; $type = isset($row['wgjs_yy' . $i]) ? trim($row['wgjs_yy' . $i]) : ''; $salary = isset($row['wgjs_je' . $i]) ? (float)$row['wgjs_je' . $i] : 0; $price = ''; $name = $employeeNames[$bh] ?? ''; $key = $ymd . '-' . $bh . '-' . $name . '-' . $price; if (isset($data[$key])) { $data[$key]['duration'] = floatval(number_format((float)$data[$key]['duration'] + $duration, 2, '.', '')); $data[$key]['salary'] = floatval(number_format((float)$data[$key]['salary'] + $salary, 2, '.', '')); if ($type !== '' && strpos($data[$key]['type'], $type) === false) { $data[$key]['type'] = trim($data[$key]['type'] . ',' . $type, ','); } continue; } $data[$key] = [ 'sczl_rq' => $sczl_rq, 'type' => $type, 'duration' => floatval(number_format($duration, 2, '.', '')), 'price' => '', 'remark' => '', 'bh' => $bh, '姓名' => $name, 'salary' => floatval(number_format($salary, 2, '.', '')), ]; } } return $data; } /** * 合并计时工资数据 * @param array $data1 * @param array $data2 * @return array */ protected function mergeTimekeepSalaryData(array $data1, array $data2) { $data = $data1; foreach ($data2 as $key => $item) { if (!isset($data[$key])) { $data[$key] = $item; continue; } $data[$key]['duration'] = floatval(number_format((float)$data[$key]['duration'] + (float)$item['duration'], 2, '.', '')); $data[$key]['salary'] = floatval(number_format((float)$data[$key]['salary'] + (float)$item['salary'], 2, '.', '')); if (!empty($item['type']) && strpos($data[$key]['type'], $item['type']) === false) { $data[$key]['type'] = trim($data[$key]['type'] . ',' . $item['type'], ','); } if (!empty($item['remark']) && strpos($data[$key]['remark'], $item['remark']) === false) { $data[$key]['remark'] = trim($data[$key]['remark'] . ',' . $item['remark'], ','); } } return $data; } /** * 构建工资汇总统一字段结构 * @param array $fields * @return array */ protected function buildSalarySummaryRow(array $fields = []) { $defaults = [ 'sczl_gdbh' => '', 'sczl_gxmc' => '', 'sczl_rq' => '', 'sczl_dedh' => '', 'sczl_cl' => 0, '工价系数' => '', '保养工时' => '', '装版工时' => '', '异常工时' => '', '设备运行工时' => '', 'sczl_jtbh' => '', 'cpdh' => '', 'cpmc' => '', 'bh' => '', 'rate' => '', 'name' => '', 'salary' => 0, 'time_salary' => 0, 'price' => 0, 'time_price' => 0, 'time_duration' => 0, 'remark' => '', 'sys_id' => '', 'sys_rq' => date('Y-m-d H:i:s'), ]; $row = array_merge($defaults, $fields); $decimalFields = ['sczl_cl', 'salary', 'time_salary', 'price', 'time_price', 'time_duration']; foreach ($decimalFields as $field) { if (!isset($row[$field]) || $row[$field] === '' || $row[$field] === null) { $row[$field] = 0; } else { $row[$field] = is_numeric($row[$field]) ? (float)$row[$field] : 0; } } return $row; } }