|
@@ -42,6 +42,8 @@ class ImportService extends Service
|
|
|
'dailyDwOrder', // 设备日工时单
|
|
'dailyDwOrder', // 设备日工时单
|
|
|
'leaveOrder', // 请假单
|
|
'leaveOrder', // 请假单
|
|
|
'overtimeOrder', // 加班单
|
|
'overtimeOrder', // 加班单
|
|
|
|
|
+ 'feeOrder', // 项目费用报销单
|
|
|
|
|
+ 'RDOrder', // 研发支出辅助帐
|
|
|
];
|
|
];
|
|
|
|
|
|
|
|
public function getTableTitleXls($data,$user){
|
|
public function getTableTitleXls($data,$user){
|
|
@@ -1518,134 +1520,6 @@ class ImportService extends Service
|
|
|
return [!empty($errors) ? implode('|', $errors) : "", $update_map, $dbEmps];
|
|
return [!empty($errors) ? implode('|', $errors) : "", $update_map, $dbEmps];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private function monthPwOrderCheck1(&$array, $user, $table_config)
|
|
|
|
|
- {
|
|
|
|
|
- $keys = array_column($table_config, 'key');
|
|
|
|
|
- $codeIdx = array_search('code', $keys);
|
|
|
|
|
- $monthIdx = array_search('month', $keys);
|
|
|
|
|
- $empIdx = array_search('employee_id', $keys);
|
|
|
|
|
-
|
|
|
|
|
- $numIdx = array_search('total_days', $keys);
|
|
|
|
|
- $num2Idx = array_search('rd_total_days', $keys);
|
|
|
|
|
- $num3Idx = array_search('total_hours', $keys);
|
|
|
|
|
- $num4Idx = array_search('rd_total_hours', $keys);
|
|
|
|
|
-
|
|
|
|
|
- // 1. 预加载基础数据
|
|
|
|
|
- $allEmpNumbers = array_filter(array_unique(array_column($array, $empIdx)));
|
|
|
|
|
- $dbEmps = Employee::where('del_time', 0)
|
|
|
|
|
- ->whereIn('number', $allEmpNumbers)
|
|
|
|
|
- ->where('top_depart_id', $user['top_depart_id'])
|
|
|
|
|
- ->pluck('id', 'number')->toArray();
|
|
|
|
|
-
|
|
|
|
|
- $allCodes = array_filter(array_unique(array_column($array, $codeIdx)));
|
|
|
|
|
- $dbOrders = DB::table('monthly_pw_order')
|
|
|
|
|
- ->whereIn('code', $allCodes)
|
|
|
|
|
- ->where('top_depart_id', $user['top_depart_id'])
|
|
|
|
|
- ->where('del_time', 0)
|
|
|
|
|
- ->get()->keyBy('code');
|
|
|
|
|
-
|
|
|
|
|
- $errors = [];
|
|
|
|
|
- $uniqueMonths = [];
|
|
|
|
|
-
|
|
|
|
|
- // --- 步骤 1:月份预处理 ---
|
|
|
|
|
- foreach ($array as $rowIndex => $row) {
|
|
|
|
|
- $valMonthRaw = trim($row[$monthIdx] ?? '');
|
|
|
|
|
- if ($valMonthRaw === '') continue;
|
|
|
|
|
-
|
|
|
|
|
- list($mStatus, $valMonthTs) = $this->convertExcelCellToDate($valMonthRaw);
|
|
|
|
|
- if (!$mStatus) {
|
|
|
|
|
- $errors[] = "第" . ($rowIndex + 1) . "行:月份格式错误({$valMonthRaw})";
|
|
|
|
|
- continue;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- $valMonthTs = strtotime(date('Y-m-01', $valMonthTs));
|
|
|
|
|
- $array[$rowIndex][$monthIdx] = $valMonthTs;
|
|
|
|
|
- $uniqueMonths[] = $valMonthTs;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 查重数据库中已有的月份
|
|
|
|
|
- $existingMonthsMap = [];
|
|
|
|
|
- if (!empty($uniqueMonths)) {
|
|
|
|
|
- $existingMonths = DB::table('monthly_pw_order')
|
|
|
|
|
- ->where('top_depart_id', $user['top_depart_id'])
|
|
|
|
|
- ->where('del_time', 0)
|
|
|
|
|
- ->whereIn('month', array_unique($uniqueMonths))
|
|
|
|
|
- ->pluck('month')
|
|
|
|
|
- ->toArray();
|
|
|
|
|
- $existingMonthsMap = array_fill_keys($existingMonths, true);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- $excelAggregator = [];
|
|
|
|
|
- $update_map = [];
|
|
|
|
|
- $monthToKeyMap = []; // 校验同一月份是否指向了多个 AggKey
|
|
|
|
|
-
|
|
|
|
|
- // --- 步骤 2:全量业务检查 ---
|
|
|
|
|
- foreach ($array as $rowIndex => $row) {
|
|
|
|
|
- $displayLine = $rowIndex + 1;
|
|
|
|
|
-
|
|
|
|
|
- $valCode = trim($row[$codeIdx] ?? '');
|
|
|
|
|
- $valMonthTs = $row[$monthIdx] ?? '';
|
|
|
|
|
- $valEmp = trim($row[$empIdx] ?? '');
|
|
|
|
|
-
|
|
|
|
|
- if (!is_numeric($valMonthTs)) continue;
|
|
|
|
|
-
|
|
|
|
|
- // 确定单据组标识
|
|
|
|
|
- $aggKey = $valCode ?: "NEW_ORDER_" . $valMonthTs;
|
|
|
|
|
-
|
|
|
|
|
- // B. 校验单据存在性 & 匹配主表 ID
|
|
|
|
|
- if ($valCode) {
|
|
|
|
|
- if (isset($dbOrders[$valCode])) {
|
|
|
|
|
- $dbOrder = $dbOrders[$valCode];
|
|
|
|
|
- if ($dbOrder->month != $valMonthTs) {
|
|
|
|
|
- $errors[] = "第{$displayLine}行:单据[{$valCode}]月份应为[" . date('Y-m', $dbOrder->month) . "],与导入不符";
|
|
|
|
|
- }
|
|
|
|
|
- $update_map[$rowIndex] = $dbOrder->id;
|
|
|
|
|
- }
|
|
|
|
|
- // 注意:如果填了 Code 但数据库没搜到,不进 update_map,会被下方视为“新增”
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // C. 【核心修正】月份唯一性拦截
|
|
|
|
|
- // 如果该行被判定为“新增”,但数据库里该月已经有单据了,直接报错
|
|
|
|
|
- if (!isset($update_map[$rowIndex])) {
|
|
|
|
|
- if (isset($existingMonthsMap[$valMonthTs])) {
|
|
|
|
|
- $errors[] = "第{$displayLine}行:月份[" . date('Y-m', $valMonthTs) . "]已存在单据,请填写编码编辑";
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // D. Excel 内部逻辑一致性
|
|
|
|
|
- // 确保同一个月份在同一个 Excel 里不会既有“单据 A”又有“单据 B”或者“新增单据”
|
|
|
|
|
- if (!isset($monthToKeyMap[$valMonthTs])) {
|
|
|
|
|
- $monthToKeyMap[$valMonthTs] = $aggKey;
|
|
|
|
|
- } elseif ($monthToKeyMap[$valMonthTs] !== $aggKey) {
|
|
|
|
|
- $errors[] = "第{$displayLine}行:同月份[" . date('Y-m', $valMonthTs) . "]在 Excel 中存在多组单据冲突";
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // E. 人员与单据内唯一性
|
|
|
|
|
- if (!isset($dbEmps[$valEmp])) {
|
|
|
|
|
- $errors[] = "第{$displayLine}行:工号[{$valEmp}]不存在";
|
|
|
|
|
- } else {
|
|
|
|
|
- if (isset($excelAggregator[$aggKey]['emps'][$valEmp])) {
|
|
|
|
|
- $errors[] = "第{$displayLine}行:人员[{$valEmp}]在同单据内重复";
|
|
|
|
|
- }
|
|
|
|
|
- $excelAggregator[$aggKey]['emps'][$valEmp] = true;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // G. 数字有效性校验
|
|
|
|
|
- $numFields = [
|
|
|
|
|
- $numIdx => '出勤天数', $num2Idx => '研发天数',
|
|
|
|
|
- $num3Idx => '出勤工时', $num4Idx => '研发工时'
|
|
|
|
|
- ];
|
|
|
|
|
- foreach ($numFields as $idx => $label) {
|
|
|
|
|
- $val = $row[$idx] ?? 0;
|
|
|
|
|
- $res = $this->checkNumber($val, 2, 'non-negative');
|
|
|
|
|
- if (!$res['valid']) $errors[] = "第{$displayLine}行{$label}:" . $res['error'];
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- $error_string = !empty($errors) ? implode('|', $errors) : "";
|
|
|
|
|
- return [$error_string, $update_map, $dbEmps];
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
// 设备月度工时单
|
|
// 设备月度工时单
|
|
|
public function monthDwOrderImport($array, $user, $other_param)
|
|
public function monthDwOrderImport($array, $user, $other_param)
|
|
|
{
|
|
{
|
|
@@ -1907,129 +1781,6 @@ class ImportService extends Service
|
|
|
return [$error_string, $update_map, $dbDevs];
|
|
return [$error_string, $update_map, $dbDevs];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private function monthDwOrderCheck1(&$array, $user, $table_config)
|
|
|
|
|
- {
|
|
|
|
|
- $keys = array_column($table_config, 'key');
|
|
|
|
|
- $codeIdx = array_search('code', $keys);
|
|
|
|
|
- $monthIdx = array_search('month', $keys);
|
|
|
|
|
- $devIdx = array_search('device_id', $keys);
|
|
|
|
|
-
|
|
|
|
|
- $numIdx = array_search('total_days', $keys);
|
|
|
|
|
- $num2Idx = array_search('rd_total_days', $keys);
|
|
|
|
|
- $num3Idx = array_search('total_hours', $keys);
|
|
|
|
|
- $num4Idx = array_search('rd_total_hours', $keys);
|
|
|
|
|
-
|
|
|
|
|
- // 1. 基础数据预加载
|
|
|
|
|
- $allDevCodes = array_filter(array_unique(array_column($array, $devIdx)));
|
|
|
|
|
- $dbDevs = Device::where('del_time', 0)
|
|
|
|
|
- ->whereIn('code', $allDevCodes)
|
|
|
|
|
- ->where('top_depart_id', $user['top_depart_id'])
|
|
|
|
|
- ->pluck('id', 'code')->toArray();
|
|
|
|
|
-
|
|
|
|
|
- $allCodes = array_filter(array_unique(array_column($array, $codeIdx)));
|
|
|
|
|
- $dbOrders = DB::table('monthly_dw_order')
|
|
|
|
|
- ->whereIn('code', $allCodes)
|
|
|
|
|
- ->where('top_depart_id', $user['top_depart_id'])
|
|
|
|
|
- ->where('del_time', 0)
|
|
|
|
|
- ->get()->keyBy('code');
|
|
|
|
|
-
|
|
|
|
|
- $errors = [];
|
|
|
|
|
- $uniqueMonths = [];
|
|
|
|
|
-
|
|
|
|
|
- // --- 步骤 1:预处理月份时间戳 ---
|
|
|
|
|
- foreach ($array as $rowIndex => $row) {
|
|
|
|
|
- $valMonthRaw = trim($row[$monthIdx] ?? '');
|
|
|
|
|
- if ($valMonthRaw === '') continue;
|
|
|
|
|
-
|
|
|
|
|
- list($mStatus, $valMonthTs) = $this->convertExcelCellToDate($valMonthRaw);
|
|
|
|
|
- if (!$mStatus) {
|
|
|
|
|
- $errors[] = "第" . ($rowIndex + 1) . "行:月份格式错误({$valMonthRaw})";
|
|
|
|
|
- continue;
|
|
|
|
|
- }
|
|
|
|
|
- $valMonthTs = strtotime(date('Y-m-01', $valMonthTs));
|
|
|
|
|
- $array[$rowIndex][$monthIdx] = $valMonthTs;
|
|
|
|
|
- $uniqueMonths[] = $valMonthTs;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 查询数据库中已存在的月份单据
|
|
|
|
|
- $existingMonthsMap = [];
|
|
|
|
|
- if (!empty($uniqueMonths)) {
|
|
|
|
|
- $existingMonths = DB::table('monthly_dw_order')
|
|
|
|
|
- ->where('top_depart_id', $user['top_depart_id'])
|
|
|
|
|
- ->where('del_time', 0)
|
|
|
|
|
- ->whereIn('month', array_unique($uniqueMonths))
|
|
|
|
|
- ->pluck('month')
|
|
|
|
|
- ->toArray();
|
|
|
|
|
- $existingMonthsMap = array_fill_keys($existingMonths, true);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- $excelAggregator = [];
|
|
|
|
|
- $update_map = [];
|
|
|
|
|
- $monthToKeyMap = []; // 校验 Excel 内部月份是否指向了多个单据
|
|
|
|
|
-
|
|
|
|
|
- // --- 步骤 2:核心校验循环 ---
|
|
|
|
|
- foreach ($array as $rowIndex => $row) {
|
|
|
|
|
- $displayLine = $rowIndex + 1;
|
|
|
|
|
- $valCode = trim($row[$codeIdx] ?? '');
|
|
|
|
|
- $valMonthTs = $row[$monthIdx] ?? '';
|
|
|
|
|
- $valDev = trim($row[$devIdx] ?? '');
|
|
|
|
|
-
|
|
|
|
|
- if (!is_numeric($valMonthTs)) continue;
|
|
|
|
|
-
|
|
|
|
|
- // A. 确定该行的归组 Key
|
|
|
|
|
- $aggKey = $valCode ?: "NEW_ORDER_" . $valMonthTs;
|
|
|
|
|
-
|
|
|
|
|
- // B. 校验单据与月份一致性 & 确定 Update 映射
|
|
|
|
|
- if ($valCode) {
|
|
|
|
|
- if (isset($dbOrders[$valCode])) {
|
|
|
|
|
- $dbOrder = $dbOrders[$valCode];
|
|
|
|
|
- if ($dbOrder->month != $valMonthTs) {
|
|
|
|
|
- $errors[] = "第{$displayLine}行:单据[{$valCode}]对应月份为[" . date('Y-m', $dbOrder->month) . "],与 Excel 不符";
|
|
|
|
|
- }
|
|
|
|
|
- $update_map[$rowIndex] = $dbOrder->id;
|
|
|
|
|
- } else {
|
|
|
|
|
- // 如果填了编码但在数据库没找到,它会被视为“新增”,需进入下方的月份查重
|
|
|
|
|
- // 这里暂不报错,由下方的唯一性检查拦截
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // C. 【关键修正】月份唯一单据校验
|
|
|
|
|
- // 如果系统判定该行是“新增”(没进 update_map),且月份已存在,则拦截
|
|
|
|
|
- if (!isset($update_map[$rowIndex])) {
|
|
|
|
|
- if (isset($existingMonthsMap[$valMonthTs])) {
|
|
|
|
|
- $errors[] = "第{$displayLine}行:月份[" . date('Y-m', $valMonthTs) . "]已存在单据,请填写正确的单据编码进行编辑";
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // D. Excel 内部一致性校验
|
|
|
|
|
- // 防止 Excel 里同一个月出现了两个不同的 aggKey(例如一个填了码,一个没填)
|
|
|
|
|
- if (!isset($monthToKeyMap[$valMonthTs])) {
|
|
|
|
|
- $monthToKeyMap[$valMonthTs] = $aggKey;
|
|
|
|
|
- } elseif ($monthToKeyMap[$valMonthTs] !== $aggKey) {
|
|
|
|
|
- $errors[] = "第{$displayLine}行:同一个月份[" . date('Y-m', $valMonthTs) . "]在 Excel 中指向了不同的单据组";
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // E. 设备存在性与唯一性
|
|
|
|
|
- if (!isset($dbDevs[$valDev])) {
|
|
|
|
|
- $errors[] = "第{$displayLine}行:资产编码[{$valDev}]不存在";
|
|
|
|
|
- } else {
|
|
|
|
|
- if (isset($excelAggregator[$aggKey]['devs'][$valDev])) {
|
|
|
|
|
- $errors[] = "第{$displayLine}行:资产编码[{$valDev}]在同单据中重复";
|
|
|
|
|
- }
|
|
|
|
|
- $excelAggregator[$aggKey]['devs'][$valDev] = true;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // G. 数字格式校验 (checkNumber 方法)
|
|
|
|
|
- foreach ([$numIdx => '天数', $num2Idx => '研发天数', $num3Idx => '工时', $num4Idx => '研发工时'] as $idx => $label) {
|
|
|
|
|
- $res = $this->checkNumber($row[$idx] ?? 0, 2, 'non-negative');
|
|
|
|
|
- if (!$res['valid']) $errors[] = "第{$displayLine}行{$label}:" . $res['error'];
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- $error_string = !empty($errors) ? implode('|', $errors) : "";
|
|
|
|
|
- return [$error_string, $update_map, $dbDevs];
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
// 人员月度工资单
|
|
// 人员月度工资单
|
|
|
public function monthPsOrderImport($array, $user, $other_param)
|
|
public function monthPsOrderImport($array, $user, $other_param)
|
|
|
{
|
|
{
|
|
@@ -3782,6 +3533,249 @@ class ImportService extends Service
|
|
|
return [!empty($errors) ? implode('|', $errors) : "", $update_map, $dbEmps];
|
|
return [!empty($errors) ? implode('|', $errors) : "", $update_map, $dbEmps];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // 项目费用报销单月度导入 ------------------------------
|
|
|
|
|
+ // 项目费用报销单月度导入 ------------------------------
|
|
|
|
|
+ public function feeOrderImport($array, $user, $other_param)
|
|
|
|
|
+ {
|
|
|
|
|
+ $upload = $array[0];
|
|
|
|
|
+ list($status, $msg) = $this->compareTableAndReturn($upload, $other_param);
|
|
|
|
|
+ if (!$status) return [false, $msg];
|
|
|
|
|
+ $table_config = $msg;
|
|
|
|
|
+
|
|
|
|
|
+ unset($array[0]);
|
|
|
|
|
+ if (empty($array)) return [false, '导入数据不能为空'];
|
|
|
|
|
+
|
|
|
|
|
+ // 1. 基础校验(格式、必填项等)
|
|
|
|
|
+ list($array, $error) = $this->checkCommon($array, $table_config);
|
|
|
|
|
+ if (!empty($error)) return [0, $error];
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 业务详细校验 (获取 update_map 和 基础档案映射)
|
|
|
|
|
+ // 此时 claim_date 会在 check 方法内部被转换为时间戳并校验月份归属
|
|
|
|
|
+ list($error, $update_map, $maps) = $this->feeOrderCheck($array, $user, $table_config);
|
|
|
|
|
+ if (!empty($error)) return [0, $error];
|
|
|
|
|
+
|
|
|
|
|
+ $keys = array_column($table_config, 'key');
|
|
|
|
|
+ $codeIdx = array_search('code', $keys);
|
|
|
|
|
+ $monthIdx = array_search('month', $keys);
|
|
|
|
|
+
|
|
|
|
|
+ // --- 步骤 1: 数据聚合分组 ---
|
|
|
|
|
+ $groups = [];
|
|
|
|
|
+ foreach ($array as $rowIndex => $row) {
|
|
|
|
|
+ $cCode = trim($row[$codeIdx] ?? '');
|
|
|
|
|
+ $cMonthTs = $row[$monthIdx];
|
|
|
|
|
+
|
|
|
|
|
+ // 聚合 Key:有编码用编码,没编码用月份
|
|
|
|
|
+ $aggKey = $cCode ?: "MONTH_" . $cMonthTs;
|
|
|
|
|
+
|
|
|
|
|
+ if (!isset($groups[$aggKey])) {
|
|
|
|
|
+ $groups[$aggKey] = [
|
|
|
|
|
+ 'main_id' => $update_map[$rowIndex] ?? 0,
|
|
|
|
|
+ 'code' => $cCode,
|
|
|
|
|
+ 'month' => $cMonthTs,
|
|
|
|
|
+ 'details' => []
|
|
|
|
|
+ ];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 准备详情行数据
|
|
|
|
|
+ $detailTmp = [];
|
|
|
|
|
+ foreach ($table_config as $k => $conf) {
|
|
|
|
|
+ if (!$conf['is_main']) {
|
|
|
|
|
+ $fieldKey = $conf['key'];
|
|
|
|
|
+ // 跳过仅用于展示的名称字段
|
|
|
|
|
+ if (in_array($fieldKey, ['employee_title', 'item_title', 'fee_title'])) continue;
|
|
|
|
|
+
|
|
|
|
|
+ $fieldVal = $row[$k];
|
|
|
|
|
+
|
|
|
|
|
+ // 转换编号为 ID
|
|
|
|
|
+ if ($fieldKey == 'employee_id') $fieldVal = $maps['emps'][$fieldVal] ?? 0;
|
|
|
|
|
+ if ($fieldKey == 'item_id') $fieldVal = $maps['items'][$fieldVal] ?? 0;
|
|
|
|
|
+ if ($fieldKey == 'fee_id') $fieldVal = $maps['fees'][$fieldVal] ?? 0;
|
|
|
|
|
+
|
|
|
|
|
+ // 转换枚举值(委托方式、是否定位到人)
|
|
|
|
|
+ if ($fieldKey == 'entrust_type') {
|
|
|
|
|
+ $fieldVal = array_search($fieldVal, \App\Model\ExpenseClaimsDetails::State_Type) ?: 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ if ($fieldKey == 'expense_type') {
|
|
|
|
|
+ $fieldVal = array_search($fieldVal, \App\Model\ExpenseClaimsDetails::State_Type_2) ?: 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 注意:claim_date 已经在 check 方法里转成了时间戳,这里直接赋值即可
|
|
|
|
|
+ $detailTmp[$fieldKey] = $fieldVal;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ $groups[$aggKey]['details'][] = $detailTmp;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // --- 步骤 2: 事务写入 ---
|
|
|
|
|
+ DB::beginTransaction();
|
|
|
|
|
+ try {
|
|
|
|
|
+ $time = time();
|
|
|
|
|
+ foreach ($groups as $group) {
|
|
|
|
|
+ $mainId = $group['main_id'];
|
|
|
|
|
+
|
|
|
|
|
+ if ($mainId > 0) {
|
|
|
|
|
+ // 编辑:逻辑删除旧明细
|
|
|
|
|
+ DB::table('expense_claims_details')->where('del_time', 0)
|
|
|
|
|
+ ->where('expense_claims_id', $mainId)
|
|
|
|
|
+ ->update(['del_time' => $time]);
|
|
|
|
|
+
|
|
|
|
|
+ // 更新主表更新时间
|
|
|
|
|
+ DB::table('expense_claims')->where('id', $mainId)->update(['upd_time' => $time]);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 新增:生成单号
|
|
|
|
|
+ $newCode = $this->generateBillNo([
|
|
|
|
|
+ 'top_depart_id' => $user['top_depart_id'],
|
|
|
|
|
+ 'type' => \App\Model\ExpenseClaims::Order_type,
|
|
|
|
|
+ 'period' => date("Ym", $group['month'])
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ $mainId = DB::table('expense_claims')->insertGetId([
|
|
|
|
|
+ 'code' => $newCode,
|
|
|
|
|
+ 'month' => $group['month'],
|
|
|
|
|
+ 'top_depart_id' => $user['top_depart_id'],
|
|
|
|
|
+ 'crt_id' => $user['id'],
|
|
|
|
|
+ 'crt_time' => $time,
|
|
|
|
|
+ 'upd_time' => $time,
|
|
|
|
|
+ 'del_time' => 0
|
|
|
|
|
+ ]);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 批量插入详情
|
|
|
|
|
+ $insertDetails = [];
|
|
|
|
|
+ foreach ($group['details'] as $detail) {
|
|
|
|
|
+ $detail['expense_claims_id'] = $mainId;
|
|
|
|
|
+ $detail['top_depart_id'] = $user['top_depart_id'];
|
|
|
|
|
+ $detail['crt_id'] = $user['id'];
|
|
|
|
|
+ $detail['crt_time'] = $time;
|
|
|
|
|
+ $detail['upd_time'] = $time;
|
|
|
|
|
+ $detail['del_time'] = 0;
|
|
|
|
|
+ $insertDetails[] = $detail;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (!empty($insertDetails)) {
|
|
|
|
|
+ DB::table('expense_claims_details')->insert($insertDetails);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ DB::commit();
|
|
|
|
|
+ } catch (\Exception $e) {
|
|
|
|
|
+ DB::rollBack();
|
|
|
|
|
+ return [false, "写入失败:" . $e->getMessage() . " (行号:" . $e->getLine() . ")"];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return [true, ''];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private function feeOrderCheck(&$array, $user, $table_config)
|
|
|
|
|
+ {
|
|
|
|
|
+ $keys = array_column($table_config, 'key');
|
|
|
|
|
+ $codeIdx = array_search('code', $keys);
|
|
|
|
|
+ $monthIdx = array_search('month', $keys);
|
|
|
|
|
+ $empIdx = array_search('employee_id', $keys);
|
|
|
|
|
+ $itemIdx = array_search('item_id', $keys);
|
|
|
|
|
+ $feeIdx = array_search('fee_id', $keys);
|
|
|
|
|
+ $claimDateIdx = array_search('claim_date', $keys);
|
|
|
|
|
+
|
|
|
|
|
+ $topDepartId = $user['top_depart_id'];
|
|
|
|
|
+ $errors = [];
|
|
|
|
|
+
|
|
|
|
|
+ $allEmpNos = []; $allItemCodes = []; $allFeeCodes = []; $allMonthsTs = []; $allCodes = [];
|
|
|
|
|
+
|
|
|
|
|
+ // --- 1. 预处理:日期转换与基础编号提取 ---
|
|
|
|
|
+ foreach ($array as $rowIndex => $row) {
|
|
|
|
|
+ $line = $rowIndex + 1;
|
|
|
|
|
+
|
|
|
|
|
+ // A. 报销主月份处理
|
|
|
|
|
+ $valMonthRaw = trim($row[$monthIdx] ?? '');
|
|
|
|
|
+ list($mStatus, $valMonthTs) = $this->convertExcelCellToDate($valMonthRaw);
|
|
|
|
|
+ if (!$mStatus) {
|
|
|
|
|
+ $errors[] = "第{$line}行:月份格式错误";
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ $valMonthTs = strtotime(date('Y-m-01', $valMonthTs));
|
|
|
|
|
+ $array[$rowIndex][$monthIdx] = $valMonthTs; // 回写转换后的时间戳
|
|
|
|
|
+ $allMonthsTs[] = $valMonthTs;
|
|
|
|
|
+
|
|
|
|
|
+ // B. 费用产生日期校验 (claim_date)
|
|
|
|
|
+ $valClaimDateRaw = trim($row[$claimDateIdx] ?? '');
|
|
|
|
|
+ if (empty($valClaimDateRaw)) {
|
|
|
|
|
+ $errors[] = "第{$line}行:费用产生日期不能为空";
|
|
|
|
|
+ } else {
|
|
|
|
|
+ list($dStatus, $dTs) = $this->convertExcelCellToDate($valClaimDateRaw);
|
|
|
|
|
+ if (!$dStatus) {
|
|
|
|
|
+ $errors[] = "第{$line}行:费用产生日期格式错误";
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 核心逻辑:判断产生日期是否在主月份内
|
|
|
|
|
+ $monthStr = date('Y-m', $valMonthTs);
|
|
|
|
|
+ $claimMonthStr = date('Y-m', $dTs);
|
|
|
|
|
+ if ($monthStr !== $claimMonthStr) {
|
|
|
|
|
+ $errors[] = "第{$line}行:产生日期[{$claimMonthStr}]与报销月份[{$monthStr}]不符";
|
|
|
|
|
+ }
|
|
|
|
|
+ $array[$rowIndex][$claimDateIdx] = $dTs; // 回写转换后的时间戳
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // C. 提取其他编号
|
|
|
|
|
+ if (!empty($row[$empIdx])) $allEmpNos[] = trim($row[$empIdx]);
|
|
|
|
|
+ if (!empty($row[$itemIdx])) $allItemCodes[] = trim($row[$itemIdx]);
|
|
|
|
|
+ if (!empty($row[$feeIdx])) $allFeeCodes[] = trim($row[$feeIdx]);
|
|
|
|
|
+ if (!empty($row[$codeIdx])) $allCodes[] = trim($row[$codeIdx]);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (!empty($errors)) return [implode('|', $errors), [], []];
|
|
|
|
|
+
|
|
|
|
|
+ // --- 2. 批量预加载档案映射 ---
|
|
|
|
|
+ $dbEmps = DB::table('employee')->where('del_time', 0)->where('top_depart_id', $topDepartId)
|
|
|
|
|
+ ->whereIn('number', array_unique($allEmpNos))->pluck('id', 'number')->toArray();
|
|
|
|
|
+
|
|
|
|
|
+ $dbItems = DB::table('item')->where('del_time', 0)->where('top_depart_id', $topDepartId)
|
|
|
|
|
+ ->whereIn('code', array_unique($allItemCodes))->pluck('id', 'code')->toArray();
|
|
|
|
|
+
|
|
|
|
|
+ $dbFees = DB::table('fee')->where('del_time', 0)->where('top_depart_id', $topDepartId)
|
|
|
|
|
+ ->whereIn('code', array_unique($allFeeCodes))->pluck('id', 'code')->toArray();
|
|
|
|
|
+
|
|
|
|
|
+ $existingMonthsMap = DB::table('expense_claims')->where('del_time', 0)->where('top_depart_id', $topDepartId)
|
|
|
|
|
+ ->whereIn('month', array_unique($allMonthsTs))->pluck('code', 'month')->toArray();
|
|
|
|
|
+
|
|
|
|
|
+ $dbOrdersByCode = DB::table('expense_claims')->where('del_time', 0)->where('top_depart_id', $topDepartId)
|
|
|
|
|
+ ->whereIn('code', array_unique($allCodes))->get()->keyBy('code');
|
|
|
|
|
+
|
|
|
|
|
+ // --- 3. 逐行校验档案存在性与单据逻辑 ---
|
|
|
|
|
+ $update_map = [];
|
|
|
|
|
+ foreach ($array as $rowIndex => $row) {
|
|
|
|
|
+ $line = $rowIndex + 1;
|
|
|
|
|
+ $valCode = trim($row[$codeIdx] ?? '');
|
|
|
|
|
+ $valMonthTs = $row[$monthIdx];
|
|
|
|
|
+
|
|
|
|
|
+ if (!empty($row[$empIdx]) && !isset($dbEmps[trim($row[$empIdx])])) {
|
|
|
|
|
+ $errors[] = "第{$line}行:工号[{$row[$empIdx]}]不存在";
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!isset($dbItems[trim($row[$itemIdx])])) {
|
|
|
|
|
+ $errors[] = "第{$line}行:项目编号[{$row[$itemIdx]}]不存在";
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!isset($dbFees[trim($row[$feeIdx])])) {
|
|
|
|
|
+ $errors[] = "第{$line}行:费用类型编号[{$row[$feeIdx]}]不存在";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ($valCode !== '') {
|
|
|
|
|
+ if (isset($dbOrdersByCode[$valCode])) {
|
|
|
|
|
+ if ($dbOrdersByCode[$valCode]->month != $valMonthTs) {
|
|
|
|
|
+ $errors[] = "第{$line}行:单据[{$valCode}]对应月份为" . date('Y-m', $dbOrdersByCode[$valCode]->month) . ",Excel中月份不符";
|
|
|
|
|
+ }
|
|
|
|
|
+ $update_map[$rowIndex] = $dbOrdersByCode[$valCode]->id;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ $errors[] = "第{$line}行:填写的单据编码[{$valCode}]系统中不存在";
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ if (isset($existingMonthsMap[$valMonthTs])) {
|
|
|
|
|
+ $errors[] = "第{$line}行:月份[" . date('Y-m', $valMonthTs) . "]已存在单据[{$existingMonthsMap[$valMonthTs]}],请填写该单号进行编辑";
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $maps = ['emps' => $dbEmps, 'items' => $dbItems, 'fees' => $dbFees];
|
|
|
|
|
+ return [!empty($errors) ? implode('|', $errors) : "", $update_map, $maps];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 解析并校验时间
|
|
* 解析并校验时间
|
|
|
*/
|
|
*/
|