shjEightService = $shjEightService; } /** * SHJ-10 財政年度売上集計処理メイン実行 * * 処理フロー (todo/SHJ-10/SHJ-10.txt): * 【処理1】集計対象を設定する * 【処理2】駐輪場マスタを取得する * 【判断1】取得件数判定 * 【処理3】車種区分毎に算出する * 【判断2】取得判定 * 【処理4】売上集計結果を削除→登録する * 【処理5】バッチ処理ログを作成し、情報不備がある場合のみオペレータキューを作成する * * @param string $type 集計種別(yearly/monthly) * @param string $target 集計対象 * @param array $fiscalPeriod 財政期間情報 * @return array 処理結果 */ public function executeFiscalEarningsAggregation(string $type, string $target, array $fiscalPeriod): array { $statusComments = []; // 内部変数.ステータスコメント $dataIntegrityIssues = []; // 内部変数.情報不備 try { // 【処理1】集計対象を設定する(財政年度ベース) $aggregationTarget = $this->setFiscalAggregationTarget($fiscalPeriod); Log::info('SHJ-10 売上集計処理開始', [ 'type' => $type, 'target' => $target, 'fiscal_period' => $fiscalPeriod, 'aggregation_target' => $aggregationTarget ]); // 【処理2】駐輪場マスタを取得する $parkInfo = $this->getParkInformation(); // 【判断1】取得件数判定 if (empty($parkInfo)) { $typeLabel = $this->getTypeLabel($type); $statusComment = "売上集計{$typeLabel}:駐輪場マスタが存在していません。"; $statusComments[] = $statusComment; // 【処理5】オペレータキュー作成 $this->createOperatorQueue($statusComment, null); // SHJ-8 バッチ処理ログ作成 $this->callShjEight('SHJ-10売上集計(年次・月次)', 'success', $statusComment); return [ 'success' => true, 'message' => $statusComment, 'processed_parks' => 0, 'summary_records' => 0 ]; } // 【処理3】車種区分毎に算出する & 【処理4】売上集計結果を削除→登録する $summaryRecords = 0; $processedParks = 0; foreach ($parkInfo as $park) { $result = $this->processFiscalEarningsForPark($park, $aggregationTarget, $fiscalPeriod); $processedParks++; $summaryRecords += $result['summary_records']; // 対象データなしの場合のステータスコメント収集 if (!empty($result['no_data_message'])) { $statusComments[] = $result['no_data_message']; } // 情報不備を収集("なし"でない場合) if ($result['data_integrity_issue'] !== '情報不備:なし') { $dataIntegrityIssues[] = $result['data_integrity_issue']; } } // 最終ステータスコメント生成 $typeLabel = $this->getTypeLabel($type); $finalStatusComment = "売上集計{$typeLabel}:対象={$fiscalPeriod['target_label']}、駐輪場数={$processedParks}、集計レコード数={$summaryRecords}"; if (!empty($dataIntegrityIssues)) { $finalStatusComment .= "、情報不備=" . implode('、', $dataIntegrityIssues); } // 【処理5】オペレータキュー作成 // ※ 駐輪場単位で既に作成済み(processFiscalEarningsForPark内で情報不備検出時に実施) if (!empty($dataIntegrityIssues)) { Log::warning('SHJ-10 情報不備検出', [ 'issues' => $dataIntegrityIssues ]); } // SHJ-8 バッチ処理ログ作成 $this->callShjEight('SHJ-10売上集計(年次・月次)', 'success', $finalStatusComment); Log::info('SHJ-10 売上集計処理完了', [ 'processed_parks' => $processedParks, 'summary_records' => $summaryRecords, 'data_integrity_issues' => count($dataIntegrityIssues), 'no_data_parks' => count($statusComments) ]); return [ 'success' => true, 'message' => 'SHJ-10 売上集計処理が正常に完了しました', 'processed_parks' => $processedParks, 'summary_records' => $summaryRecords, 'data_integrity_issues' => count($dataIntegrityIssues) ]; } catch (\Exception $e) { $typeLabel = $this->getTypeLabel($type ?? 'unknown'); $errorMessage = "売上集計{$typeLabel}:エラー発生 - " . $e->getMessage(); // SHJ-8 バッチ処理ログ作成(エラー時も作成) try { $this->callShjEight('SHJ-10売上集計(年次・月次)', 'error', $errorMessage); } catch (\Exception $shjException) { Log::error('SHJ-8呼び出しエラー', ['error' => $shjException->getMessage()]); } Log::error('SHJ-10 売上集計処理エラー', [ 'exception' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return [ 'success' => false, 'message' => $errorMessage, 'details' => $e->getMessage() ]; } } /** * 【処理1】財政年度集計対象を設定する * * @param array $fiscalPeriod 財政期間情報 * @return array 集計対象情報 */ private function setFiscalAggregationTarget(array $fiscalPeriod): array { return [ 'type' => $fiscalPeriod['type'], 'start_date' => $fiscalPeriod['start_date'], 'end_date' => $fiscalPeriod['end_date'], 'summary_type' => $fiscalPeriod['summary_type'], 'fiscal_year' => $fiscalPeriod['fiscal_year'], 'target_label' => $fiscalPeriod['target_label'] ]; } /** * 【処理2】駐輪場マスタを取得する * * @return array 駐輪場情報 */ private function getParkInformation(): array { try { $parkInfo = DB::table('park') ->select(['park_id', 'park_name']) ->where('park_close_flag', '<>', 1) ->orderBy('park_ruby') ->get() ->toArray(); Log::info('駐輪場マスタ取得完了', [ 'park_count' => count($parkInfo) ]); return $parkInfo; } catch (\Exception $e) { Log::error('駐輪場マスタ取得エラー', [ 'error' => $e->getMessage() ]); throw $e; } } /** * 駐輪場毎の財政年度売上集計処理 * * @param object $park 駐輪場情報 * @param array $aggregationTarget 集計対象 * @param array $fiscalPeriod 財政期間情報 * @return array 処理結果 ['summary_records' => int, 'data_integrity_issue' => string, 'no_data_message' => string|null] */ private function processFiscalEarningsForPark($park, array $aggregationTarget, array $fiscalPeriod): array { try { $startDate = $aggregationTarget['start_date']; $endDate = $aggregationTarget['end_date']; // 0. 情報不備チェック $dataIntegrityIssue = $this->checkDataIntegrity($park->park_id, $startDate, $endDate); // 情報不備がある場合、駐輪場単位でオペレータキュー作成(仕様 todo/SHJ-10/SHJ-10.txt:289-299) if ($dataIntegrityIssue !== '情報不備:なし') { $this->createOperatorQueue($dataIntegrityIssue, $park->park_id); } // ① 定期契約データ取得(車種区分・分類名1・定期有効月数毎) $regularData = $this->calculateRegularEarnings($park->park_id, $startDate, $endDate); // ② 一時金データ取得(車種毎) $lumpsumData = $this->calculateLumpsumEarnings($park->park_id, $startDate, $endDate); // ③ 解約返戻金データ取得(車種区分毎) $refundData = $this->calculateRefundEarnings($park->park_id, $startDate, $endDate); // ④ 再発行データ取得(車種区分毎) $reissueData = $this->calculateReissueCount($park->park_id, $startDate, $endDate); // 【判断2】データがいずれかあれば【処理4】へ if (empty($regularData) && empty($lumpsumData) && empty($refundData) && empty($reissueData)) { // 対象データなし - 仕様 todo/SHJ-10/SHJ-10.txt:209-211 $typeLabel = $this->getTypeLabel($aggregationTarget['type']); $noDataMessage = "売上集計{$typeLabel}:{$startDate}~{$endDate}/駐輪場:{$park->park_name}:売上データが存在しません。"; return [ 'summary_records' => 0, 'data_integrity_issue' => $dataIntegrityIssue, 'no_data_message' => $noDataMessage ]; } // 【処理4】既存の売上集計結果を削除 $this->deleteExistingFiscalSummary($park->park_id, $aggregationTarget); // 【処理4】売上集計結果を登録 $summaryRecords = 0; // ① 定期契約データがある場合:同じ組合せ(psection×usertype×months)を統合 $mergedRegularData = $this->mergeRegularDataByGroup($regularData); foreach ($mergedRegularData as $key => $mergedRow) { $this->createFiscalEarningsSummary($park, $mergedRow, $aggregationTarget, $fiscalPeriod, 'regular'); $summaryRecords++; } // ②③④ 一時金・解約・再発行データがある場合(車種区分毎に集約) $otherDataByPsection = $this->mergeOtherEarningsData($lumpsumData, $refundData, $reissueData); foreach ($otherDataByPsection as $psectionId => $data) { $this->createFiscalEarningsSummary($park, $data, $aggregationTarget, $fiscalPeriod, 'other'); $summaryRecords++; } Log::info('駐輪場売上集計完了', [ 'park_id' => $park->park_id, 'park_name' => $park->park_name, 'summary_records' => $summaryRecords, 'data_integrity_issue' => $dataIntegrityIssue ]); return [ 'summary_records' => $summaryRecords, 'data_integrity_issue' => $dataIntegrityIssue, 'no_data_message' => null ]; } catch (\Exception $e) { Log::error('駐輪場売上集計エラー', [ 'park_id' => $park->park_id, 'error' => $e->getMessage() ]); throw $e; } } /** * 0. 情報不備チェック(期間集計版) * * 仕様 todo/SHJ-10/SHJ-10.txt:77-101 * * @param int $parkId 駐輪場ID * @param string $startDate 集計開始日(YYYY-MM-DD) * @param string $endDate 集計終了日(YYYY-MM-DD) * @return string 情報不備メッセージ(仕様フォーマット:"情報不備:xxx" or "情報不備:なし") */ private function checkDataIntegrity(int $parkId, string $startDate, string $endDate): string { $incompleteContracts = DB::table('regular_contract') ->select('contract_id') ->where('park_id', $parkId) ->where('contract_flag', 1) ->whereBetween(DB::raw('DATE(contract_payment_day)'), [$startDate, $endDate]) ->where(function($query) { $query->whereNull('update_flag') ->orWhereNull('psection_id') ->orWhereNull('enable_months'); }) ->pluck('contract_id') ->toArray(); if (empty($incompleteContracts)) { return '情報不備:なし'; } // 仕様フォーマット:"情報不備:" + 契約IDカンマ区切り return '情報不備:' . implode(',', $incompleteContracts); } /** * ① 定期契約データ取得(車種区分・分類名1・定期有効月数毎) * ※ 金額・件数は全て0固定だが、分類や月数の組み合わせごとにレコードが必要 * * 仕様 todo/SHJ-10/SHJ-10.txt:104-128 * * @param int $parkId 駐輪場ID * @param string $startDate 集計開始日(YYYY-MM-DD) * @param string $endDate 集計終了日(YYYY-MM-DD) * @return array */ /** * ① 定期契約データ取得(車種区分・分類名1・定期有効月数毎) * * 仕様 todo/SHJ-10/SHJ-10.txt:104-129 * SQL定義:減免措置・継続フラグ・車種区分・分類名・有効月数でグループ化し、 * 授受金額の合計と件数を算出する * * @param int $parkId 駐輪場ID * @param string $startDate 集計開始日(YYYY-MM-DD) * @param string $endDate 集計終了日(YYYY-MM-DD) * @return array */ private function calculateRegularEarnings(int $parkId, string $startDate, string $endDate): array { $results = DB::table('regular_contract as T1') ->join('usertype as T3', 'T1.user_categoryid', '=', 'T3.user_categoryid') ->select([ DB::raw('IFNULL(T1.contract_reduction, 0) as contract_reduction'), 'T1.update_flag', 'T1.psection_id', 'T3.usertype_subject1', 'T1.enable_months', DB::raw('SUM(T1.contract_money) as total_amount'), // 仕様:授受金額の合計 DB::raw('COUNT(T1.contract_money) as contract_count') // 仕様:授受件数 ]) ->where('T1.park_id', $parkId) ->where('T1.contract_flag', 1) ->whereBetween(DB::raw('DATE(T1.contract_payment_day)'), [$startDate, $endDate]) ->whereNotNull('T1.update_flag') ->whereNotNull('T1.psection_id') ->whereNotNull('T1.enable_months') ->groupBy([ DB::raw('IFNULL(T1.contract_reduction, 0)'), 'T1.update_flag', 'T1.psection_id', 'T3.usertype_subject1', 'T1.enable_months' ]) ->get(); return $results->toArray(); } /** * ② 一時金データ取得(車種毎) * * 仕様 todo/SHJ-10/SHJ-10.txt:148-159 * * @param int $parkId 駐輪場ID * @param string $startDate 集計開始日(YYYY-MM-DD) * @param string $endDate 集計終了日(YYYY-MM-DD) * @return array */ private function calculateLumpsumEarnings(int $parkId, string $startDate, string $endDate): array { $results = DB::table('lumpsum_transaction') ->select([ 'type_class as psection_id', DB::raw('COUNT(*) as lumpsum_count'), DB::raw('COALESCE(SUM(deposit_amount), 0) as lumpsum') ]) ->where('park_id', $parkId) ->whereBetween(DB::raw('DATE(pay_date)'), [$startDate, $endDate]) ->groupBy('type_class') ->get(); return $results->toArray(); } /** * ③ 解約返戻金データ取得(車種区分毎) * * 仕様 todo/SHJ-10/SHJ-10.txt:160-171 * * @param int $parkId 駐輪場ID * @param string $startDate 集計開始日(YYYY-MM-DD) * @param string $endDate 集計終了日(YYYY-MM-DD) * @return array */ private function calculateRefundEarnings(int $parkId, string $startDate, string $endDate): array { $results = DB::table('regular_contract') ->select([ 'psection_id', DB::raw('COALESCE(SUM(refunds), 0) as refunds') ]) ->where('park_id', $parkId) ->where('contract_cancel_flag', 1) ->whereBetween(DB::raw('DATE(repayment_at)'), [$startDate, $endDate]) ->groupBy('psection_id') ->get(); return $results->toArray(); } /** * ④ 再発行データ取得(車種区分毎) * * 仕様 todo/SHJ-10/SHJ-10.txt:172-183 * * @param int $parkId 駐輪場ID * @param string $startDate 集計開始日(YYYY-MM-DD) * @param string $endDate 集計終了日(YYYY-MM-DD) * @return array */ private function calculateReissueCount(int $parkId, string $startDate, string $endDate): array { $results = DB::table('seal') ->select([ 'psection_id', DB::raw('COUNT(contract_id) as reissue_count') ]) ->where('park_id', $parkId) ->where('contract_seal_issue', '>=', 2) ->whereBetween(DB::raw('DATE(seal_day)'), [$startDate, $endDate]) ->groupBy('psection_id') ->get(); return $results->toArray(); } /** * 定期契約データを組合せ毎に統合 * * SQLは contract_reduction × update_flag で分組しているため、 * 同じ psection × usertype × months の組合せで複数行が返る場合がある。 * ここで park_id + psection_id + usertype_subject1 + enable_months をキーに統合し、 * 新規/更新 × 減免/通常 の各件数・金額を1つのオブジェクトに集約する。 * * 仕様 todo/SHJ-10/SHJ-10.txt:130-147 * * @param array $regularData calculateRegularEarnings()の結果 * @return array キー:psection_id|usertype|months、値:統合されたデータオブジェクト */ private function mergeRegularDataByGroup(array $regularData): array { $merged = []; foreach ($regularData as $row) { // 統合キー:psection_id|usertype_subject1|enable_months $key = $row->psection_id . '|' . $row->usertype_subject1 . '|' . $row->enable_months; // 初回作成 if (!isset($merged[$key])) { $merged[$key] = (object)[ 'psection_id' => $row->psection_id, 'usertype_subject1' => $row->usertype_subject1, 'enable_months' => $row->enable_months, // 新規・通常 'regular_new_count' => 0, 'regular_new_amount' => 0, // 新規・減免 'regular_new_reduction_count' => 0, 'regular_new_reduction_amount' => 0, // 更新・通常 'regular_update_count' => 0, 'regular_update_amount' => 0, // 更新・減免 'regular_update_reduction_count' => 0, 'regular_update_reduction_amount' => 0 ]; } // 区分判定 $isNew = in_array($row->update_flag, [2, null]); // 新規 $isReduction = ($row->contract_reduction == 1); // 減免 $count = $row->contract_count ?? 0; $amount = $row->total_amount ?? 0; // 対応するフィールドに累加 if ($isNew && !$isReduction) { // 新規・通常 $merged[$key]->regular_new_count += $count; $merged[$key]->regular_new_amount += $amount; } elseif ($isNew && $isReduction) { // 新規・減免 $merged[$key]->regular_new_reduction_count += $count; $merged[$key]->regular_new_reduction_amount += $amount; } elseif (!$isNew && !$isReduction) { // 更新・通常 $merged[$key]->regular_update_count += $count; $merged[$key]->regular_update_amount += $amount; } elseif (!$isNew && $isReduction) { // 更新・減免 $merged[$key]->regular_update_reduction_count += $count; $merged[$key]->regular_update_reduction_amount += $amount; } } return $merged; } /** * 一時金・解約・再発行データを車種区分毎に統合 * * @param array $lumpsumData * @param array $refundData * @param array $reissueData * @return array */ private function mergeOtherEarningsData(array $lumpsumData, array $refundData, array $reissueData): array { $merged = []; // 一時金 foreach ($lumpsumData as $row) { $psectionId = $row->psection_id; if (!isset($merged[$psectionId])) { $merged[$psectionId] = (object)[ 'psection_id' => $psectionId, 'usertype_subject1' => null, 'enable_months' => 0, 'lumpsum_count' => 0, 'lumpsum' => 0, 'refunds' => 0, 'reissue_count' => 0 ]; } $merged[$psectionId]->lumpsum_count = $row->lumpsum_count; $merged[$psectionId]->lumpsum = $row->lumpsum; } // 解約返戻金 foreach ($refundData as $row) { $psectionId = $row->psection_id; if (!isset($merged[$psectionId])) { $merged[$psectionId] = (object)[ 'psection_id' => $psectionId, 'usertype_subject1' => null, 'enable_months' => 0, 'lumpsum_count' => 0, 'lumpsum' => 0, 'refunds' => 0, 'reissue_count' => 0 ]; } $merged[$psectionId]->refunds = $row->refunds; } // 再発行 foreach ($reissueData as $row) { $psectionId = $row->psection_id; if (!isset($merged[$psectionId])) { $merged[$psectionId] = (object)[ 'psection_id' => $psectionId, 'usertype_subject1' => null, 'enable_months' => 0, 'lumpsum_count' => 0, 'lumpsum' => 0, 'refunds' => 0, 'reissue_count' => 0 ]; } $merged[$psectionId]->reissue_count = $row->reissue_count; } return $merged; } /** * 【処理4】既存の売上集計結果を削除 * * 仕様書のキー:駐輪場ID, 集計種別, 集計開始日, 集計終了日, 売上日付, 車種区分, 分類名1, 定期有効月数 * 仕様 todo/SHJ-10/SHJ-10.txt:213-221 * 仕様書どおり summary_start_date と summary_end_date は NULL で保存されているため、NULL で検索する * * @param int $parkId 駐輪場ID * @param array $aggregationTarget 集計対象 * @return void */ private function deleteExistingFiscalSummary(int $parkId, array $aggregationTarget): void { // 仕様書どおり、同一キーの組み合わせで削除 DB::table('earnings_summary') ->where('park_id', $parkId) ->where('summary_type', $aggregationTarget['summary_type']) ->whereNull('summary_start_date') // 仕様書line 251: null ->whereNull('summary_end_date') // 仕様書line 252: null ->where('earnings_date', $aggregationTarget['end_date']) // psection_id, usertype_subject1, enable_months は // レコードごとに異なるため、ここでは指定しない ->delete(); Log::debug('既存の売上集計結果削除', [ 'park_id' => $parkId, 'summary_type' => $aggregationTarget['summary_type'], 'earnings_date' => $aggregationTarget['end_date'] ]); } /** * 売上集計結果を登録(財政年度ベース) * * 仕様 todo/SHJ-10/SHJ-10.txt:215-284 * * @param object $park 駐輪場情報 * @param object $data 売上データ * @param array $aggregationTarget 集計対象 * @param array $fiscalPeriod 財政期間情報 * @param string $dataType データ種別(regular or other) * @return void */ private function createFiscalEarningsSummary($park, $data, array $aggregationTarget, array $fiscalPeriod, string $dataType): void { $insertData = [ 'park_id' => $park->park_id, 'summary_type' => $aggregationTarget['summary_type'], // 1=年次, 2=月次 'summary_start_date' => null, // 仕様書line 251: null 'summary_end_date' => null, // 仕様書line 252: null 'earnings_date' => $aggregationTarget['end_date'], // 集計終了日 'psection_id' => $data->psection_id, 'usertype_subject1' => $data->usertype_subject1 ?? null, // 実際の分類名 'enable_months' => $data->enable_months ?? 0, // 実際の定期有効月数 'summary_note' => "SHJ-10:{$fiscalPeriod['target_label']}/{$aggregationTarget['start_date']}~{$aggregationTarget['end_date']}", // 仕様line 272 'created_at' => now(), 'updated_at' => now(), 'operator_id' => self::BATCH_OPERATOR_ID // 9999999 (仕様line 275) ]; if ($dataType === 'regular') { // 定期契約データの場合:mergeRegularDataByGroup()で既に統合済み // 新規/更新 × 減免/通常 の各件数・金額がすべて含まれている (仕様line 130-147) $insertData = array_merge($insertData, [ 'regular_new_count' => $data->regular_new_count ?? 0, 'regular_new_amount' => $data->regular_new_amount ?? 0, 'regular_new_reduction_count' => $data->regular_new_reduction_count ?? 0, 'regular_new_reduction_amount' => $data->regular_new_reduction_amount ?? 0, 'regular_update_count' => $data->regular_update_count ?? 0, 'regular_update_amount' => $data->regular_update_amount ?? 0, 'regular_update_reduction_count' => $data->regular_update_reduction_count ?? 0, 'regular_update_reduction_amount' => $data->regular_update_reduction_amount ?? 0, 'lumpsum_count' => 0, // 仕様line 140 'lumpsum' => 0, // 仕様line 141 'refunds' => 0, // 仕様line 142 'other_income' => 0, // 仕様line 143 'other_spending' => 0, // 仕様line 144 'reissue_count' => 0, // 仕様line 145 'reissue_amount' => 0 // 仕様line 146 ]); } else { // 一時金・解約・再発行データの場合:定期フィールドは0固定 (仕様line 186-202) $insertData = array_merge($insertData, [ 'regular_new_count' => 0, // 仕様line 186 'regular_new_amount' => 0, // 仕様line 187 'regular_new_reduction_count' => 0, // 仕様line 188 'regular_new_reduction_amount' => 0, // 仕様line 189 'regular_update_count' => 0, // 仕様line 190 'regular_update_amount' => 0, // 仕様line 191 'regular_update_reduction_count' => 0, // 仕様line 192 'regular_update_reduction_amount' => 0, // 仕様line 193 'lumpsum_count' => $data->lumpsum_count ?? 0, // 仕様line 194 'lumpsum' => $data->lumpsum ?? 0, // 仕様line 195 'refunds' => $data->refunds ?? 0, // 仕様line 196 'other_income' => 0, // 仕様line 197 'other_spending' => 0, // 仕様line 198 'reissue_count' => $data->reissue_count ?? 0, // 仕様line 199 'reissue_amount' => 0 // 仕様line 200: 0固定 ]); } DB::table('earnings_summary')->insert($insertData); Log::debug('売上集計結果登録', [ 'park_id' => $park->park_id, 'psection_id' => $data->psection_id, 'data_type' => $dataType, 'summary_type' => $aggregationTarget['summary_type'] ]); } /** * 【処理5】オペレータキュー作成(駐輪場単位・情報不備がある場合のみ) * * 仕様 todo/SHJ-10/SHJ-10.txt:289-317 * - que_class: 14(集計対象エラー) * - que_comment: 空(仕様書line 297) * - que_status: 1(キュー発生) * - que_status_comment: 空(仕様書line 299) * - work_instructions: 情報不備メッセージ(仕様書line 300) * - park_id: 駐輪場ID(仕様 "処理1.駐輪場ID"、パラメータエラー時はnull) * - operator_id: 9999999(バッチ処理固定値) * * @param string $message 情報不備メッセージ * @param int|null $parkId 駐輪場ID(パラメータエラー時はnull) * @return void */ private function createOperatorQueue(string $message, ?int $parkId = null): void { try { DB::table('operator_que')->insert([ 'que_class' => 14, // 集計対象エラー 'user_id' => null, 'contract_id' => null, 'park_id' => $parkId, // 仕様:処理1.駐輪場ID 'que_comment' => '', // 仕様: 空 'que_status' => 1, // キュー発生 'que_status_comment' => '', // 仕様: 空 'work_instructions' => $message, // 仕様: 情報不備 'operator_id' => self::BATCH_OPERATOR_ID, // 9999999 'created_at' => now(), 'updated_at' => now() ]); Log::info('オペレータキュー作成完了', [ 'park_id' => $parkId, 'que_class' => 14, 'que_status' => 1, 'operator_id' => self::BATCH_OPERATOR_ID, 'work_instructions' => $message ]); } catch (\Exception $e) { Log::error('オペレータキュー作成エラー', [ 'park_id' => $parkId, 'error' => $e->getMessage() ]); } } /** * SHJ-8 バッチ処理ログ作成 * * 共通処理「SHJ-8 バッチ処理ログ作成」を呼び出す * * @param string $jobName ジョブ名 * @param string $status ステータス (success/error) * @param string $statusComment 業務固有のステータスコメント * @return void */ private function callShjEight(string $jobName, string $status, string $statusComment): void { try { $device = Device::orderBy('device_id')->first(); $deviceId = $device ? $device->device_id : 1; $today = now()->format('Y/m/d'); $this->shjEightService->execute( $deviceId, 'SHJ-10', $jobName, $status, $statusComment, $today, $today ); Log::info('SHJ-8 バッチ処理ログ作成完了', [ 'job_name' => $jobName, 'status' => $status ]); } catch (\Exception $e) { Log::error('SHJ-8 バッチ処理ログ作成エラー', [ 'error' => $e->getMessage(), 'job_name' => $jobName, 'status_comment' => $statusComment ]); throw $e; } } /** * 集計種別のラベル取得 * * @param string $type 集計種別 * @return string ラベル */ private function getTypeLabel(string $type): string { switch ($type) { case 'yearly': return '(年次)'; case 'monthly': return '(月次)'; default: return ''; } } }