so-manager-dev.com/app/Services/ShjElevenService.php
2025-09-19 19:01:21 +09:00

433 lines
16 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Services;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use App\Models\Batch\BatchLog;
use App\Models\RegularContract;
use App\Models\Park;
use App\Models\Psection;
use App\Models\Ptype;
use Carbon\Carbon;
/**
* SHJ-11 現在契約台数集計サービス
*
* 集計単位每个の契約台数を算出し、ゾーンマスタとの管理処理を実行
*/
class ShjElevenService
{
/**
* 【処理1】集計単位每个の契約台数を算出する
*
* 集計単位: 駐輪場ID + 車種区分ID + 駐輪分類ID + ゾーンID
*
* SQL仕様に基づく複雑なJOIN処理:
* - regular_contract (T1)
* - park (T2)
* - psection (T4)
* - price_a (T5)
* - ptype (T3)
*
* @return array 契約台数集計結果
*/
public function calculateContractCounts(): array
{
try {
$query = DB::table('regular_contract as T1')
->select([
'T1.park_id', // 駐輪場ID
'T2.park_name', // 駐輪場名
'T5.psection_id', // 車種区分ID
'T4.psection_subject', // 車種区分名
'T5.ptype_id', // 駐輪分類ID
'T3.ptype_subject', // 駐輪分類名
'T1.zone_id', // ゾーンID
DB::raw('count(T1.contract_id) as cnt') // 契約台数
])
// park テーブルとの JOIN
->join('park as T2', 'T1.park_id', '=', 'T2.park_id')
// psection テーブルとの JOIN
->join('psection as T4', 'T1.psection_id', '=', 'T4.psection_id')
// price_a テーブルとの複合条件 JOIN
->join('price_a as T5', function($join) {
$join->on('T1.park_id', '=', 'T5.park_id')
->on('T1.price_parkplaceid', '=', 'T5.price_parkplaceid')
->on('T1.psection_id', '=', 'T5.psection_id');
})
// ptype テーブルとの JOIN
->join('ptype as T3', 'T5.ptype_id', '=', 'T3.ptype_id')
->where([
['T1.contract_flag', '=', 1], // 有効契約
['T2.park_close_flag', '=', 0], // 駐輪場未閉鎖
])
// 契約有効期間内の条件
->whereRaw("date_format(now(), '%y %m %d') BETWEEN T1.contract_periods AND T1.contract_periode")
->groupBy([
'T1.park_id',
'T2.park_name',
'T5.psection_id',
'T4.psection_subject',
'T5.ptype_id',
'T3.ptype_subject',
'T1.zone_id'
])
->get();
Log::info('SHJ-11 契約台数算出完了', [
'count' => $query->count(),
'sql_conditions' => [
'contract_flag' => 1,
'park_close_flag' => 0,
'contract_period_check' => 'BETWEEN contract_periods AND contract_periode'
]
]);
return $query->toArray();
} catch (\Exception $e) {
Log::error('SHJ-11 契約台数算出エラー', [
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString()
]);
throw $e;
}
}
/**
* 【処理2・3】ゾーンマスタ管理処理
*
* 処理フロー:
* 1. ゾーンマスタを取得する
* 2. 取得判定 → 存在しない場合は新規登録
* 3. 契約台数チェック(限界台数超過判定)
* 4. 契約台数を反映する(ゾーンマスタ更新)
*
* @param array $contractCounts 契約台数集計結果
* @return array 処理結果
*/
public function processZoneManagement(array $contractCounts): array
{
$createdZones = 0;
$updatedZones = 0;
$overCapacityCount = 0;
$errors = [];
$processParameters = [];
try {
DB::beginTransaction();
foreach ($contractCounts as $contractData) {
try {
// 【処理2】ゾーンマスタを取得する
$zoneData = $this->getZoneData($contractData);
if (!$zoneData) {
// 【判断2】ゾーンマスタが存在しない場合 → 新規登録
$createResult = $this->createZoneData($contractData);
if ($createResult['success']) {
$createdZones++;
}
$zoneData = $createResult['zone_data'];
}
// 【判断3】契約台数チェック限界台数超過判定
$isOverCapacity = $this->checkCapacityLimit($contractData, $zoneData);
if ($isOverCapacity) {
$overCapacityCount++;
Log::warning('SHJ-11 限界台数超過検出', [
'park_id' => $contractData->park_id,
'zone_id' => $contractData->zone_id,
'current_count' => $contractData->cnt,
'limit_capacity' => $zoneData->zone_tolerance ?? 0
]);
}
// 【処理3】契約台数を反映するゾーンマスタ更新
$updateResult = $this->updateZoneContractCount($contractData);
if ($updateResult['success']) {
$updatedZones++;
}
// 処理パラメータ記録
$processParameters[] = [
'park_id' => $contractData->park_id,
'psection_id' => $contractData->psection_id,
'ptype_id' => $contractData->ptype_id,
'zone_id' => $contractData->zone_id,
'contract_count' => $contractData->cnt,
'is_over_capacity' => $isOverCapacity,
'zone_created' => !$zoneData && $createResult['success'] ?? false,
'zone_updated' => $updateResult['success'] ?? false
];
} catch (\Exception $e) {
$errors[] = [
'park_id' => $contractData->park_id ?? null,
'zone_id' => $contractData->zone_id ?? null,
'error' => $e->getMessage()
];
Log::warning('SHJ-11 個別処理エラー', [
'park_id' => $contractData->park_id ?? null,
'zone_id' => $contractData->zone_id ?? null,
'error' => $e->getMessage()
]);
}
}
DB::commit();
return [
'success' => true,
'created_zones' => $createdZones,
'updated_zones' => $updatedZones,
'over_capacity_count' => $overCapacityCount,
'parameters' => $processParameters,
'errors' => $errors,
'message' => '現在契約台数集計処理完了'
];
} catch (\Exception $e) {
DB::rollBack();
Log::error('SHJ-11 ゾーンマスタ管理処理全体エラー', [
'error' => $e->getMessage(),
'processed_count' => count($processParameters)
]);
return [
'success' => false,
'created_zones' => $createdZones,
'updated_zones' => $updatedZones,
'over_capacity_count' => $overCapacityCount,
'parameters' => $processParameters,
'errors' => $errors,
'message' => 'ゾーンマスタ管理処理エラー: ' . $e->getMessage(),
'details' => $e->getTraceAsString()
];
}
}
/**
* ゾーンマスタデータ取得
*
* 集計単位に対応するゾーンマスタを取得
*
* @param object $contractData 契約台数集計データ
* @return object|null ゾーンマスタデータ
*/
private function getZoneData($contractData)
{
try {
return DB::table('zone')
->select([
'zone_id',
'park_id',
'ptype_id',
'psection_id',
'zone_name',
'zone_number', // 現在契約台数
'zone_standard', // 標準収容台数
'zone_tolerance' // 限界収容台数
])
->where([
['park_id', '=', $contractData->park_id],
['psection_id', '=', $contractData->psection_id],
['ptype_id', '=', $contractData->ptype_id],
['zone_id', '=', $contractData->zone_id]
])
->first();
} catch (\Exception $e) {
Log::error('SHJ-11 ゾーンマスタ取得エラー', [
'park_id' => $contractData->park_id,
'zone_id' => $contractData->zone_id,
'error' => $e->getMessage()
]);
throw $e;
}
}
/**
* ゾーンマスタ新規作成
*
* 仕様書に基づくINSERT処理
*
* @param object $contractData 契約台数集計データ
* @return array 作成結果
*/
private function createZoneData($contractData): array
{
try {
// 新規ゾーンマスタのデフォルト値設定
$newZoneData = [
'zone_id' => $contractData->zone_id,
'park_id' => $contractData->park_id,
'ptype_id' => $contractData->ptype_id,
'psection_id' => $contractData->psection_id,
'zone_name' => null, // デフォルトnull
'zone_number' => $contractData->cnt, // 算出した契約台数
'zone_standard' => null, // デフォルトnull
'zone_tolerance' => null, // デフォルトnull
'zone_sort' => null, // デフォルトnull
'delete_flag' => 0, // 削除フラグOFF
'created_at' => now(),
'updated_at' => now(),
'ope_id' => 9999999 // 仕様書指定値
];
DB::table('zone')->insert($newZoneData);
Log::info('SHJ-11 ゾーンマスタ新規作成完了', [
'zone_id' => $contractData->zone_id,
'park_id' => $contractData->park_id,
'contract_count' => $contractData->cnt
]);
return [
'success' => true,
'zone_data' => (object) $newZoneData,
'message' => 'ゾーンマスタを新規作成しました'
];
} catch (\Exception $e) {
Log::error('SHJ-11 ゾーンマスタ新規作成エラー', [
'zone_id' => $contractData->zone_id,
'park_id' => $contractData->park_id,
'error' => $e->getMessage()
]);
return [
'success' => false,
'zone_data' => null,
'message' => 'ゾーンマスタ新規作成エラー: ' . $e->getMessage()
];
}
}
/**
* 契約台数限界チェック
*
* 【判断3】契約台数 > 限界収容台数の判定
*
* @param object $contractData 契約台数集計データ
* @param object|null $zoneData ゾーンマスタデータ
* @return bool 限界台数超過フラグ
*/
private function checkCapacityLimit($contractData, $zoneData = null): bool
{
if (!$zoneData || is_null($zoneData->zone_tolerance)) {
// ゾーンデータが存在しないか、限界収容台数が未設定の場合は超過判定しない
return false;
}
// 契約台数 > 限界収容台数の判定
return $contractData->cnt > $zoneData->zone_tolerance;
}
/**
* ゾーンマスタ契約台数更新
*
* 【処理3】現在契約台数をゾーンマスタに反映
*
* @param object $contractData 契約台数集計データ
* @return array 更新結果
*/
private function updateZoneContractCount($contractData): array
{
try {
$updateData = [
'zone_number' => $contractData->cnt, // 現在契約台数を更新
'updated_at' => now(), // 更新日時
'ope_id' => 'SHJ-11' // 更新オペレータID
];
$updated = DB::table('zone')
->where([
['park_id', '=', $contractData->park_id],
['psection_id', '=', $contractData->psection_id],
['ptype_id', '=', $contractData->ptype_id],
['zone_id', '=', $contractData->zone_id]
])
->update($updateData);
if ($updated > 0) {
Log::info('SHJ-11 ゾーンマスタ更新完了', [
'zone_id' => $contractData->zone_id,
'park_id' => $contractData->park_id,
'new_contract_count' => $contractData->cnt
]);
return [
'success' => true,
'message' => 'ゾーンマスタ契約台数を更新しました'
];
} else {
return [
'success' => false,
'message' => 'ゾーンマスタ更新対象が見つかりません'
];
}
} catch (\Exception $e) {
Log::error('SHJ-11 ゾーンマスタ更新エラー', [
'zone_id' => $contractData->zone_id,
'park_id' => $contractData->park_id,
'error' => $e->getMessage()
]);
return [
'success' => false,
'message' => 'ゾーンマスタ更新エラー: ' . $e->getMessage()
];
}
}
/**
* 【処理4】バッチ処理ログを作成する
*
* 統一BatchLogシステムを使用してSHJ-11の実行ログを記録
*
* @param string $status ステータス
* @param array $parameters パラメータ
* @param string $message メッセージ
* @param int $executionCount 実行回数
* @param int $successCount 成功回数
* @param int $errorCount エラー回数
* @return void
*/
public function createBatchLog(
string $status,
array $parameters,
string $message,
int $executionCount = 0,
int $successCount = 0,
int $errorCount = 0
): void {
try {
BatchLog::createBatchLog(
'SHJ-11',
$status,
$parameters,
$message,
[
'execution_count' => $executionCount,
'success_count' => $successCount,
'error_count' => $errorCount,
'process_type' => '現在契約台数集計',
'executed_at' => now()->toISOString()
]
);
} catch (\Exception $e) {
Log::error('SHJ-11 バッチログ作成エラー', [
'error' => $e->getMessage(),
'status' => $status,
'message' => $message
]);
}
}
}