Merge pull request 'main_go' (#8) from main_go into main
All checks were successful
Deploy main / deploy (push) Successful in 22s
All checks were successful
Deploy main / deploy (push) Successful in 22s
Reviewed-on: #8
This commit is contained in:
commit
20d99f2102
20
.gitea/workflows/deploy-preview.yml
Normal file
20
.gitea/workflows/deploy-preview.yml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
name: Deploy preview (main_go)
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ["main_go"]
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: deploy-main_go
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ["native"]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Deploy to preview (main_go)
|
||||||
|
env:
|
||||||
|
BRANCH: main_go
|
||||||
|
run: /usr/local/bin/deploy_branch_simple.sh
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -21,3 +21,4 @@ yarn-error.log
|
|||||||
/.nova
|
/.nova
|
||||||
/.vscode
|
/.vscode
|
||||||
/.zed
|
/.zed
|
||||||
|
/docs
|
||||||
|
|||||||
206
app/Console/Commands/ShjNineCommand.php
Normal file
206
app/Console/Commands/ShjNineCommand.php
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use App\Services\ShjNineService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHJ-9 売上集計処理コマンド
|
||||||
|
*
|
||||||
|
* 駐輪場の売上データを日次・月次・年次で集計する処理を実行する
|
||||||
|
* バックグラウンドで実行される定期バッチ処理
|
||||||
|
*/
|
||||||
|
class ShjNineCommand extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* コンソールコマンドの名前とシグネチャ
|
||||||
|
*
|
||||||
|
* 引数:
|
||||||
|
* - type: 集計種別 (daily/monthly/yearly) (必須)
|
||||||
|
* - target_date: 集計対象日 (オプション、YYYY-MM-DD形式)
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'shj:9 {type : 集計種別(daily/monthly/yearly)} {target_date? : 集計対象日(YYYY-MM-DD)}';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* コンソールコマンドの説明
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'SHJ-9 売上集計処理 - 日次/月次/年次売上データ集計を実行';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHJ-9サービスクラス
|
||||||
|
*
|
||||||
|
* @var ShjNineService
|
||||||
|
*/
|
||||||
|
protected $shjNineService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* コンストラクタ
|
||||||
|
*
|
||||||
|
* @param ShjNineService $shjNineService
|
||||||
|
*/
|
||||||
|
public function __construct(ShjNineService $shjNineService)
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
$this->shjNineService = $shjNineService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* コンソールコマンドを実行
|
||||||
|
*
|
||||||
|
* 処理フロー:
|
||||||
|
* 1. パラメータ取得と検証
|
||||||
|
* 2. 集計対象日設定
|
||||||
|
* 3. 売上集計処理実行
|
||||||
|
* 4. バッチログ作成
|
||||||
|
* 5. 処理結果返却
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// 開始ログ出力
|
||||||
|
$startTime = now();
|
||||||
|
$this->info('SHJ-9 売上集計処理を開始します。');
|
||||||
|
|
||||||
|
// 引数取得
|
||||||
|
$type = $this->argument('type');
|
||||||
|
$targetDate = $this->argument('target_date');
|
||||||
|
|
||||||
|
Log::info('SHJ-9 売上集計処理開始', [
|
||||||
|
'start_time' => $startTime,
|
||||||
|
'type' => $type,
|
||||||
|
'target_date' => $targetDate
|
||||||
|
]);
|
||||||
|
|
||||||
|
// パラメータ検証
|
||||||
|
if (!$this->validateParameters($type, $targetDate)) {
|
||||||
|
$this->error('パラメータが不正です。');
|
||||||
|
return self::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 集計対象日設定
|
||||||
|
$aggregationDate = $this->determineAggregationDate($type, $targetDate);
|
||||||
|
|
||||||
|
$this->info("集計種別: {$type}");
|
||||||
|
$this->info("集計対象日: {$aggregationDate}");
|
||||||
|
|
||||||
|
// SHJ-9処理実行
|
||||||
|
$result = $this->shjNineService->executeEarningsAggregation($type, $aggregationDate);
|
||||||
|
|
||||||
|
// 処理結果確認
|
||||||
|
if ($result['success']) {
|
||||||
|
$endTime = now();
|
||||||
|
$this->info('SHJ-9 売上集計処理が正常に完了しました。');
|
||||||
|
$this->info("処理時間: {$startTime->diffInSeconds($endTime)}秒");
|
||||||
|
$this->info("処理結果: 駐輪場数 {$result['processed_parks']}, 集計レコード数 {$result['summary_records']}");
|
||||||
|
|
||||||
|
Log::info('SHJ-9 売上集計処理完了', [
|
||||||
|
'end_time' => $endTime,
|
||||||
|
'duration_seconds' => $startTime->diffInSeconds($endTime),
|
||||||
|
'result' => $result
|
||||||
|
]);
|
||||||
|
|
||||||
|
return self::SUCCESS;
|
||||||
|
} else {
|
||||||
|
$this->error('SHJ-9 売上集計処理でエラーが発生しました: ' . $result['message']);
|
||||||
|
Log::error('SHJ-9 売上集計処理エラー', [
|
||||||
|
'error' => $result['message'],
|
||||||
|
'details' => $result['details'] ?? null
|
||||||
|
]);
|
||||||
|
|
||||||
|
return self::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->error('SHJ-9 売上集計処理で予期しないエラーが発生しました: ' . $e->getMessage());
|
||||||
|
Log::error('SHJ-9 売上集計処理例外エラー', [
|
||||||
|
'exception' => $e->getMessage(),
|
||||||
|
'trace' => $e->getTraceAsString()
|
||||||
|
]);
|
||||||
|
|
||||||
|
return self::FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* パラメータの妥当性を検証
|
||||||
|
*
|
||||||
|
* @param string $type 集計種別
|
||||||
|
* @param string|null $targetDate 対象日
|
||||||
|
* @return bool 検証結果
|
||||||
|
*/
|
||||||
|
private function validateParameters(string $type, ?string $targetDate): bool
|
||||||
|
{
|
||||||
|
// 集計種別チェック
|
||||||
|
$allowedTypes = ['daily', 'monthly', 'yearly'];
|
||||||
|
if (!in_array($type, $allowedTypes)) {
|
||||||
|
$this->error('集計種別は daily, monthly, yearly のいずれかを指定してください。');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 対象日形式チェック(指定されている場合)
|
||||||
|
if ($targetDate && !$this->isValidDateFormat($targetDate)) {
|
||||||
|
$this->error('対象日の形式が正しくありません(YYYY-MM-DD形式で指定してください)。');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 集計対象日を決定
|
||||||
|
*
|
||||||
|
* @param string $type 集計種別
|
||||||
|
* @param string|null $targetDate 指定日
|
||||||
|
* @return string 集計対象日
|
||||||
|
*/
|
||||||
|
private function determineAggregationDate(string $type, ?string $targetDate): string
|
||||||
|
{
|
||||||
|
if ($targetDate) {
|
||||||
|
return $targetDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
// パラメータ指定がない場合のデフォルト設定
|
||||||
|
switch ($type) {
|
||||||
|
case 'daily':
|
||||||
|
// 日次:昨日(本日の1日前)
|
||||||
|
return now()->subDay()->format('Y-m-d');
|
||||||
|
|
||||||
|
case 'monthly':
|
||||||
|
// 月次:前月の最終日
|
||||||
|
return now()->subMonth()->endOfMonth()->format('Y-m-d');
|
||||||
|
|
||||||
|
case 'yearly':
|
||||||
|
// 年次:前年の最終日
|
||||||
|
return now()->subYear()->endOfYear()->format('Y-m-d');
|
||||||
|
|
||||||
|
default:
|
||||||
|
return now()->subDay()->format('Y-m-d');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日付形式の検証
|
||||||
|
*
|
||||||
|
* @param string $date 日付文字列
|
||||||
|
* @return bool 有効な日付形式かどうか
|
||||||
|
*/
|
||||||
|
private function isValidDateFormat(string $date): bool
|
||||||
|
{
|
||||||
|
// YYYY-MM-DD形式の正規表現チェック
|
||||||
|
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $date)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 実際の日付として有効かチェック
|
||||||
|
$dateParts = explode('-', $date);
|
||||||
|
return checkdate((int)$dateParts[1], (int)$dateParts[2], (int)$dateParts[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
129
app/Console/Commands/ShjSixCommand.php
Normal file
129
app/Console/Commands/ShjSixCommand.php
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use App\Services\ShjSixService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHJ-6 サーバ死活監視処理コマンド
|
||||||
|
*
|
||||||
|
* サーバとデバイスの死活監視を行い、異常時にはメール通知を実行する
|
||||||
|
* 定期実行またはオンデマンド実行のバックグラウンドバッチ処理
|
||||||
|
*/
|
||||||
|
class ShjSixCommand extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* コンソールコマンドの名前とシグネチャ
|
||||||
|
*
|
||||||
|
* パラメータなしで実行
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'shj:6';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* コンソールコマンドの説明
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'SHJ-6 サーバ死活監視処理 - サーバ・デバイス監視とアラート通知を実行';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHJ-6サービスクラス
|
||||||
|
*
|
||||||
|
* @var ShjSixService
|
||||||
|
*/
|
||||||
|
protected $shjSixService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* コンストラクタ
|
||||||
|
*
|
||||||
|
* @param ShjSixService $shjSixService
|
||||||
|
*/
|
||||||
|
public function __construct(ShjSixService $shjSixService)
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
$this->shjSixService = $shjSixService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* コンソールコマンドを実行
|
||||||
|
*
|
||||||
|
* 処理フロー:
|
||||||
|
* 1. サーバ死活監視(DBアクセス)
|
||||||
|
* 2. デバイス管理マスタを取得する
|
||||||
|
* 3. デバイス毎のハードウェア状態を取得する
|
||||||
|
* 4. プリンタ制御プログラムログを取得する
|
||||||
|
* 5. バッチ処理ログを作成する
|
||||||
|
* ※ 異常検出時は共通A処理(メール通知)を実行
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// 開始ログ出力
|
||||||
|
$startTime = now();
|
||||||
|
$this->info('SHJ-6 サーバ死活監視処理を開始します。');
|
||||||
|
|
||||||
|
Log::info('SHJ-6 サーバ死活監視処理開始', [
|
||||||
|
'start_time' => $startTime
|
||||||
|
]);
|
||||||
|
|
||||||
|
// SHJ-6監視処理実行
|
||||||
|
$result = $this->shjSixService->executeServerMonitoring();
|
||||||
|
|
||||||
|
// 処理結果確認
|
||||||
|
if ($result['success']) {
|
||||||
|
$endTime = now();
|
||||||
|
$this->info('SHJ-6 サーバ死活監視処理が正常に完了しました。');
|
||||||
|
$this->info("処理時間: {$startTime->diffInSeconds($endTime)}秒");
|
||||||
|
$this->info("監視結果: {$result['monitoring_summary']}");
|
||||||
|
|
||||||
|
// 警告がある場合は表示
|
||||||
|
if (!empty($result['warnings'])) {
|
||||||
|
$this->warn('警告が検出されました:');
|
||||||
|
foreach ($result['warnings'] as $warning) {
|
||||||
|
$this->warn("- {$warning}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::info('SHJ-6 サーバ死活監視処理完了', [
|
||||||
|
'end_time' => $endTime,
|
||||||
|
'duration_seconds' => $startTime->diffInSeconds($endTime),
|
||||||
|
'result' => $result
|
||||||
|
]);
|
||||||
|
|
||||||
|
return self::SUCCESS;
|
||||||
|
} else {
|
||||||
|
$this->error('SHJ-6 サーバ死活監視処理でエラーが発生しました: ' . $result['message']);
|
||||||
|
|
||||||
|
// エラー詳細があれば表示
|
||||||
|
if (!empty($result['error_details'])) {
|
||||||
|
$this->error('エラー詳細:');
|
||||||
|
foreach ($result['error_details'] as $detail) {
|
||||||
|
$this->error("- {$detail}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::error('SHJ-6 サーバ死活監視処理エラー', [
|
||||||
|
'error' => $result['message'],
|
||||||
|
'details' => $result['error_details'] ?? null
|
||||||
|
]);
|
||||||
|
|
||||||
|
return self::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->error('SHJ-6 サーバ死活監視処理で予期しないエラーが発生しました: ' . $e->getMessage());
|
||||||
|
Log::error('SHJ-6 サーバ死活監視処理例外エラー', [
|
||||||
|
'exception' => $e->getMessage(),
|
||||||
|
'trace' => $e->getTraceAsString()
|
||||||
|
]);
|
||||||
|
|
||||||
|
return self::FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
236
app/Console/Commands/ShjTenCommand.php
Normal file
236
app/Console/Commands/ShjTenCommand.php
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use App\Services\ShjTenService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHJ-10 売上集計処理コマンド
|
||||||
|
*
|
||||||
|
* 駐輪場の売上データを財政年度ベースで年次・月次集計する処理を実行する
|
||||||
|
* 4月開始の財政年度期間で計算するバックグラウンドバッチ処理
|
||||||
|
*/
|
||||||
|
class ShjTenCommand extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* コンソールコマンドの名前とシグネチャ
|
||||||
|
*
|
||||||
|
* 引数:
|
||||||
|
* - type: 集計種別 (yearly/monthly) (必須)
|
||||||
|
* - target: 集計対象 (必須)
|
||||||
|
* - yearly: 年度 (例: 2019)
|
||||||
|
* - monthly: 年月 (例: 2019/01)
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'shj:10 {type : 集計種別(yearly/monthly)} {target : 集計対象(yearly:年度, monthly:年月)}';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* コンソールコマンドの説明
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'SHJ-10 売上集計処理 - 財政年度ベース年次/月次売上データ集計を実行';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHJ-10サービスクラス
|
||||||
|
*
|
||||||
|
* @var ShjTenService
|
||||||
|
*/
|
||||||
|
protected $shjTenService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* コンストラクタ
|
||||||
|
*
|
||||||
|
* @param ShjTenService $shjTenService
|
||||||
|
*/
|
||||||
|
public function __construct(ShjTenService $shjTenService)
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
$this->shjTenService = $shjTenService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* コンソールコマンドを実行
|
||||||
|
*
|
||||||
|
* 処理フロー:
|
||||||
|
* 1. パラメータ取得と検証
|
||||||
|
* 2. 財政年度期間設定
|
||||||
|
* 3. 売上集計処理実行
|
||||||
|
* 4. バッチログ作成
|
||||||
|
* 5. 処理結果返却
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// 開始ログ出力
|
||||||
|
$startTime = now();
|
||||||
|
$this->info('SHJ-10 売上集計処理を開始します。');
|
||||||
|
|
||||||
|
// 引数取得
|
||||||
|
$type = $this->argument('type');
|
||||||
|
$target = $this->argument('target');
|
||||||
|
|
||||||
|
Log::info('SHJ-10 売上集計処理開始', [
|
||||||
|
'start_time' => $startTime,
|
||||||
|
'type' => $type,
|
||||||
|
'target' => $target
|
||||||
|
]);
|
||||||
|
|
||||||
|
// パラメータ検証
|
||||||
|
if (!$this->validateParameters($type, $target)) {
|
||||||
|
$this->error('パラメータが不正です。');
|
||||||
|
return self::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 財政年度期間設定
|
||||||
|
$fiscalPeriod = $this->determineFiscalPeriod($type, $target);
|
||||||
|
|
||||||
|
$this->info("集計種別: {$type}");
|
||||||
|
$this->info("集計対象: {$target}");
|
||||||
|
$this->info("財政期間: {$fiscalPeriod['start_date']} ~ {$fiscalPeriod['end_date']}");
|
||||||
|
|
||||||
|
// SHJ-10処理実行
|
||||||
|
$result = $this->shjTenService->executeFiscalEarningsAggregation($type, $target, $fiscalPeriod);
|
||||||
|
|
||||||
|
// 処理結果確認
|
||||||
|
if ($result['success']) {
|
||||||
|
$endTime = now();
|
||||||
|
$this->info('SHJ-10 売上集計処理が正常に完了しました。');
|
||||||
|
$this->info("処理時間: {$startTime->diffInSeconds($endTime)}秒");
|
||||||
|
$this->info("処理結果: 駐輪場数 {$result['processed_parks']}, 集計レコード数 {$result['summary_records']}");
|
||||||
|
|
||||||
|
Log::info('SHJ-10 売上集計処理完了', [
|
||||||
|
'end_time' => $endTime,
|
||||||
|
'duration_seconds' => $startTime->diffInSeconds($endTime),
|
||||||
|
'result' => $result
|
||||||
|
]);
|
||||||
|
|
||||||
|
return self::SUCCESS;
|
||||||
|
} else {
|
||||||
|
$this->error('SHJ-10 売上集計処理でエラーが発生しました: ' . $result['message']);
|
||||||
|
Log::error('SHJ-10 売上集計処理エラー', [
|
||||||
|
'error' => $result['message'],
|
||||||
|
'details' => $result['details'] ?? null
|
||||||
|
]);
|
||||||
|
|
||||||
|
return self::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->error('SHJ-10 売上集計処理で予期しないエラーが発生しました: ' . $e->getMessage());
|
||||||
|
Log::error('SHJ-10 売上集計処理例外エラー', [
|
||||||
|
'exception' => $e->getMessage(),
|
||||||
|
'trace' => $e->getTraceAsString()
|
||||||
|
]);
|
||||||
|
|
||||||
|
return self::FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* パラメータの妥当性を検証
|
||||||
|
*
|
||||||
|
* @param string $type 集計種別
|
||||||
|
* @param string $target 集計対象
|
||||||
|
* @return bool 検証結果
|
||||||
|
*/
|
||||||
|
private function validateParameters(string $type, string $target): bool
|
||||||
|
{
|
||||||
|
// 集計種別チェック
|
||||||
|
$allowedTypes = ['yearly', 'monthly'];
|
||||||
|
if (!in_array($type, $allowedTypes)) {
|
||||||
|
$this->error('集計種別は yearly, monthly のいずれかを指定してください。');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 集計対象形式チェック
|
||||||
|
if ($type === 'yearly') {
|
||||||
|
// 年度形式チェック (例: 2019)
|
||||||
|
if (!preg_match('/^\d{4}$/', $target)) {
|
||||||
|
$this->error('年次集計の場合、年度を4桁の数字で指定してください。(例: 2019)');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} elseif ($type === 'monthly') {
|
||||||
|
// 年月形式チェック (例: 2019/01)
|
||||||
|
if (!preg_match('/^\d{4}\/\d{2}$/', $target)) {
|
||||||
|
$this->error('月次集計の場合、年月をYYYY/MM形式で指定してください。(例: 2019/01)');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 月の範囲チェック (01-12)
|
||||||
|
$parts = explode('/', $target);
|
||||||
|
$month = (int)$parts[1];
|
||||||
|
if ($month < 1 || $month > 12) {
|
||||||
|
$this->error('月は01から12までの範囲で指定してください。');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 財政年度期間を決定
|
||||||
|
*
|
||||||
|
* 財政年度は4月開始(Config設定可能)
|
||||||
|
* - yearly 2019: 2019年4月1日 ~ 2020年3月31日
|
||||||
|
* - monthly 2019/01: 2019年1月1日 ~ 2019年1月31日
|
||||||
|
*
|
||||||
|
* @param string $type 集計種別
|
||||||
|
* @param string $target 集計対象
|
||||||
|
* @return array 財政期間情報
|
||||||
|
*/
|
||||||
|
private function determineFiscalPeriod(string $type, string $target): array
|
||||||
|
{
|
||||||
|
$fiscalStartMonth = 4; // 財政年度開始月(4月)
|
||||||
|
|
||||||
|
if ($type === 'yearly') {
|
||||||
|
$year = (int)$target;
|
||||||
|
|
||||||
|
// 財政年度期間計算
|
||||||
|
$startDate = sprintf('%04d-%02d-01', $year, $fiscalStartMonth);
|
||||||
|
$endDate = sprintf('%04d-%02d-%02d', $year + 1, $fiscalStartMonth - 1,
|
||||||
|
date('t', strtotime(sprintf('%04d-%02d-01', $year + 1, $fiscalStartMonth - 1))));
|
||||||
|
|
||||||
|
return [
|
||||||
|
'type' => 'yearly',
|
||||||
|
'fiscal_year' => $year,
|
||||||
|
'start_date' => $startDate,
|
||||||
|
'end_date' => $endDate,
|
||||||
|
'summary_type' => 1, // 年次
|
||||||
|
'target_label' => "{$year}年度"
|
||||||
|
];
|
||||||
|
|
||||||
|
} elseif ($type === 'monthly') {
|
||||||
|
$parts = explode('/', $target);
|
||||||
|
$year = (int)$parts[0];
|
||||||
|
$month = (int)$parts[1];
|
||||||
|
|
||||||
|
// 指定月の期間計算
|
||||||
|
$startDate = sprintf('%04d-%02d-01', $year, $month);
|
||||||
|
$endDate = sprintf('%04d-%02d-%02d', $year, $month,
|
||||||
|
date('t', strtotime($startDate)));
|
||||||
|
|
||||||
|
// 該当する財政年度を計算
|
||||||
|
$fiscalYear = $month >= $fiscalStartMonth ? $year : $year - 1;
|
||||||
|
|
||||||
|
return [
|
||||||
|
'type' => 'monthly',
|
||||||
|
'fiscal_year' => $fiscalYear,
|
||||||
|
'target_year' => $year,
|
||||||
|
'target_month' => $month,
|
||||||
|
'start_date' => $startDate,
|
||||||
|
'end_date' => $endDate,
|
||||||
|
'summary_type' => 2, // 月次
|
||||||
|
'target_label' => "{$year}年{$month}月"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \InvalidArgumentException("不正な集計種別: {$type}");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -24,3 +24,5 @@ enum QueueClass: string
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -15,3 +15,5 @@ enum QueueStatus: string
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -85,3 +85,5 @@ class OperatorQue extends Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -56,3 +56,5 @@ class Park extends Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -112,3 +112,5 @@ class User extends Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -19,3 +19,4 @@ abstract class BaseModel extends Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -38,3 +38,5 @@ trait HasSortable
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
298
app/Models/EarningsSummary.php
Normal file
298
app/Models/EarningsSummary.php
Normal file
@ -0,0 +1,298 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 売上集計結果モデル - earnings_summaryテーブル
|
||||||
|
*
|
||||||
|
* SHJ-9で作成される日次・月次・年次の売上集計データを管理
|
||||||
|
*/
|
||||||
|
class EarningsSummary extends Model
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* テーブル名
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $table = 'earnings_summary';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* プライマリキー
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $primaryKey = 'earnings_summary_id';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一括代入可能な属性
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'park_id', // 駐輪場ID
|
||||||
|
'summary_type', // 集計区分
|
||||||
|
'summary_start_date', // 集計開始日
|
||||||
|
'summary_end_date', // 集計終了日
|
||||||
|
'earnings_date', // 売上日
|
||||||
|
'psection_id', // 車種区分ID
|
||||||
|
'usertype_subject1', // 規格
|
||||||
|
'enable_months', // 期間(月数)
|
||||||
|
'regular_new_count', // 期間件数
|
||||||
|
'regular_new_amount', // 期間金額
|
||||||
|
'regular_new_reduction_count', // 期間成免件数
|
||||||
|
'regular_new_reduction_amount', // 期間成免金額
|
||||||
|
'regular_update_count', // 更新件数
|
||||||
|
'regular_update_amount', // 更新金額
|
||||||
|
'regular_update_reduction_count', // 更新成免件数
|
||||||
|
'regular_update_reduction_amount', // 更新成免金額
|
||||||
|
'turnsum_count', // 残金件数
|
||||||
|
'turnsum', // 残金
|
||||||
|
'refunds', // 解時返戻金
|
||||||
|
'other_income', // 分別収入
|
||||||
|
'other_spending', // 分別支出
|
||||||
|
'reissue_count', // 発行件数
|
||||||
|
'reissue_amount', // 発行金額
|
||||||
|
'summary_note', // 計備考
|
||||||
|
'created_at', // 登録日時
|
||||||
|
'updated_at', // 更新日時
|
||||||
|
'operator_id' // 新法・ページID
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* キャストする属性
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $casts = [
|
||||||
|
'earnings_summary_id' => 'integer',
|
||||||
|
'park_id' => 'integer',
|
||||||
|
'psection_id' => 'integer',
|
||||||
|
'enable_months' => 'integer',
|
||||||
|
'regular_new_count' => 'integer',
|
||||||
|
'regular_new_amount' => 'decimal:2',
|
||||||
|
'regular_new_reduction_count' => 'integer',
|
||||||
|
'regular_new_reduction_amount' => 'decimal:2',
|
||||||
|
'regular_update_count' => 'integer',
|
||||||
|
'regular_update_amount' => 'decimal:2',
|
||||||
|
'regular_update_reduction_count' => 'integer',
|
||||||
|
'regular_update_reduction_amount' => 'decimal:2',
|
||||||
|
'turnsum_count' => 'integer',
|
||||||
|
'turnsum' => 'decimal:2',
|
||||||
|
'refunds' => 'decimal:2',
|
||||||
|
'other_income' => 'decimal:2',
|
||||||
|
'other_spending' => 'decimal:2',
|
||||||
|
'reissue_count' => 'integer',
|
||||||
|
'reissue_amount' => 'decimal:2',
|
||||||
|
'operator_id' => 'integer',
|
||||||
|
'summary_start_date' => 'date',
|
||||||
|
'summary_end_date' => 'date',
|
||||||
|
'earnings_date' => 'date',
|
||||||
|
'created_at' => 'datetime',
|
||||||
|
'updated_at' => 'datetime'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日付属性
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $dates = [
|
||||||
|
'summary_start_date',
|
||||||
|
'summary_end_date',
|
||||||
|
'earnings_date',
|
||||||
|
'created_at',
|
||||||
|
'updated_at'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 集計タイプの定数
|
||||||
|
*/
|
||||||
|
const TYPE_DAILY = '日次';
|
||||||
|
const TYPE_MONTHLY = '月次';
|
||||||
|
const TYPE_YEARLY = '年次';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 駐輪場との関連
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
|
public function park()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Park::class, 'park_id', 'park_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 車種区分との関連
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
|
public function psection()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Psection::class, 'psection_id', 'psection_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 指定期間の売上集計データを取得
|
||||||
|
*
|
||||||
|
* @param int $parkId 駐輪場ID
|
||||||
|
* @param string $startDate 開始日
|
||||||
|
* @param string $endDate 終了日
|
||||||
|
* @param string|null $summaryType 集計タイプ
|
||||||
|
* @return \Illuminate\Database\Eloquent\Collection
|
||||||
|
*/
|
||||||
|
public static function getEarningsByPeriod(int $parkId, string $startDate, string $endDate, ?string $summaryType = null)
|
||||||
|
{
|
||||||
|
$query = self::where('park_id', $parkId)
|
||||||
|
->whereBetween('earnings_date', [$startDate, $endDate]);
|
||||||
|
|
||||||
|
if ($summaryType) {
|
||||||
|
$query->where('summary_type', $summaryType);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query->with(['park', 'psection'])
|
||||||
|
->orderBy('earnings_date')
|
||||||
|
->orderBy('psection_id')
|
||||||
|
->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 駐輪場別の売上合計を取得
|
||||||
|
*
|
||||||
|
* @param int $parkId 駐輪場ID
|
||||||
|
* @param string $startDate 開始日
|
||||||
|
* @param string $endDate 終了日
|
||||||
|
* @return array 売上合計データ
|
||||||
|
*/
|
||||||
|
public static function getEarningsTotalByPark(int $parkId, string $startDate, string $endDate): array
|
||||||
|
{
|
||||||
|
$result = self::where('park_id', $parkId)
|
||||||
|
->whereBetween('earnings_date', [$startDate, $endDate])
|
||||||
|
->selectRaw('
|
||||||
|
SUM(regular_new_count) as total_new_count,
|
||||||
|
SUM(regular_new_amount) as total_new_amount,
|
||||||
|
SUM(regular_update_count) as total_update_count,
|
||||||
|
SUM(regular_update_amount) as total_update_amount,
|
||||||
|
SUM(turnsum_count) as total_turnsum_count,
|
||||||
|
SUM(turnsum) as total_turnsum,
|
||||||
|
SUM(refunds) as total_refunds,
|
||||||
|
SUM(reissue_count) as total_reissue_count,
|
||||||
|
SUM(reissue_amount) as total_reissue_amount
|
||||||
|
')
|
||||||
|
->first();
|
||||||
|
|
||||||
|
return $result ? $result->toArray() : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最新の集計日を取得
|
||||||
|
*
|
||||||
|
* @param int|null $parkId 駐輪場ID(省略時は全体)
|
||||||
|
* @param string|null $summaryType 集計タイプ
|
||||||
|
* @return string|null 最新集計日
|
||||||
|
*/
|
||||||
|
public static function getLatestEarningsDate(?int $parkId = null, ?string $summaryType = null): ?string
|
||||||
|
{
|
||||||
|
$query = self::query();
|
||||||
|
|
||||||
|
if ($parkId) {
|
||||||
|
$query->where('park_id', $parkId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($summaryType) {
|
||||||
|
$query->where('summary_type', $summaryType);
|
||||||
|
}
|
||||||
|
|
||||||
|
$latest = $query->max('earnings_date');
|
||||||
|
|
||||||
|
return $latest ? Carbon::parse($latest)->format('Y-m-d') : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 期間の売上データを削除
|
||||||
|
*
|
||||||
|
* @param int $parkId 駐輪場ID
|
||||||
|
* @param string $startDate 開始日
|
||||||
|
* @param string $endDate 終了日
|
||||||
|
* @param string|null $summaryType 集計タイプ
|
||||||
|
* @return int 削除件数
|
||||||
|
*/
|
||||||
|
public static function deleteEarningsByPeriod(int $parkId, string $startDate, string $endDate, ?string $summaryType = null): int
|
||||||
|
{
|
||||||
|
$query = self::where('park_id', $parkId)
|
||||||
|
->where('summary_start_date', $startDate)
|
||||||
|
->where('summary_end_date', $endDate);
|
||||||
|
|
||||||
|
if ($summaryType) {
|
||||||
|
$query->where('summary_type', $summaryType);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 売上集計データの作成
|
||||||
|
*
|
||||||
|
* @param array $data 売上データ
|
||||||
|
* @return EarningsSummary 作成されたモデル
|
||||||
|
*/
|
||||||
|
public static function createEarningsSummary(array $data): EarningsSummary
|
||||||
|
{
|
||||||
|
$defaultData = [
|
||||||
|
'regular_new_count' => 0,
|
||||||
|
'regular_new_amount' => 0.00,
|
||||||
|
'regular_new_reduction_count' => 0,
|
||||||
|
'regular_new_reduction_amount' => 0.00,
|
||||||
|
'regular_update_count' => 0,
|
||||||
|
'regular_update_amount' => 0.00,
|
||||||
|
'regular_update_reduction_count' => 0,
|
||||||
|
'regular_update_reduction_amount' => 0.00,
|
||||||
|
'turnsum_count' => 0,
|
||||||
|
'turnsum' => 0.00,
|
||||||
|
'refunds' => 0.00,
|
||||||
|
'other_income' => 0.00,
|
||||||
|
'other_spending' => 0.00,
|
||||||
|
'reissue_count' => 0,
|
||||||
|
'reissue_amount' => 0.00,
|
||||||
|
'operator_id' => 0
|
||||||
|
];
|
||||||
|
|
||||||
|
$mergedData = array_merge($defaultData, $data);
|
||||||
|
|
||||||
|
return self::create($mergedData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 売上合計の計算
|
||||||
|
*
|
||||||
|
* @return float 売上合計
|
||||||
|
*/
|
||||||
|
public function getTotalEarningsAttribute(): float
|
||||||
|
{
|
||||||
|
return $this->regular_new_amount +
|
||||||
|
$this->regular_update_amount +
|
||||||
|
$this->turnsum +
|
||||||
|
$this->reissue_amount +
|
||||||
|
$this->other_income -
|
||||||
|
$this->other_spending -
|
||||||
|
$this->refunds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文字列表現
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function __toString(): string
|
||||||
|
{
|
||||||
|
return sprintf(
|
||||||
|
'EarningsSummary[ID:%d, Park:%d, Type:%s, Date:%s]',
|
||||||
|
$this->earnings_summary_id,
|
||||||
|
$this->park_id,
|
||||||
|
$this->summary_type,
|
||||||
|
$this->earnings_date ? $this->earnings_date->format('Y-m-d') : 'N/A'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
229
app/Models/HardwareCheckLog.php
Normal file
229
app/Models/HardwareCheckLog.php
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ハードウェアチェックログモデル - hardware_check_logテーブル
|
||||||
|
*
|
||||||
|
* デバイスのハードウェア状態監視ログを管理
|
||||||
|
*/
|
||||||
|
class HardwareCheckLog extends Model
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* テーブル名
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $table = 'hardware_check_log';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* プライマリキー
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $primaryKey = 'log_id';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一括代入可能な属性
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'device_id', // デバイスID
|
||||||
|
'status', // ステータス
|
||||||
|
'status_comment', // ステータスコメント
|
||||||
|
'created_at', // 作成日時
|
||||||
|
'updated_at', // 更新日時
|
||||||
|
'operator_id' // オペレータID
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* キャストする属性
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $casts = [
|
||||||
|
'log_id' => 'integer',
|
||||||
|
'device_id' => 'integer',
|
||||||
|
'status' => 'integer',
|
||||||
|
'operator_id' => 'integer',
|
||||||
|
'created_at' => 'datetime',
|
||||||
|
'updated_at' => 'datetime'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ステータスの定数
|
||||||
|
*/
|
||||||
|
const STATUS_NORMAL = 1; // 正常
|
||||||
|
const STATUS_WARNING = 2; // 警告
|
||||||
|
const STATUS_ERROR = 3; // エラー
|
||||||
|
const STATUS_UNKNOWN = 0; // 不明
|
||||||
|
|
||||||
|
/**
|
||||||
|
* デバイスとの関連
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
|
public function device()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Device::class, 'device_id', 'device_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 指定デバイスの最新ハードウェア状態を取得
|
||||||
|
*
|
||||||
|
* @param int $deviceId デバイスID
|
||||||
|
* @return HardwareCheckLog|null 最新ログ
|
||||||
|
*/
|
||||||
|
public static function getLatestStatusByDevice(int $deviceId): ?HardwareCheckLog
|
||||||
|
{
|
||||||
|
return self::where('device_id', $deviceId)
|
||||||
|
->orderBy('created_at', 'desc')
|
||||||
|
->first();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全デバイスの最新ハードウェア状態を取得
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Eloquent\Collection
|
||||||
|
*/
|
||||||
|
public static function getLatestStatusForAllDevices()
|
||||||
|
{
|
||||||
|
return self::select('device_id')
|
||||||
|
->selectRaw('MAX(created_at) as latest_created_at')
|
||||||
|
->groupBy('device_id')
|
||||||
|
->with(['device'])
|
||||||
|
->get()
|
||||||
|
->map(function ($log) {
|
||||||
|
return self::where('device_id', $log->device_id)
|
||||||
|
->where('created_at', $log->latest_created_at)
|
||||||
|
->with(['device'])
|
||||||
|
->first();
|
||||||
|
})
|
||||||
|
->filter();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 異常状態のデバイスを取得
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Eloquent\Collection
|
||||||
|
*/
|
||||||
|
public static function getAbnormalDevices()
|
||||||
|
{
|
||||||
|
$latestLogs = self::getLatestStatusForAllDevices();
|
||||||
|
|
||||||
|
return $latestLogs->filter(function ($log) {
|
||||||
|
return $log->status !== self::STATUS_NORMAL;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 指定期間内のログを取得
|
||||||
|
*
|
||||||
|
* @param int $deviceId デバイスID
|
||||||
|
* @param string $startTime 開始時刻
|
||||||
|
* @param string $endTime 終了時刻
|
||||||
|
* @return \Illuminate\Database\Eloquent\Collection
|
||||||
|
*/
|
||||||
|
public static function getLogsByPeriod(int $deviceId, string $startTime, string $endTime)
|
||||||
|
{
|
||||||
|
return self::where('device_id', $deviceId)
|
||||||
|
->whereBetween('created_at', [$startTime, $endTime])
|
||||||
|
->orderBy('created_at', 'desc')
|
||||||
|
->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ハードウェア状態ログを作成
|
||||||
|
*
|
||||||
|
* @param int $deviceId デバイスID
|
||||||
|
* @param int $status ステータス
|
||||||
|
* @param string $statusComment ステータスコメント
|
||||||
|
* @param int|null $operatorId オペレータID
|
||||||
|
* @return HardwareCheckLog 作成されたログ
|
||||||
|
*/
|
||||||
|
public static function createLog(
|
||||||
|
int $deviceId,
|
||||||
|
int $status,
|
||||||
|
string $statusComment = '',
|
||||||
|
?int $operatorId = null
|
||||||
|
): HardwareCheckLog {
|
||||||
|
return self::create([
|
||||||
|
'device_id' => $deviceId,
|
||||||
|
'status' => $status,
|
||||||
|
'status_comment' => $statusComment,
|
||||||
|
'operator_id' => $operatorId ?? 0
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ステータス名を取得
|
||||||
|
*
|
||||||
|
* @param int $status ステータス
|
||||||
|
* @return string ステータス名
|
||||||
|
*/
|
||||||
|
public static function getStatusName(int $status): string
|
||||||
|
{
|
||||||
|
switch ($status) {
|
||||||
|
case self::STATUS_NORMAL:
|
||||||
|
return '正常';
|
||||||
|
case self::STATUS_WARNING:
|
||||||
|
return '警告';
|
||||||
|
case self::STATUS_ERROR:
|
||||||
|
return 'エラー';
|
||||||
|
case self::STATUS_UNKNOWN:
|
||||||
|
return '不明';
|
||||||
|
default:
|
||||||
|
return "ステータス{$status}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 現在のステータス名を取得
|
||||||
|
*
|
||||||
|
* @return string ステータス名
|
||||||
|
*/
|
||||||
|
public function getStatusNameAttribute(): string
|
||||||
|
{
|
||||||
|
return self::getStatusName($this->status);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 正常状態かどうかを判定
|
||||||
|
*
|
||||||
|
* @return bool 正常状態かどうか
|
||||||
|
*/
|
||||||
|
public function isNormal(): bool
|
||||||
|
{
|
||||||
|
return $this->status === self::STATUS_NORMAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 異常状態かどうかを判定
|
||||||
|
*
|
||||||
|
* @return bool 異常状態かどうか
|
||||||
|
*/
|
||||||
|
public function isAbnormal(): bool
|
||||||
|
{
|
||||||
|
return $this->status !== self::STATUS_NORMAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文字列表現
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function __toString(): string
|
||||||
|
{
|
||||||
|
return sprintf(
|
||||||
|
'HardwareCheckLog[ID:%d, Device:%d, Status:%s, Time:%s]',
|
||||||
|
$this->log_id,
|
||||||
|
$this->device_id,
|
||||||
|
$this->getStatusNameAttribute(),
|
||||||
|
$this->created_at ? $this->created_at->format('Y-m-d H:i:s') : 'N/A'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
293
app/Models/OperatorQue.php
Normal file
293
app/Models/OperatorQue.php
Normal file
@ -0,0 +1,293 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* オペレータキューモデル - operator_queテーブル
|
||||||
|
*
|
||||||
|
* バッチ処理結果の通知や作業指示を管理
|
||||||
|
*/
|
||||||
|
class OperatorQue extends Model
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* テーブル名
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $table = 'operator_que';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* プライマリキー
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $primaryKey = 'que_id';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一括代入可能な属性
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'que_class', // キュークラス
|
||||||
|
'user_id', // ユーザーID
|
||||||
|
'contract_id', // 契約ID
|
||||||
|
'park_id', // 駐輪場ID
|
||||||
|
'que_comment', // キューコメント
|
||||||
|
'que_status', // キューステータス
|
||||||
|
'que_status_comment', // キューステータスコメント
|
||||||
|
'work_instructions', // 作業指示
|
||||||
|
'created_at', // 作成日時
|
||||||
|
'updated_at' // 更新日時
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* キャストする属性
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $casts = [
|
||||||
|
'que_id' => 'integer',
|
||||||
|
'que_class' => 'integer',
|
||||||
|
'user_id' => 'integer',
|
||||||
|
'contract_id' => 'integer',
|
||||||
|
'park_id' => 'integer',
|
||||||
|
'que_status' => 'integer',
|
||||||
|
'created_at' => 'datetime',
|
||||||
|
'updated_at' => 'datetime'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* キュークラスの定数
|
||||||
|
*/
|
||||||
|
const CLASS_SHJ4C = 4; // SHJ-4C室割当処理
|
||||||
|
const CLASS_SHJ6 = 6; // SHJ-6サーバ死活監視処理
|
||||||
|
const CLASS_SHJ8 = 8; // SHJ-8バッチログ処理
|
||||||
|
const CLASS_SHJ9 = 9; // SHJ-9売上集計処理
|
||||||
|
const CLASS_SHJ10 = 10; // SHJ-10財政年度売上集計処理
|
||||||
|
const CLASS_MAIL_SEND = 11; // メール送信処理
|
||||||
|
|
||||||
|
/**
|
||||||
|
* キューステータスの定数
|
||||||
|
*/
|
||||||
|
const STATUS_PENDING = 0; // 待機中
|
||||||
|
const STATUS_COMPLETED = 1; // 完了
|
||||||
|
const STATUS_ERROR = 2; // エラー
|
||||||
|
const STATUS_CANCELLED = 3; // キャンセル
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 駐輪場との関連
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
|
public function park()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Park::class, 'park_id', 'park_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ユーザーとの関連
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class, 'user_id', 'user_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 契約との関連
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
|
public function contract()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(RegularContract::class, 'contract_id', 'contract_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* バッチ処理用キューを作成
|
||||||
|
*
|
||||||
|
* @param int $queClass キュークラス
|
||||||
|
* @param string $comment コメント
|
||||||
|
* @param int $status ステータス
|
||||||
|
* @param string|null $workInstructions 作業指示
|
||||||
|
* @param int|null $parkId 駐輪場ID
|
||||||
|
* @return OperatorQue 作成されたキュー
|
||||||
|
*/
|
||||||
|
public static function createBatchQueue(
|
||||||
|
int $queClass,
|
||||||
|
string $comment,
|
||||||
|
int $status = self::STATUS_COMPLETED,
|
||||||
|
?string $workInstructions = null,
|
||||||
|
?int $parkId = null
|
||||||
|
): OperatorQue {
|
||||||
|
return self::create([
|
||||||
|
'que_class' => $queClass,
|
||||||
|
'user_id' => null,
|
||||||
|
'contract_id' => null,
|
||||||
|
'park_id' => $parkId,
|
||||||
|
'que_comment' => $comment,
|
||||||
|
'que_status' => $status,
|
||||||
|
'que_status_comment' => self::getStatusComment($status),
|
||||||
|
'work_instructions' => $workInstructions
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHJ-9用キューを作成
|
||||||
|
*
|
||||||
|
* @param string $message メッセージ
|
||||||
|
* @param int $batchLogId バッチログID
|
||||||
|
* @param int $status ステータス
|
||||||
|
* @return OperatorQue 作成されたキュー
|
||||||
|
*/
|
||||||
|
public static function createShjNineQueue(
|
||||||
|
string $message,
|
||||||
|
int $batchLogId,
|
||||||
|
int $status = self::STATUS_COMPLETED
|
||||||
|
): OperatorQue {
|
||||||
|
return self::createBatchQueue(
|
||||||
|
self::CLASS_SHJ9,
|
||||||
|
$message,
|
||||||
|
$status,
|
||||||
|
"SHJ-9売上集計処理 BatchLogID: {$batchLogId}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 指定期間のキューを取得
|
||||||
|
*
|
||||||
|
* @param string $startDate 開始日
|
||||||
|
* @param string $endDate 終了日
|
||||||
|
* @param int|null $queClass キュークラス
|
||||||
|
* @return \Illuminate\Database\Eloquent\Collection
|
||||||
|
*/
|
||||||
|
public static function getQueuesByPeriod(string $startDate, string $endDate, ?int $queClass = null)
|
||||||
|
{
|
||||||
|
$query = self::whereBetween('created_at', [$startDate, $endDate]);
|
||||||
|
|
||||||
|
if ($queClass) {
|
||||||
|
$query->where('que_class', $queClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query->with(['park', 'user', 'contract'])
|
||||||
|
->orderBy('created_at', 'desc')
|
||||||
|
->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 未完了のキューを取得
|
||||||
|
*
|
||||||
|
* @param int|null $queClass キュークラス
|
||||||
|
* @return \Illuminate\Database\Eloquent\Collection
|
||||||
|
*/
|
||||||
|
public static function getPendingQueues(?int $queClass = null)
|
||||||
|
{
|
||||||
|
$query = self::where('que_status', self::STATUS_PENDING);
|
||||||
|
|
||||||
|
if ($queClass) {
|
||||||
|
$query->where('que_class', $queClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query->with(['park', 'user', 'contract'])
|
||||||
|
->orderBy('created_at')
|
||||||
|
->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* キューを完了状態に更新
|
||||||
|
*
|
||||||
|
* @param string|null $comment 完了コメント
|
||||||
|
* @return bool 更新結果
|
||||||
|
*/
|
||||||
|
public function markAsCompleted(?string $comment = null): bool
|
||||||
|
{
|
||||||
|
return $this->update([
|
||||||
|
'que_status' => self::STATUS_COMPLETED,
|
||||||
|
'que_status_comment' => $comment ?? self::getStatusComment(self::STATUS_COMPLETED),
|
||||||
|
'updated_at' => now()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* キューをエラー状態に更新
|
||||||
|
*
|
||||||
|
* @param string $errorMessage エラーメッセージ
|
||||||
|
* @return bool 更新結果
|
||||||
|
*/
|
||||||
|
public function markAsError(string $errorMessage): bool
|
||||||
|
{
|
||||||
|
return $this->update([
|
||||||
|
'que_status' => self::STATUS_ERROR,
|
||||||
|
'que_status_comment' => $errorMessage,
|
||||||
|
'updated_at' => now()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ステータスコメントを取得
|
||||||
|
*
|
||||||
|
* @param int $status ステータス
|
||||||
|
* @return string ステータスコメント
|
||||||
|
*/
|
||||||
|
public static function getStatusComment(int $status): string
|
||||||
|
{
|
||||||
|
switch ($status) {
|
||||||
|
case self::STATUS_PENDING:
|
||||||
|
return '待機中';
|
||||||
|
case self::STATUS_COMPLETED:
|
||||||
|
return '完了';
|
||||||
|
case self::STATUS_ERROR:
|
||||||
|
return 'エラー';
|
||||||
|
case self::STATUS_CANCELLED:
|
||||||
|
return 'キャンセル';
|
||||||
|
default:
|
||||||
|
return '不明';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* キュークラス名を取得
|
||||||
|
*
|
||||||
|
* @param int $queClass キュークラス
|
||||||
|
* @return string クラス名
|
||||||
|
*/
|
||||||
|
public static function getClassName(int $queClass): string
|
||||||
|
{
|
||||||
|
switch ($queClass) {
|
||||||
|
case self::CLASS_SHJ4C:
|
||||||
|
return 'SHJ-4C室割当処理';
|
||||||
|
case self::CLASS_SHJ6:
|
||||||
|
return 'SHJ-6サーバ死活監視処理';
|
||||||
|
case self::CLASS_SHJ8:
|
||||||
|
return 'SHJ-8バッチログ処理';
|
||||||
|
case self::CLASS_SHJ9:
|
||||||
|
return 'SHJ-9売上集計処理';
|
||||||
|
case self::CLASS_SHJ10:
|
||||||
|
return 'SHJ-10財政年度売上集計処理';
|
||||||
|
case self::CLASS_MAIL_SEND:
|
||||||
|
return 'メール送信処理';
|
||||||
|
default:
|
||||||
|
return "クラス{$queClass}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文字列表現
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function __toString(): string
|
||||||
|
{
|
||||||
|
return sprintf(
|
||||||
|
'OperatorQue[ID:%d, Class:%s, Status:%s, Date:%s]',
|
||||||
|
$this->que_id,
|
||||||
|
self::getClassName($this->que_class),
|
||||||
|
self::getStatusComment($this->que_status),
|
||||||
|
$this->created_at ? $this->created_at->format('Y-m-d H:i:s') : 'N/A'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -42,3 +42,5 @@ class Park extends Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -58,3 +58,5 @@ class PriceA extends Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
251
app/Models/PrintJobLog.php
Normal file
251
app/Models/PrintJobLog.php
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* プリンタジョブログモデル - print_job_logテーブル
|
||||||
|
*
|
||||||
|
* プリンタ制御プログラムの実行ログを管理
|
||||||
|
*/
|
||||||
|
class PrintJobLog extends Model
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* テーブル名
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $table = 'print_job_log';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* プライマリキー
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $primaryKey = 'log_id';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一括代入可能な属性
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'park_id', // 駐輪場ID
|
||||||
|
'user_id', // ユーザーID
|
||||||
|
'contract_id', // 契約ID
|
||||||
|
'process_name', // プロセス名
|
||||||
|
'job_name', // ジョブ名
|
||||||
|
'status', // ステータス
|
||||||
|
'error_code', // エラーコード
|
||||||
|
'status_comment', // ステータスコメント
|
||||||
|
'created_at' // 作成日時
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* キャストする属性
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $casts = [
|
||||||
|
'log_id' => 'integer',
|
||||||
|
'park_id' => 'integer',
|
||||||
|
'user_id' => 'integer',
|
||||||
|
'contract_id' => 'integer',
|
||||||
|
'error_code' => 'integer',
|
||||||
|
'created_at' => 'datetime'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* エラーコードの定数
|
||||||
|
*/
|
||||||
|
const ERROR_CODE_THRESHOLD = 100; // エラー判定閾値(>=100がエラー)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* updateされない設定(created_atのみ)
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 駐輪場との関連
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
|
public function park()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Park::class, 'park_id', 'park_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ユーザーとの関連
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class, 'user_id', 'user_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 契約との関連
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
|
public function contract()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(RegularContract::class, 'contract_id', 'contract_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 過去15分間のエラーログを取得
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Eloquent\Collection
|
||||||
|
*/
|
||||||
|
public static function getRecentErrorLogs()
|
||||||
|
{
|
||||||
|
$fifteenMinutesAgo = Carbon::now()->subMinutes(15);
|
||||||
|
|
||||||
|
return self::where('created_at', '>=', $fifteenMinutesAgo)
|
||||||
|
->where('error_code', '>=', self::ERROR_CODE_THRESHOLD)
|
||||||
|
->orderBy('created_at', 'desc')
|
||||||
|
->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 指定期間内のエラーログを取得
|
||||||
|
*
|
||||||
|
* @param string $startTime 開始時刻
|
||||||
|
* @param string $endTime 終了時刻
|
||||||
|
* @return \Illuminate\Database\Eloquent\Collection
|
||||||
|
*/
|
||||||
|
public static function getErrorLogsByPeriod(string $startTime, string $endTime)
|
||||||
|
{
|
||||||
|
return self::whereBetween('created_at', [$startTime, $endTime])
|
||||||
|
->where('error_code', '>=', self::ERROR_CODE_THRESHOLD)
|
||||||
|
->orderBy('created_at', 'desc')
|
||||||
|
->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 指定期間内の全ログを取得
|
||||||
|
*
|
||||||
|
* @param string $startTime 開始時刻
|
||||||
|
* @param string $endTime 終了時刻
|
||||||
|
* @return \Illuminate\Database\Eloquent\Collection
|
||||||
|
*/
|
||||||
|
public static function getLogsByPeriod(string $startTime, string $endTime)
|
||||||
|
{
|
||||||
|
return self::whereBetween('created_at', [$startTime, $endTime])
|
||||||
|
->orderBy('created_at', 'desc')
|
||||||
|
->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* プリンタジョブログを作成
|
||||||
|
*
|
||||||
|
* @param array $data ログデータ
|
||||||
|
* @return PrintJobLog 作成されたログ
|
||||||
|
*/
|
||||||
|
public static function createLog(array $data): PrintJobLog
|
||||||
|
{
|
||||||
|
$defaultData = [
|
||||||
|
'park_id' => null,
|
||||||
|
'user_id' => null,
|
||||||
|
'contract_id' => null,
|
||||||
|
'process_name' => '',
|
||||||
|
'job_name' => '',
|
||||||
|
'status' => '',
|
||||||
|
'error_code' => 0,
|
||||||
|
'status_comment' => '',
|
||||||
|
'created_at' => now()
|
||||||
|
];
|
||||||
|
|
||||||
|
$mergedData = array_merge($defaultData, $data);
|
||||||
|
|
||||||
|
return self::create($mergedData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* エラーログかどうかを判定
|
||||||
|
*
|
||||||
|
* @return bool エラーログかどうか
|
||||||
|
*/
|
||||||
|
public function isError(): bool
|
||||||
|
{
|
||||||
|
return $this->error_code >= self::ERROR_CODE_THRESHOLD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 正常ログかどうかを判定
|
||||||
|
*
|
||||||
|
* @return bool 正常ログかどうか
|
||||||
|
*/
|
||||||
|
public function isNormal(): bool
|
||||||
|
{
|
||||||
|
return $this->error_code < self::ERROR_CODE_THRESHOLD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* エラーレベルを取得
|
||||||
|
*
|
||||||
|
* @return string エラーレベル
|
||||||
|
*/
|
||||||
|
public function getErrorLevel(): string
|
||||||
|
{
|
||||||
|
if ($this->error_code >= 200) {
|
||||||
|
return '重大エラー';
|
||||||
|
} elseif ($this->error_code >= self::ERROR_CODE_THRESHOLD) {
|
||||||
|
return 'エラー';
|
||||||
|
} else {
|
||||||
|
return '正常';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* エラーログの統計情報を取得
|
||||||
|
*
|
||||||
|
* @param string $startTime 開始時刻
|
||||||
|
* @param string $endTime 終了時刻
|
||||||
|
* @return array 統計情報
|
||||||
|
*/
|
||||||
|
public static function getErrorStatistics(string $startTime, string $endTime): array
|
||||||
|
{
|
||||||
|
$errorLogs = self::getErrorLogsByPeriod($startTime, $endTime);
|
||||||
|
$totalLogs = self::getLogsByPeriod($startTime, $endTime);
|
||||||
|
|
||||||
|
$errorByCode = $errorLogs->groupBy('error_code')->map->count();
|
||||||
|
$errorByProcess = $errorLogs->groupBy('process_name')->map->count();
|
||||||
|
|
||||||
|
return [
|
||||||
|
'total_logs' => $totalLogs->count(),
|
||||||
|
'error_logs' => $errorLogs->count(),
|
||||||
|
'error_rate' => $totalLogs->count() > 0 ?
|
||||||
|
round(($errorLogs->count() / $totalLogs->count()) * 100, 2) : 0,
|
||||||
|
'error_by_code' => $errorByCode->toArray(),
|
||||||
|
'error_by_process' => $errorByProcess->toArray(),
|
||||||
|
'period' => [
|
||||||
|
'start' => $startTime,
|
||||||
|
'end' => $endTime
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文字列表現
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function __toString(): string
|
||||||
|
{
|
||||||
|
return sprintf(
|
||||||
|
'PrintJobLog[ID:%d, Process:%s, ErrorCode:%d, Time:%s]',
|
||||||
|
$this->log_id,
|
||||||
|
$this->process_name,
|
||||||
|
$this->error_code,
|
||||||
|
$this->created_at ? $this->created_at->format('Y-m-d H:i:s') : 'N/A'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
106
app/Models/Psection.php
Normal file
106
app/Models/Psection.php
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 車種区分モデル - psectionテーブル
|
||||||
|
*
|
||||||
|
* 駐輪場の車種区分マスタデータを管理
|
||||||
|
*/
|
||||||
|
class Psection extends Model
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* テーブル名
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $table = 'psection';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* プライマリキー
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $primaryKey = 'psection_id';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一括代入可能な属性
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'psection_subject', // 車種区分名
|
||||||
|
'operator_id', // オペレータID
|
||||||
|
'created_at', // 作成日時
|
||||||
|
'updated_at' // 更新日時
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* キャストする属性
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $casts = [
|
||||||
|
'psection_id' => 'integer',
|
||||||
|
'operator_id' => 'integer',
|
||||||
|
'created_at' => 'datetime',
|
||||||
|
'updated_at' => 'datetime'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 売上集計との関連
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||||
|
*/
|
||||||
|
public function earningsSummaries()
|
||||||
|
{
|
||||||
|
return $this->hasMany(EarningsSummary::class, 'psection_id', 'psection_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定期契約との関連
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||||
|
*/
|
||||||
|
public function regularContracts()
|
||||||
|
{
|
||||||
|
return $this->hasMany(RegularContract::class, 'psection_id', 'psection_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* アクティブな車種区分一覧を取得
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Eloquent\Collection
|
||||||
|
*/
|
||||||
|
public static function getActivePsections()
|
||||||
|
{
|
||||||
|
return self::orderBy('psection_id')->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 車種区分名で検索
|
||||||
|
*
|
||||||
|
* @param string $subject 車種区分名
|
||||||
|
* @return Psection|null
|
||||||
|
*/
|
||||||
|
public static function findBySubject(string $subject): ?Psection
|
||||||
|
{
|
||||||
|
return self::where('psection_subject', $subject)->first();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文字列表現
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function __toString(): string
|
||||||
|
{
|
||||||
|
return sprintf(
|
||||||
|
'Psection[ID:%d, Subject:%s]',
|
||||||
|
$this->psection_id,
|
||||||
|
$this->psection_subject
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -33,3 +33,5 @@ class Ptype extends Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -72,3 +72,5 @@ class RegularContract extends Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,9 @@ namespace App\Providers;
|
|||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
use App\Services\ShjFourCService;
|
use App\Services\ShjFourCService;
|
||||||
use App\Services\ShjMailSendService;
|
use App\Services\ShjMailSendService;
|
||||||
|
use App\Services\ShjNineService;
|
||||||
|
use App\Services\ShjTenService;
|
||||||
|
use App\Services\ShjSixService;
|
||||||
|
|
||||||
class AppServiceProvider extends ServiceProvider
|
class AppServiceProvider extends ServiceProvider
|
||||||
{
|
{
|
||||||
@ -30,7 +33,41 @@ class AppServiceProvider extends ServiceProvider
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// SHJ-9売上集計処理サービスを登録
|
||||||
|
$this->app->singleton(ShjNineService::class, function ($app) {
|
||||||
|
return new ShjNineService(
|
||||||
|
$app->make(\App\Models\Park::class),
|
||||||
|
$app->make(\App\Models\RegularContract::class),
|
||||||
|
$app->make(\App\Models\EarningsSummary::class),
|
||||||
|
$app->make(\App\Models\Psection::class),
|
||||||
|
$app->make(\App\Models\Batch\BatchLog::class),
|
||||||
|
$app->make(\App\Models\OperatorQue::class)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// SHJ-10財政年度売上集計処理サービスを登録
|
||||||
|
$this->app->singleton(ShjTenService::class, function ($app) {
|
||||||
|
return new ShjTenService(
|
||||||
|
$app->make(\App\Models\Park::class),
|
||||||
|
$app->make(\App\Models\RegularContract::class),
|
||||||
|
$app->make(\App\Models\EarningsSummary::class),
|
||||||
|
$app->make(\App\Models\Psection::class),
|
||||||
|
$app->make(\App\Models\Batch\BatchLog::class),
|
||||||
|
$app->make(\App\Models\OperatorQue::class)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// SHJ-6サーバ死活監視処理サービスを登録
|
||||||
|
$this->app->singleton(ShjSixService::class, function ($app) {
|
||||||
|
return new ShjSixService(
|
||||||
|
$app->make(\App\Models\Device::class),
|
||||||
|
$app->make(\App\Models\HardwareCheckLog::class),
|
||||||
|
$app->make(\App\Models\PrintJobLog::class),
|
||||||
|
$app->make(\App\Models\Batch\BatchLog::class),
|
||||||
|
$app->make(\App\Models\OperatorQue::class),
|
||||||
|
$app->make(\App\Services\ShjMailSendService::class)
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -42,3 +42,4 @@ class LegacyServiceProvider extends ServiceProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -32,3 +32,5 @@ class FileService
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -25,3 +25,5 @@ class OperatorQueService
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
595
app/Services/ShjNineService.php
Normal file
595
app/Services/ShjNineService.php
Normal file
@ -0,0 +1,595 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Models\Park;
|
||||||
|
use App\Models\RegularContract;
|
||||||
|
use App\Models\EarningsSummary;
|
||||||
|
use App\Models\Psection;
|
||||||
|
use App\Models\Batch\BatchLog;
|
||||||
|
use App\Models\OperatorQue;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHJ-9 売上集計処理サービス
|
||||||
|
*
|
||||||
|
* 日次・月次・年次の売上集計処理を実行するビジネスロジック
|
||||||
|
* バッチ処理「SHJ-9売上集計」の核となる処理を担当
|
||||||
|
*/
|
||||||
|
class ShjNineService
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Park モデル
|
||||||
|
*
|
||||||
|
* @var Park
|
||||||
|
*/
|
||||||
|
protected $parkModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RegularContract モデル
|
||||||
|
*
|
||||||
|
* @var RegularContract
|
||||||
|
*/
|
||||||
|
protected $contractModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EarningsSummary モデル
|
||||||
|
*
|
||||||
|
* @var EarningsSummary
|
||||||
|
*/
|
||||||
|
protected $earningsSummaryModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Psection モデル
|
||||||
|
*
|
||||||
|
* @var Psection
|
||||||
|
*/
|
||||||
|
protected $psectionModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BatchLog モデル
|
||||||
|
*
|
||||||
|
* @var BatchLog
|
||||||
|
*/
|
||||||
|
protected $batchLogModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OperatorQue モデル
|
||||||
|
*
|
||||||
|
* @var OperatorQue
|
||||||
|
*/
|
||||||
|
protected $operatorQueModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* コンストラクタ
|
||||||
|
*
|
||||||
|
* @param Park $parkModel
|
||||||
|
* @param RegularContract $contractModel
|
||||||
|
* @param EarningsSummary $earningsSummaryModel
|
||||||
|
* @param Psection $psectionModel
|
||||||
|
* @param BatchLog $batchLogModel
|
||||||
|
* @param OperatorQue $operatorQueModel
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
Park $parkModel,
|
||||||
|
RegularContract $contractModel,
|
||||||
|
EarningsSummary $earningsSummaryModel,
|
||||||
|
Psection $psectionModel,
|
||||||
|
BatchLog $batchLogModel,
|
||||||
|
OperatorQue $operatorQueModel
|
||||||
|
) {
|
||||||
|
$this->parkModel = $parkModel;
|
||||||
|
$this->contractModel = $contractModel;
|
||||||
|
$this->earningsSummaryModel = $earningsSummaryModel;
|
||||||
|
$this->psectionModel = $psectionModel;
|
||||||
|
$this->batchLogModel = $batchLogModel;
|
||||||
|
$this->operatorQueModel = $operatorQueModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHJ-9 売上集計処理メイン実行
|
||||||
|
*
|
||||||
|
* 処理フロー:
|
||||||
|
* 【処理1】集計対象を設定する
|
||||||
|
* 【処理2】駐輪場マスタを取得する
|
||||||
|
* 【判断1】取得件数判定
|
||||||
|
* 【処理3】車種区分毎に算出する
|
||||||
|
* 【判断2】取得判定
|
||||||
|
* 【処理4】売上集計結果を削除→登録する
|
||||||
|
* 【処理5】オペレータキュー作成およびバッチ処理ログを作成する
|
||||||
|
*
|
||||||
|
* @param string $type 集計種別(daily/monthly/yearly)
|
||||||
|
* @param string $aggregationDate 集計対象日
|
||||||
|
* @return array 処理結果
|
||||||
|
*/
|
||||||
|
public function executeEarningsAggregation(string $type, string $aggregationDate): array
|
||||||
|
{
|
||||||
|
$batchLogId = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 【処理1】集計対象を設定する
|
||||||
|
$aggregationTarget = $this->setAggregationTarget($type, $aggregationDate);
|
||||||
|
|
||||||
|
// バッチ処理開始ログ作成
|
||||||
|
$batchLog = BatchLog::createBatchLog(
|
||||||
|
'shj9',
|
||||||
|
BatchLog::STATUS_START,
|
||||||
|
[
|
||||||
|
'type' => $type,
|
||||||
|
'aggregation_date' => $aggregationDate,
|
||||||
|
'aggregation_target' => $aggregationTarget
|
||||||
|
],
|
||||||
|
"SHJ-9 売上集計処理開始 ({$type})"
|
||||||
|
);
|
||||||
|
$batchLogId = $batchLog->id;
|
||||||
|
|
||||||
|
Log::info('SHJ-9 売上集計処理開始', [
|
||||||
|
'batch_log_id' => $batchLogId,
|
||||||
|
'type' => $type,
|
||||||
|
'aggregation_date' => $aggregationDate,
|
||||||
|
'aggregation_target' => $aggregationTarget
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 【処理2】駐輪場マスタを取得する
|
||||||
|
$parkInfo = $this->getParkInformation();
|
||||||
|
|
||||||
|
// 【判断1】取得件数判定
|
||||||
|
if (empty($parkInfo)) {
|
||||||
|
$message = '売上集計(' . $this->getTypeLabel($type) . '):駐輪場マスタが存在していません。';
|
||||||
|
|
||||||
|
// バッチログ更新
|
||||||
|
$batchLog->update([
|
||||||
|
'status' => BatchLog::STATUS_WARNING,
|
||||||
|
'end_time' => now(),
|
||||||
|
'message' => $message,
|
||||||
|
'success_count' => 1 // 処理は成功したが対象なし
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 【処理5】オペレータキュー作成
|
||||||
|
$this->createOperatorQueue($message, $batchLogId);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => true,
|
||||||
|
'message' => $message,
|
||||||
|
'processed_parks' => 0,
|
||||||
|
'summary_records' => 0,
|
||||||
|
'batch_log_id' => $batchLogId
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 【処理3】車種区分毎に算出する & 【処理4】売上集計結果を削除→登録する
|
||||||
|
$summaryRecords = 0;
|
||||||
|
$processedParks = 0;
|
||||||
|
|
||||||
|
foreach ($parkInfo as $park) {
|
||||||
|
$parkSummaryRecords = $this->processEarningsForPark($park, $aggregationTarget, $type);
|
||||||
|
|
||||||
|
if ($parkSummaryRecords > 0) {
|
||||||
|
$processedParks++;
|
||||||
|
$summaryRecords += $parkSummaryRecords;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 【判断2】取得判定
|
||||||
|
if ($summaryRecords === 0) {
|
||||||
|
$message = '対象なしの結果を設定する(契約)';
|
||||||
|
|
||||||
|
// バッチログ更新
|
||||||
|
$batchLog->update([
|
||||||
|
'status' => BatchLog::STATUS_WARNING,
|
||||||
|
'end_time' => now(),
|
||||||
|
'message' => $message,
|
||||||
|
'success_count' => 1
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 【処理5】オペレータキュー作成
|
||||||
|
$this->createOperatorQueue($message, $batchLogId);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => true,
|
||||||
|
'message' => $message,
|
||||||
|
'processed_parks' => $processedParks,
|
||||||
|
'summary_records' => 0,
|
||||||
|
'batch_log_id' => $batchLogId
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// バッチ処理完了ログ更新
|
||||||
|
$completionMessage = "SHJ-9 売上集計処理正常完了 ({$type}) - 駐輪場数: {$processedParks}, 集計レコード数: {$summaryRecords}";
|
||||||
|
$batchLog->update([
|
||||||
|
'status' => BatchLog::STATUS_SUCCESS,
|
||||||
|
'end_time' => now(),
|
||||||
|
'message' => $completionMessage,
|
||||||
|
'success_count' => 1
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 【処理5】オペレータキュー作成
|
||||||
|
$this->createOperatorQueue($completionMessage, $batchLogId);
|
||||||
|
|
||||||
|
Log::info('SHJ-9 売上集計処理完了', [
|
||||||
|
'batch_log_id' => $batchLogId,
|
||||||
|
'processed_parks' => $processedParks,
|
||||||
|
'summary_records' => $summaryRecords
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'SHJ-9 売上集計処理が正常に完了しました',
|
||||||
|
'processed_parks' => $processedParks,
|
||||||
|
'summary_records' => $summaryRecords,
|
||||||
|
'batch_log_id' => $batchLogId
|
||||||
|
];
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$errorMessage = 'SHJ-9 売上集計処理でエラーが発生: ' . $e->getMessage();
|
||||||
|
|
||||||
|
if (isset($batchLog) && $batchLog) {
|
||||||
|
$batchLog->update([
|
||||||
|
'status' => BatchLog::STATUS_ERROR,
|
||||||
|
'end_time' => now(),
|
||||||
|
'message' => $errorMessage,
|
||||||
|
'error_details' => $e->getMessage(),
|
||||||
|
'error_count' => 1
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::error('SHJ-9 売上集計処理エラー', [
|
||||||
|
'batch_log_id' => $batchLogId,
|
||||||
|
'exception' => $e->getMessage(),
|
||||||
|
'trace' => $e->getTraceAsString()
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => $errorMessage,
|
||||||
|
'details' => $e->getMessage(),
|
||||||
|
'batch_log_id' => $batchLogId
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【処理1】集計対象を設定する
|
||||||
|
*
|
||||||
|
* @param string $type 集計種別
|
||||||
|
* @param string $aggregationDate 集計対象日
|
||||||
|
* @return array 集計対象情報
|
||||||
|
*/
|
||||||
|
private function setAggregationTarget(string $type, string $aggregationDate): array
|
||||||
|
{
|
||||||
|
$date = Carbon::parse($aggregationDate);
|
||||||
|
|
||||||
|
switch ($type) {
|
||||||
|
case 'daily':
|
||||||
|
return [
|
||||||
|
'type' => 'daily',
|
||||||
|
'start_date' => $date->format('Y-m-d'),
|
||||||
|
'end_date' => $date->format('Y-m-d'),
|
||||||
|
'summary_type' => '日次'
|
||||||
|
];
|
||||||
|
|
||||||
|
case 'monthly':
|
||||||
|
return [
|
||||||
|
'type' => 'monthly',
|
||||||
|
'start_date' => $date->startOfMonth()->format('Y-m-d'),
|
||||||
|
'end_date' => $date->endOfMonth()->format('Y-m-d'),
|
||||||
|
'summary_type' => '月次'
|
||||||
|
];
|
||||||
|
|
||||||
|
case 'yearly':
|
||||||
|
return [
|
||||||
|
'type' => 'yearly',
|
||||||
|
'start_date' => $date->startOfYear()->format('Y-m-d'),
|
||||||
|
'end_date' => $date->endOfYear()->format('Y-m-d'),
|
||||||
|
'summary_type' => '年次'
|
||||||
|
];
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new \InvalidArgumentException("不正な集計種別: {$type}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【処理2】駐輪場マスタを取得する
|
||||||
|
*
|
||||||
|
* 仕様書のSQLクエリに基づく駐輪場情報取得
|
||||||
|
* SELECT 駐輪場ID, 駐輪場名
|
||||||
|
* FROM 駐輪場マスタ
|
||||||
|
* WHERE 閉設フラグ <> 1
|
||||||
|
* ORDER BY 駐輪場ふりがな
|
||||||
|
*
|
||||||
|
* @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 string $type 集計種別
|
||||||
|
* @return int 作成された集計レコード数
|
||||||
|
*/
|
||||||
|
private function processEarningsForPark($park, array $aggregationTarget, string $type): int
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// 【処理4】既存の売上集計結果を削除
|
||||||
|
$this->deleteExistingSummary($park->park_id, $aggregationTarget);
|
||||||
|
|
||||||
|
// 【処理3】車種区分毎に算出する
|
||||||
|
$psections = $this->getPsectionInformation();
|
||||||
|
$summaryRecords = 0;
|
||||||
|
|
||||||
|
foreach ($psections as $psection) {
|
||||||
|
$earningsData = $this->calculateEarningsForPsection(
|
||||||
|
$park->park_id,
|
||||||
|
$psection->psection_id,
|
||||||
|
$aggregationTarget
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($this->hasEarningsData($earningsData)) {
|
||||||
|
// 売上集計結果を登録
|
||||||
|
$this->createEarningsSummary($park, $psection, $aggregationTarget, $earningsData, $type);
|
||||||
|
$summaryRecords++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::info('駐輪場売上集計完了', [
|
||||||
|
'park_id' => $park->park_id,
|
||||||
|
'park_name' => $park->park_name,
|
||||||
|
'summary_records' => $summaryRecords
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $summaryRecords;
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('駐輪場売上集計エラー', [
|
||||||
|
'park_id' => $park->park_id,
|
||||||
|
'error' => $e->getMessage()
|
||||||
|
]);
|
||||||
|
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 車種区分情報取得
|
||||||
|
*
|
||||||
|
* @return array 車種区分情報
|
||||||
|
*/
|
||||||
|
private function getPsectionInformation(): array
|
||||||
|
{
|
||||||
|
return DB::table('psection')
|
||||||
|
->select(['psection_id', 'psection_subject'])
|
||||||
|
->get()
|
||||||
|
->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【処理3】車種区分毎に売上を算出する
|
||||||
|
*
|
||||||
|
* 4つの項目を計算:
|
||||||
|
* ①売上・件数
|
||||||
|
* ②一時金売上
|
||||||
|
* ③解約返戻金
|
||||||
|
* ④再発行金額・件数
|
||||||
|
*
|
||||||
|
* @param int $parkId 駐輪場ID
|
||||||
|
* @param int $psectionId 車種区分ID
|
||||||
|
* @param array $aggregationTarget 集計対象
|
||||||
|
* @return array 売上データ
|
||||||
|
*/
|
||||||
|
private function calculateEarningsForPsection(int $parkId, int $psectionId, array $aggregationTarget): array
|
||||||
|
{
|
||||||
|
$startDate = $aggregationTarget['start_date'];
|
||||||
|
$endDate = $aggregationTarget['end_date'];
|
||||||
|
|
||||||
|
// ①売上・件数(billing_amount)
|
||||||
|
$salesData = DB::table('regular_contract')
|
||||||
|
->select([
|
||||||
|
DB::raw('COUNT(*) as sales_count'),
|
||||||
|
DB::raw('COALESCE(SUM(billing_amount), 0) as sales_amount')
|
||||||
|
])
|
||||||
|
->where('park_id', $parkId)
|
||||||
|
->where('psection_id', $psectionId)
|
||||||
|
->where('contract_flag', 1)
|
||||||
|
->whereBetween('contract_payment_day', [$startDate, $endDate])
|
||||||
|
->whereNull('contract_cancelday')
|
||||||
|
->first();
|
||||||
|
|
||||||
|
// ②一時金売上(contract_money)
|
||||||
|
$temporaryData = DB::table('regular_contract')
|
||||||
|
->select([
|
||||||
|
DB::raw('COUNT(*) as temporary_count'),
|
||||||
|
DB::raw('COALESCE(SUM(contract_money), 0) as temporary_amount')
|
||||||
|
])
|
||||||
|
->where('park_id', $parkId)
|
||||||
|
->where('psection_id', $psectionId)
|
||||||
|
->where('contract_flag', 1)
|
||||||
|
->whereBetween('contract_payment_day', [$startDate, $endDate])
|
||||||
|
->whereNotNull('contract_money')
|
||||||
|
->where('contract_money', '>', 0)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
// ③解約返戻金(refunds)
|
||||||
|
$refundData = DB::table('regular_contract')
|
||||||
|
->select([
|
||||||
|
DB::raw('COUNT(*) as refund_count'),
|
||||||
|
DB::raw('COALESCE(SUM(refunds), 0) as refund_amount')
|
||||||
|
])
|
||||||
|
->where('park_id', $parkId)
|
||||||
|
->where('psection_id', $psectionId)
|
||||||
|
->whereBetween('contract_cancelday', [$startDate, $endDate])
|
||||||
|
->whereNotNull('refunds')
|
||||||
|
->where('refunds', '>', 0)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
// ④再発行金額・件数(seal_reissue_request)
|
||||||
|
$reissueData = DB::table('regular_contract')
|
||||||
|
->select([
|
||||||
|
DB::raw('COUNT(*) as reissue_count'),
|
||||||
|
DB::raw('COALESCE(SUM(contract_seal_issue), 0) as reissue_amount')
|
||||||
|
])
|
||||||
|
->where('park_id', $parkId)
|
||||||
|
->where('psection_id', $psectionId)
|
||||||
|
->where('seal_reissue_request', 1)
|
||||||
|
->whereBetween('updated_at', [$startDate, $endDate])
|
||||||
|
->first();
|
||||||
|
|
||||||
|
return [
|
||||||
|
'sales_count' => $salesData->sales_count ?? 0,
|
||||||
|
'sales_amount' => $salesData->sales_amount ?? 0,
|
||||||
|
'temporary_count' => $temporaryData->temporary_count ?? 0,
|
||||||
|
'temporary_amount' => $temporaryData->temporary_amount ?? 0,
|
||||||
|
'refund_count' => $refundData->refund_count ?? 0,
|
||||||
|
'refund_amount' => $refundData->refund_amount ?? 0,
|
||||||
|
'reissue_count' => $reissueData->reissue_count ?? 0,
|
||||||
|
'reissue_amount' => $reissueData->reissue_amount ?? 0
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 売上データの存在チェック
|
||||||
|
*
|
||||||
|
* @param array $earningsData 売上データ
|
||||||
|
* @return bool データが存在するかどうか
|
||||||
|
*/
|
||||||
|
private function hasEarningsData(array $earningsData): bool
|
||||||
|
{
|
||||||
|
return $earningsData['sales_count'] > 0 ||
|
||||||
|
$earningsData['temporary_count'] > 0 ||
|
||||||
|
$earningsData['refund_count'] > 0 ||
|
||||||
|
$earningsData['reissue_count'] > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【処理4】既存の売上集計結果を削除
|
||||||
|
*
|
||||||
|
* @param int $parkId 駐輪場ID
|
||||||
|
* @param array $aggregationTarget 集計対象
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function deleteExistingSummary(int $parkId, array $aggregationTarget): void
|
||||||
|
{
|
||||||
|
DB::table('earnings_summary')
|
||||||
|
->where('park_id', $parkId)
|
||||||
|
->where('summary_start_date', $aggregationTarget['start_date'])
|
||||||
|
->where('summary_end_date', $aggregationTarget['end_date'])
|
||||||
|
->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 売上集計結果を登録
|
||||||
|
*
|
||||||
|
* @param object $park 駐輪場情報
|
||||||
|
* @param object $psection 車種区分情報
|
||||||
|
* @param array $aggregationTarget 集計対象
|
||||||
|
* @param array $earningsData 売上データ
|
||||||
|
* @param string $type 集計種別
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function createEarningsSummary($park, $psection, array $aggregationTarget, array $earningsData, string $type): void
|
||||||
|
{
|
||||||
|
DB::table('earnings_summary')->insert([
|
||||||
|
'park_id' => $park->park_id,
|
||||||
|
'summary_type' => $aggregationTarget['summary_type'],
|
||||||
|
'summary_start_date' => $aggregationTarget['start_date'],
|
||||||
|
'summary_end_date' => $aggregationTarget['end_date'],
|
||||||
|
'earnings_date' => $aggregationTarget['end_date'], // 集計日として終了日を使用
|
||||||
|
'psection_id' => $psection->psection_id,
|
||||||
|
'usertype_subject1' => $psection->psection_subject,
|
||||||
|
'regular_new_count' => $earningsData['sales_count'],
|
||||||
|
'regular_new_amount' => $earningsData['sales_amount'],
|
||||||
|
'turnsum' => $earningsData['temporary_amount'],
|
||||||
|
'turnsum_count' => $earningsData['temporary_count'],
|
||||||
|
'refunds' => $earningsData['refund_amount'],
|
||||||
|
'reissue_count' => $earningsData['reissue_count'],
|
||||||
|
'reissue_amount' => $earningsData['reissue_amount'],
|
||||||
|
'summary_note' => "SHJ-9 {$type} 売上集計結果",
|
||||||
|
'created_at' => now(),
|
||||||
|
'updated_at' => now(),
|
||||||
|
'operator_id' => 0 // システム処理
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【処理5】オペレータキュー作成
|
||||||
|
*
|
||||||
|
* @param string $message メッセージ
|
||||||
|
* @param int $batchLogId バッチログID
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function createOperatorQueue(string $message, int $batchLogId): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
DB::table('operator_que')->insert([
|
||||||
|
'que_class' => 9, // SHJ-9用のクラス
|
||||||
|
'user_id' => null,
|
||||||
|
'contract_id' => null,
|
||||||
|
'park_id' => null,
|
||||||
|
'que_comment' => $message,
|
||||||
|
'que_status' => 1, // 完了
|
||||||
|
'que_status_comment' => 'バッチ処理完了',
|
||||||
|
'work_instructions' => "SHJ-9売上集計処理 BatchLogID: {$batchLogId}",
|
||||||
|
'created_at' => now(),
|
||||||
|
'updated_at' => now()
|
||||||
|
]);
|
||||||
|
|
||||||
|
Log::info('オペレータキュー作成完了', [
|
||||||
|
'batch_log_id' => $batchLogId,
|
||||||
|
'message' => $message
|
||||||
|
]);
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('オペレータキュー作成エラー', [
|
||||||
|
'batch_log_id' => $batchLogId,
|
||||||
|
'error' => $e->getMessage()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 集計種別のラベル取得
|
||||||
|
*
|
||||||
|
* @param string $type 集計種別
|
||||||
|
* @return string ラベル
|
||||||
|
*/
|
||||||
|
private function getTypeLabel(string $type): string
|
||||||
|
{
|
||||||
|
switch ($type) {
|
||||||
|
case 'daily':
|
||||||
|
return '日次';
|
||||||
|
case 'monthly':
|
||||||
|
return '月次';
|
||||||
|
case 'yearly':
|
||||||
|
return '年次';
|
||||||
|
default:
|
||||||
|
return $type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
710
app/Services/ShjSixService.php
Normal file
710
app/Services/ShjSixService.php
Normal file
@ -0,0 +1,710 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Models\Device;
|
||||||
|
use App\Models\HardwareCheckLog;
|
||||||
|
use App\Models\PrintJobLog;
|
||||||
|
use App\Models\Batch\BatchLog;
|
||||||
|
use App\Models\OperatorQue;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Models\Park;
|
||||||
|
use App\Services\ShjMailSendService;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHJ-6 サーバ死活監視処理サービス
|
||||||
|
*
|
||||||
|
* サーバとデバイスの死活監視、ハードウェア状態監視、プリンタログ監視を実行
|
||||||
|
* 異常検出時のメール通知機能を含む統合モニタリングサービス
|
||||||
|
*/
|
||||||
|
class ShjSixService
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Device モデル
|
||||||
|
*
|
||||||
|
* @var Device
|
||||||
|
*/
|
||||||
|
protected $deviceModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HardwareCheckLog モデル
|
||||||
|
*
|
||||||
|
* @var HardwareCheckLog
|
||||||
|
*/
|
||||||
|
protected $hardwareCheckLogModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PrintJobLog モデル
|
||||||
|
*
|
||||||
|
* @var PrintJobLog
|
||||||
|
*/
|
||||||
|
protected $printJobLogModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BatchLog モデル
|
||||||
|
*
|
||||||
|
* @var BatchLog
|
||||||
|
*/
|
||||||
|
protected $batchLogModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OperatorQue モデル
|
||||||
|
*
|
||||||
|
* @var OperatorQue
|
||||||
|
*/
|
||||||
|
protected $operatorQueModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ShjMailSendService
|
||||||
|
*
|
||||||
|
* @var ShjMailSendService
|
||||||
|
*/
|
||||||
|
protected $mailSendService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 固定メールアドレス(DB反映NG時用)
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const FIXED_EMAIL_ADDRESS = 'system-alert@so-manager.com';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* プリンタログ監視期間(分)
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
const PRINTER_LOG_MONITOR_MINUTES = 15;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* コンストラクタ
|
||||||
|
*
|
||||||
|
* @param Device $deviceModel
|
||||||
|
* @param HardwareCheckLog $hardwareCheckLogModel
|
||||||
|
* @param PrintJobLog $printJobLogModel
|
||||||
|
* @param BatchLog $batchLogModel
|
||||||
|
* @param OperatorQue $operatorQueModel
|
||||||
|
* @param ShjMailSendService $mailSendService
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
Device $deviceModel,
|
||||||
|
HardwareCheckLog $hardwareCheckLogModel,
|
||||||
|
PrintJobLog $printJobLogModel,
|
||||||
|
BatchLog $batchLogModel,
|
||||||
|
OperatorQue $operatorQueModel,
|
||||||
|
ShjMailSendService $mailSendService
|
||||||
|
) {
|
||||||
|
$this->deviceModel = $deviceModel;
|
||||||
|
$this->hardwareCheckLogModel = $hardwareCheckLogModel;
|
||||||
|
$this->printJobLogModel = $printJobLogModel;
|
||||||
|
$this->batchLogModel = $batchLogModel;
|
||||||
|
$this->operatorQueModel = $operatorQueModel;
|
||||||
|
$this->mailSendService = $mailSendService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHJ-6 サーバ死活監視処理メイン実行
|
||||||
|
*
|
||||||
|
* 処理フロー:
|
||||||
|
* 【処理1】サーバ死活監視(DBアクセス)
|
||||||
|
* 【処理2】デバイス管理マスタを取得する
|
||||||
|
* 【処理3】デバイス毎のハードウェア状態を取得する
|
||||||
|
* 【処理4】プリンタ制御プログラムログを取得する
|
||||||
|
* 【判断3】エラーログ有無
|
||||||
|
* 【処理5】バッチ処理ログを作成する
|
||||||
|
* ※ 異常時は共通A処理を実行
|
||||||
|
*
|
||||||
|
* @return array 処理結果
|
||||||
|
*/
|
||||||
|
public function executeServerMonitoring(): array
|
||||||
|
{
|
||||||
|
$batchLogId = null;
|
||||||
|
$warnings = [];
|
||||||
|
$errorDetails = [];
|
||||||
|
|
||||||
|
try {
|
||||||
|
// バッチ処理開始ログ作成
|
||||||
|
$batchLog = BatchLog::createBatchLog(
|
||||||
|
'shj6',
|
||||||
|
BatchLog::STATUS_START,
|
||||||
|
[],
|
||||||
|
'SHJ-6 サーバ死活監視処理開始'
|
||||||
|
);
|
||||||
|
$batchLogId = $batchLog->id;
|
||||||
|
|
||||||
|
Log::info('SHJ-6 サーバ死活監視処理開始', [
|
||||||
|
'batch_log_id' => $batchLogId
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 【処理1】サーバ死活監視(DBアクセス)
|
||||||
|
$dbAccessResult = $this->checkDatabaseAccess();
|
||||||
|
if (!$dbAccessResult['success']) {
|
||||||
|
// DB接続NGの場合は共通A処理実行
|
||||||
|
$this->executeCommonProcessA($batchLogId, 'DB接続エラー: ' . $dbAccessResult['message']);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'データベース接続エラーが発生しました',
|
||||||
|
'error_details' => [$dbAccessResult['message']],
|
||||||
|
'batch_log_id' => $batchLogId
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 【処理2】デバイス管理マスタを取得する
|
||||||
|
$devices = $this->getDeviceManagementData();
|
||||||
|
Log::info('デバイス管理マスタ取得完了', [
|
||||||
|
'device_count' => count($devices)
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 【処理3】デバイス毎のハードウェア状態を取得する
|
||||||
|
$hardwareStatusResult = $this->getHardwareStatus($devices);
|
||||||
|
if (!$hardwareStatusResult['success']) {
|
||||||
|
// ハードウェア状態取得できなかった場合は共通A処理実行
|
||||||
|
$this->executeCommonProcessA($batchLogId, 'ハードウェア状態取得エラー: ' . $hardwareStatusResult['message']);
|
||||||
|
$warnings[] = 'ハードウェア状態の一部で異常を検出しました';
|
||||||
|
$errorDetails[] = $hardwareStatusResult['message'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 【処理4】プリンタ制御プログラムログを取得する
|
||||||
|
$printerLogResult = $this->getPrinterControlLogs();
|
||||||
|
|
||||||
|
// 【判断3】エラーログ有無
|
||||||
|
if ($printerLogResult['has_errors']) {
|
||||||
|
// エラーログ有の場合は共通A処理実行
|
||||||
|
$this->executeCommonProcessA($batchLogId, 'プリンタエラーログ検出: ' . $printerLogResult['error_summary']);
|
||||||
|
$warnings[] = 'プリンタ制御でエラーが検出されました';
|
||||||
|
$errorDetails[] = $printerLogResult['error_summary'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 【処理5】バッチ処理ログを作成する
|
||||||
|
$monitoringSummary = $this->createMonitoringSummary($devices, $hardwareStatusResult, $printerLogResult);
|
||||||
|
|
||||||
|
$status = empty($warnings) ? BatchLog::STATUS_SUCCESS : BatchLog::STATUS_WARNING;
|
||||||
|
$message = empty($warnings) ?
|
||||||
|
'SHJ-6 サーバ死活監視処理正常完了' :
|
||||||
|
'SHJ-6 サーバ死活監視処理完了(警告あり)';
|
||||||
|
|
||||||
|
$batchLog->update([
|
||||||
|
'status' => $status,
|
||||||
|
'end_time' => now(),
|
||||||
|
'message' => $message,
|
||||||
|
'success_count' => 1
|
||||||
|
]);
|
||||||
|
|
||||||
|
Log::info('SHJ-6 サーバ死活監視処理完了', [
|
||||||
|
'batch_log_id' => $batchLogId,
|
||||||
|
'monitoring_summary' => $monitoringSummary,
|
||||||
|
'warnings' => $warnings
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'SHJ-6 サーバ死活監視処理が完了しました',
|
||||||
|
'monitoring_summary' => $monitoringSummary,
|
||||||
|
'warnings' => $warnings,
|
||||||
|
'error_details' => $errorDetails,
|
||||||
|
'batch_log_id' => $batchLogId
|
||||||
|
];
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$errorMessage = 'SHJ-6 サーバ死活監視処理でエラーが発生: ' . $e->getMessage();
|
||||||
|
|
||||||
|
if (isset($batchLog) && $batchLog) {
|
||||||
|
$batchLog->update([
|
||||||
|
'status' => BatchLog::STATUS_ERROR,
|
||||||
|
'end_time' => now(),
|
||||||
|
'message' => $errorMessage,
|
||||||
|
'error_details' => $e->getMessage(),
|
||||||
|
'error_count' => 1
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 例外発生時も共通A処理実行
|
||||||
|
$this->executeCommonProcessA($batchLogId, $errorMessage);
|
||||||
|
|
||||||
|
Log::error('SHJ-6 サーバ死活監視処理エラー', [
|
||||||
|
'batch_log_id' => $batchLogId,
|
||||||
|
'exception' => $e->getMessage(),
|
||||||
|
'trace' => $e->getTraceAsString()
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => $errorMessage,
|
||||||
|
'error_details' => [$e->getMessage()],
|
||||||
|
'batch_log_id' => $batchLogId
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【処理1】サーバ死活監視(DBアクセス)
|
||||||
|
*
|
||||||
|
* @return array アクセス結果
|
||||||
|
*/
|
||||||
|
private function checkDatabaseAccess(): array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// 設定マスタテーブルへの簡単なクエリでDB接続確認
|
||||||
|
$result = DB::select('SELECT 1 as test');
|
||||||
|
|
||||||
|
if (empty($result)) {
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'データベースクエリの結果が空です'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::info('データベース接続確認成功');
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'データベース接続正常'
|
||||||
|
];
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('データベース接続エラー', [
|
||||||
|
'error' => $e->getMessage()
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => $e->getMessage()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【処理2】デバイス管理マスタを取得する
|
||||||
|
*
|
||||||
|
* @return array デバイス情報
|
||||||
|
*/
|
||||||
|
private function getDeviceManagementData(): array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$devices = DB::table('device')
|
||||||
|
->select([
|
||||||
|
'device_id',
|
||||||
|
'park_id',
|
||||||
|
'device_type',
|
||||||
|
'device_subject',
|
||||||
|
'device_identifier',
|
||||||
|
'device_work',
|
||||||
|
'device_workstart',
|
||||||
|
'device_replace',
|
||||||
|
'device_remarks',
|
||||||
|
'operator_id'
|
||||||
|
])
|
||||||
|
->where('device_workstart', '<=', now())
|
||||||
|
->whereNull('device_replace')
|
||||||
|
->get()
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
Log::info('デバイス管理マスタ取得完了', [
|
||||||
|
'device_count' => count($devices)
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $devices;
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('デバイス管理マスタ取得エラー', [
|
||||||
|
'error' => $e->getMessage()
|
||||||
|
]);
|
||||||
|
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【処理3】デバイス毎のハードウェア状態を取得する
|
||||||
|
*
|
||||||
|
* @param array $devices デバイス一覧
|
||||||
|
* @return array ハードウェア状態結果
|
||||||
|
*/
|
||||||
|
private function getHardwareStatus(array $devices): array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$normalDevices = 0;
|
||||||
|
$abnormalDevices = 0;
|
||||||
|
$abnormalDetails = [];
|
||||||
|
|
||||||
|
foreach ($devices as $device) {
|
||||||
|
$latestStatus = HardwareCheckLog::getLatestStatusByDevice($device->device_id);
|
||||||
|
|
||||||
|
if (!$latestStatus) {
|
||||||
|
$abnormalDevices++;
|
||||||
|
$abnormalDetails[] = "デバイスID {$device->device_id}: ハードウェア状態ログが存在しません";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($latestStatus->isNormal()) {
|
||||||
|
$normalDevices++;
|
||||||
|
} else {
|
||||||
|
$abnormalDevices++;
|
||||||
|
$abnormalDetails[] = "デバイスID {$device->device_id}: {$latestStatus->getStatusNameAttribute()} - {$latestStatus->status_comment}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::info('ハードウェア状態取得完了', [
|
||||||
|
'total_devices' => count($devices),
|
||||||
|
'normal_devices' => $normalDevices,
|
||||||
|
'abnormal_devices' => $abnormalDevices
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => $abnormalDevices === 0,
|
||||||
|
'total_devices' => count($devices),
|
||||||
|
'normal_devices' => $normalDevices,
|
||||||
|
'abnormal_devices' => $abnormalDevices,
|
||||||
|
'abnormal_details' => $abnormalDetails,
|
||||||
|
'message' => $abnormalDevices > 0 ?
|
||||||
|
"{$abnormalDevices}台のデバイスで異常を検出" :
|
||||||
|
'全デバイス正常'
|
||||||
|
];
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('ハードウェア状態取得エラー', [
|
||||||
|
'error' => $e->getMessage()
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => $e->getMessage(),
|
||||||
|
'abnormal_details' => ["ハードウェア状態取得中にエラーが発生: " . $e->getMessage()]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【処理4】プリンタ制御プログラムログを取得する
|
||||||
|
*
|
||||||
|
* @return array プリンタログ結果
|
||||||
|
*/
|
||||||
|
private function getPrinterControlLogs(): array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// 過去15分間のエラーログを取得
|
||||||
|
$errorLogs = PrintJobLog::getRecentErrorLogs();
|
||||||
|
|
||||||
|
$hasErrors = $errorLogs->count() > 0;
|
||||||
|
$errorSummary = '';
|
||||||
|
$errorDetails = [];
|
||||||
|
|
||||||
|
if ($hasErrors) {
|
||||||
|
$errorsByCode = $errorLogs->groupBy('error_code');
|
||||||
|
$errorSummaryParts = [];
|
||||||
|
|
||||||
|
foreach ($errorsByCode as $errorCode => $logs) {
|
||||||
|
$count = $logs->count();
|
||||||
|
$errorSummaryParts[] = "エラーコード{$errorCode}: {$count}件";
|
||||||
|
|
||||||
|
foreach ($logs as $log) {
|
||||||
|
$errorDetails[] = sprintf(
|
||||||
|
"[%s] %s - エラーコード: %d, %s",
|
||||||
|
$log->created_at->format('Y-m-d H:i:s'),
|
||||||
|
$log->process_name,
|
||||||
|
$log->error_code,
|
||||||
|
$log->status_comment
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$errorSummary = implode(', ', $errorSummaryParts);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::info('プリンタ制御プログラムログ取得完了', [
|
||||||
|
'monitoring_period_minutes' => self::PRINTER_LOG_MONITOR_MINUTES,
|
||||||
|
'error_logs_count' => $errorLogs->count(),
|
||||||
|
'has_errors' => $hasErrors
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => true,
|
||||||
|
'has_errors' => $hasErrors,
|
||||||
|
'error_count' => $errorLogs->count(),
|
||||||
|
'error_summary' => $errorSummary,
|
||||||
|
'error_details' => $errorDetails,
|
||||||
|
'monitoring_period' => self::PRINTER_LOG_MONITOR_MINUTES . '分間'
|
||||||
|
];
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('プリンタ制御プログラムログ取得エラー', [
|
||||||
|
'error' => $e->getMessage()
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'has_errors' => true,
|
||||||
|
'error_summary' => 'ログ取得エラー: ' . $e->getMessage(),
|
||||||
|
'error_details' => ["プリンタログ取得中にエラーが発生: " . $e->getMessage()]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 監視結果サマリーを作成
|
||||||
|
*
|
||||||
|
* @param array $devices デバイス一覧
|
||||||
|
* @param array $hardwareResult ハードウェア結果
|
||||||
|
* @param array $printerResult プリンタ結果
|
||||||
|
* @return string 監視サマリー
|
||||||
|
*/
|
||||||
|
private function createMonitoringSummary(array $devices, array $hardwareResult, array $printerResult): string
|
||||||
|
{
|
||||||
|
$summary = [
|
||||||
|
'デバイス数: ' . count($devices),
|
||||||
|
'ハードウェア正常: ' . ($hardwareResult['normal_devices'] ?? 0) . '台',
|
||||||
|
'ハードウェア異常: ' . ($hardwareResult['abnormal_devices'] ?? 0) . '台',
|
||||||
|
'プリンタエラー: ' . ($printerResult['error_count'] ?? 0) . '件'
|
||||||
|
];
|
||||||
|
|
||||||
|
return implode(', ', $summary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 共通A処理:監視結果を反映
|
||||||
|
*
|
||||||
|
* @param int|null $batchLogId バッチログID
|
||||||
|
* @param string $alertMessage アラートメッセージ
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function executeCommonProcessA(?int $batchLogId, string $alertMessage): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Log::info('共通A処理開始', [
|
||||||
|
'batch_log_id' => $batchLogId,
|
||||||
|
'alert_message' => $alertMessage
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 【共通判断1】DB反映可否判定
|
||||||
|
$canReflectToDb = $this->canReflectToDatabase();
|
||||||
|
|
||||||
|
if ($canReflectToDb) {
|
||||||
|
// 【共通処理1】オペレータキューを登録する
|
||||||
|
$this->registerOperatorQueue($alertMessage, $batchLogId);
|
||||||
|
|
||||||
|
// 【共通処理2】メール送信対象オペレータを取得する
|
||||||
|
$operators = $this->getMailTargetOperators();
|
||||||
|
|
||||||
|
// 【共通判断2】送信対象有無
|
||||||
|
if (!empty($operators)) {
|
||||||
|
foreach ($operators as $operator) {
|
||||||
|
$this->sendAlertMail($operator['email'], $alertMessage, 'オペレータ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 【共通処理3】駐輪場管理者を取得する
|
||||||
|
$parkManagers = $this->getParkManagers();
|
||||||
|
|
||||||
|
// 【共通判断3】送信対象有無
|
||||||
|
if (!empty($parkManagers)) {
|
||||||
|
foreach ($parkManagers as $manager) {
|
||||||
|
$this->sendAlertMail($manager['email'], $alertMessage, '駐輪場管理者');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// DB反映NGの場合は固定メールアドレスに送信
|
||||||
|
$this->sendAlertMail(self::FIXED_EMAIL_ADDRESS, $alertMessage, 'システム管理者');
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::info('共通A処理完了', [
|
||||||
|
'batch_log_id' => $batchLogId
|
||||||
|
]);
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('共通A処理エラー', [
|
||||||
|
'batch_log_id' => $batchLogId,
|
||||||
|
'error' => $e->getMessage()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DB反映可否判定
|
||||||
|
*
|
||||||
|
* @return bool 反映可能かどうか
|
||||||
|
*/
|
||||||
|
private function canReflectToDatabase(): bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// 簡単なINSERTテストでDB反映可否を確認
|
||||||
|
DB::beginTransaction();
|
||||||
|
$testId = DB::table('operator_que')->insertGetId([
|
||||||
|
'que_class' => 6,
|
||||||
|
'que_comment' => 'DB反映テスト',
|
||||||
|
'que_status' => 0,
|
||||||
|
'created_at' => now(),
|
||||||
|
'updated_at' => now()
|
||||||
|
]);
|
||||||
|
|
||||||
|
// テストレコードを削除
|
||||||
|
DB::table('operator_que')->where('que_id', $testId)->delete();
|
||||||
|
DB::commit();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
DB::rollBack();
|
||||||
|
Log::warning('DB反映不可', ['error' => $e->getMessage()]);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* オペレータキューを登録
|
||||||
|
*
|
||||||
|
* @param string $alertMessage アラートメッセージ
|
||||||
|
* @param int|null $batchLogId バッチログID
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function registerOperatorQueue(string $alertMessage, ?int $batchLogId): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
OperatorQue::create([
|
||||||
|
'que_class' => 6, // SHJ-6用のクラス
|
||||||
|
'user_id' => null,
|
||||||
|
'contract_id' => null,
|
||||||
|
'park_id' => null,
|
||||||
|
'que_comment' => $alertMessage,
|
||||||
|
'que_status' => 0, // 待機中
|
||||||
|
'que_status_comment' => 'システム監視アラート',
|
||||||
|
'work_instructions' => "SHJ-6監視処理 BatchLogID: {$batchLogId}",
|
||||||
|
'created_at' => now(),
|
||||||
|
'updated_at' => now()
|
||||||
|
]);
|
||||||
|
|
||||||
|
Log::info('オペレータキュー登録完了', [
|
||||||
|
'batch_log_id' => $batchLogId,
|
||||||
|
'alert_message' => $alertMessage
|
||||||
|
]);
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('オペレータキュー登録エラー', [
|
||||||
|
'batch_log_id' => $batchLogId,
|
||||||
|
'error' => $e->getMessage()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* メール送信対象オペレータを取得
|
||||||
|
*
|
||||||
|
* @return array オペレータ一覧
|
||||||
|
*/
|
||||||
|
private function getMailTargetOperators(): array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// user_typeがオペレータのユーザーを取得(仮の条件)
|
||||||
|
$operators = DB::table('users')
|
||||||
|
->select(['user_id', 'email', 'name'])
|
||||||
|
->where('user_type', 'operator') // 実際のテーブル構造に合わせて調整
|
||||||
|
->whereNotNull('email')
|
||||||
|
->where('email', '!=', '')
|
||||||
|
->get()
|
||||||
|
->map(function ($user) {
|
||||||
|
return [
|
||||||
|
'user_id' => $user->user_id,
|
||||||
|
'email' => $user->email,
|
||||||
|
'name' => $user->name ?? 'オペレータ'
|
||||||
|
];
|
||||||
|
})
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
Log::info('メール送信対象オペレータ取得完了', [
|
||||||
|
'operator_count' => count($operators)
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $operators;
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('メール送信対象オペレータ取得エラー', [
|
||||||
|
'error' => $e->getMessage()
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 駐輪場管理者を取得
|
||||||
|
*
|
||||||
|
* @return array 駐輪場管理者一覧
|
||||||
|
*/
|
||||||
|
private function getParkManagers(): array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// 駐輪場管理者を取得(仮の条件)
|
||||||
|
$managers = DB::table('users')
|
||||||
|
->select(['user_id', 'email', 'name'])
|
||||||
|
->where('user_type', 'park_manager') // 実際のテーブル構造に合わせて調整
|
||||||
|
->whereNotNull('email')
|
||||||
|
->where('email', '!=', '')
|
||||||
|
->get()
|
||||||
|
->map(function ($user) {
|
||||||
|
return [
|
||||||
|
'user_id' => $user->user_id,
|
||||||
|
'email' => $user->email,
|
||||||
|
'name' => $user->name ?? '駐輪場管理者'
|
||||||
|
];
|
||||||
|
})
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
Log::info('駐輪場管理者取得完了', [
|
||||||
|
'manager_count' => count($managers)
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $managers;
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('駐輪場管理者取得エラー', [
|
||||||
|
'error' => $e->getMessage()
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* アラートメールを送信
|
||||||
|
*
|
||||||
|
* @param string $email メールアドレス
|
||||||
|
* @param string $alertMessage アラートメッセージ
|
||||||
|
* @param string $recipientType 受信者タイプ
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function sendAlertMail(string $email, string $alertMessage, string $recipientType): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// SHJメール送信機能を使用(メールテンプレートID=1を使用、実際の値に調整)
|
||||||
|
$result = $this->mailSendService->executeMailSend(
|
||||||
|
$email,
|
||||||
|
'', // 予備メールアドレスは空
|
||||||
|
1 // システムアラート用メールテンプレートID
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($result['success']) {
|
||||||
|
Log::info('アラートメール送信成功', [
|
||||||
|
'email' => $email,
|
||||||
|
'recipient_type' => $recipientType,
|
||||||
|
'alert_message' => $alertMessage
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
Log::error('アラートメール送信失敗', [
|
||||||
|
'email' => $email,
|
||||||
|
'recipient_type' => $recipientType,
|
||||||
|
'error' => $result['message']
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('アラートメール送信エラー', [
|
||||||
|
'email' => $email,
|
||||||
|
'recipient_type' => $recipientType,
|
||||||
|
'error' => $e->getMessage()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
583
app/Services/ShjTenService.php
Normal file
583
app/Services/ShjTenService.php
Normal file
@ -0,0 +1,583 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Models\Park;
|
||||||
|
use App\Models\RegularContract;
|
||||||
|
use App\Models\EarningsSummary;
|
||||||
|
use App\Models\Psection;
|
||||||
|
use App\Models\Batch\BatchLog;
|
||||||
|
use App\Models\OperatorQue;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHJ-10 売上集計処理サービス
|
||||||
|
*
|
||||||
|
* 財政年度ベースの年次・月次売上集計処理を実行するビジネスロジック
|
||||||
|
* バッチ処理「SHJ-10売上集計」の核となる処理を担当
|
||||||
|
*/
|
||||||
|
class ShjTenService
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Park モデル
|
||||||
|
*
|
||||||
|
* @var Park
|
||||||
|
*/
|
||||||
|
protected $parkModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RegularContract モデル
|
||||||
|
*
|
||||||
|
* @var RegularContract
|
||||||
|
*/
|
||||||
|
protected $contractModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EarningsSummary モデル
|
||||||
|
*
|
||||||
|
* @var EarningsSummary
|
||||||
|
*/
|
||||||
|
protected $earningsSummaryModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Psection モデル
|
||||||
|
*
|
||||||
|
* @var Psection
|
||||||
|
*/
|
||||||
|
protected $psectionModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BatchLog モデル
|
||||||
|
*
|
||||||
|
* @var BatchLog
|
||||||
|
*/
|
||||||
|
protected $batchLogModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OperatorQue モデル
|
||||||
|
*
|
||||||
|
* @var OperatorQue
|
||||||
|
*/
|
||||||
|
protected $operatorQueModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 財政年度開始月
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
const FISCAL_START_MONTH = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* コンストラクタ
|
||||||
|
*
|
||||||
|
* @param Park $parkModel
|
||||||
|
* @param RegularContract $contractModel
|
||||||
|
* @param EarningsSummary $earningsSummaryModel
|
||||||
|
* @param Psection $psectionModel
|
||||||
|
* @param BatchLog $batchLogModel
|
||||||
|
* @param OperatorQue $operatorQueModel
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
Park $parkModel,
|
||||||
|
RegularContract $contractModel,
|
||||||
|
EarningsSummary $earningsSummaryModel,
|
||||||
|
Psection $psectionModel,
|
||||||
|
BatchLog $batchLogModel,
|
||||||
|
OperatorQue $operatorQueModel
|
||||||
|
) {
|
||||||
|
$this->parkModel = $parkModel;
|
||||||
|
$this->contractModel = $contractModel;
|
||||||
|
$this->earningsSummaryModel = $earningsSummaryModel;
|
||||||
|
$this->psectionModel = $psectionModel;
|
||||||
|
$this->batchLogModel = $batchLogModel;
|
||||||
|
$this->operatorQueModel = $operatorQueModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHJ-10 財政年度売上集計処理メイン実行
|
||||||
|
*
|
||||||
|
* 処理フロー:
|
||||||
|
* 【処理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
|
||||||
|
{
|
||||||
|
$batchLogId = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 【処理1】集計対象を設定する(財政年度ベース)
|
||||||
|
$aggregationTarget = $this->setFiscalAggregationTarget($fiscalPeriod);
|
||||||
|
|
||||||
|
// バッチ処理開始ログ作成
|
||||||
|
$batchLog = BatchLog::createBatchLog(
|
||||||
|
'shj10',
|
||||||
|
BatchLog::STATUS_START,
|
||||||
|
[
|
||||||
|
'type' => $type,
|
||||||
|
'target' => $target,
|
||||||
|
'fiscal_period' => $fiscalPeriod,
|
||||||
|
'aggregation_target' => $aggregationTarget
|
||||||
|
],
|
||||||
|
"SHJ-10 売上集計処理開始 ({$type}: {$fiscalPeriod['target_label']})"
|
||||||
|
);
|
||||||
|
$batchLogId = $batchLog->id;
|
||||||
|
|
||||||
|
Log::info('SHJ-10 売上集計処理開始', [
|
||||||
|
'batch_log_id' => $batchLogId,
|
||||||
|
'type' => $type,
|
||||||
|
'target' => $target,
|
||||||
|
'fiscal_period' => $fiscalPeriod,
|
||||||
|
'aggregation_target' => $aggregationTarget
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 【処理2】駐輪場マスタを取得する
|
||||||
|
$parkInfo = $this->getParkInformation();
|
||||||
|
|
||||||
|
// 【判断1】取得件数判定
|
||||||
|
if (empty($parkInfo)) {
|
||||||
|
$typeLabel = $this->getTypeLabel($type);
|
||||||
|
$message = "売上集計({$typeLabel}):駐輪場マスタが存在していません。";
|
||||||
|
|
||||||
|
// バッチログ更新
|
||||||
|
$batchLog->update([
|
||||||
|
'status' => BatchLog::STATUS_WARNING,
|
||||||
|
'end_time' => now(),
|
||||||
|
'message' => $message,
|
||||||
|
'success_count' => 1 // 処理は成功したが対象なし
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 【処理5】オペレータキュー作成
|
||||||
|
$this->createOperatorQueue($message, $batchLogId);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => true,
|
||||||
|
'message' => $message,
|
||||||
|
'processed_parks' => 0,
|
||||||
|
'summary_records' => 0,
|
||||||
|
'batch_log_id' => $batchLogId
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 【処理3】車種区分毎に算出する & 【処理4】売上集計結果を削除→登録する
|
||||||
|
$summaryRecords = 0;
|
||||||
|
$processedParks = 0;
|
||||||
|
|
||||||
|
foreach ($parkInfo as $park) {
|
||||||
|
$parkSummaryRecords = $this->processFiscalEarningsForPark($park, $aggregationTarget, $fiscalPeriod);
|
||||||
|
|
||||||
|
if ($parkSummaryRecords > 0) {
|
||||||
|
$processedParks++;
|
||||||
|
$summaryRecords += $parkSummaryRecords;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 【判断2】取得判定
|
||||||
|
if ($summaryRecords === 0) {
|
||||||
|
$message = '対象なしの結果を設定する(契約)';
|
||||||
|
|
||||||
|
// バッチログ更新
|
||||||
|
$batchLog->update([
|
||||||
|
'status' => BatchLog::STATUS_WARNING,
|
||||||
|
'end_time' => now(),
|
||||||
|
'message' => $message,
|
||||||
|
'success_count' => 1
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 【処理5】オペレータキュー作成
|
||||||
|
$this->createOperatorQueue($message, $batchLogId);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => true,
|
||||||
|
'message' => $message,
|
||||||
|
'processed_parks' => $processedParks,
|
||||||
|
'summary_records' => 0,
|
||||||
|
'batch_log_id' => $batchLogId
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// バッチ処理完了ログ更新
|
||||||
|
$completionMessage = "SHJ-10 売上集計処理正常完了 ({$type}: {$fiscalPeriod['target_label']}) - 駐輪場数: {$processedParks}, 集計レコード数: {$summaryRecords}";
|
||||||
|
$batchLog->update([
|
||||||
|
'status' => BatchLog::STATUS_SUCCESS,
|
||||||
|
'end_time' => now(),
|
||||||
|
'message' => $completionMessage,
|
||||||
|
'success_count' => 1
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 【処理5】オペレータキュー作成
|
||||||
|
$this->createOperatorQueue($completionMessage, $batchLogId);
|
||||||
|
|
||||||
|
Log::info('SHJ-10 売上集計処理完了', [
|
||||||
|
'batch_log_id' => $batchLogId,
|
||||||
|
'processed_parks' => $processedParks,
|
||||||
|
'summary_records' => $summaryRecords
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'SHJ-10 売上集計処理が正常に完了しました',
|
||||||
|
'processed_parks' => $processedParks,
|
||||||
|
'summary_records' => $summaryRecords,
|
||||||
|
'batch_log_id' => $batchLogId
|
||||||
|
];
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$errorMessage = 'SHJ-10 売上集計処理でエラーが発生: ' . $e->getMessage();
|
||||||
|
|
||||||
|
if (isset($batchLog) && $batchLog) {
|
||||||
|
$batchLog->update([
|
||||||
|
'status' => BatchLog::STATUS_ERROR,
|
||||||
|
'end_time' => now(),
|
||||||
|
'message' => $errorMessage,
|
||||||
|
'error_details' => $e->getMessage(),
|
||||||
|
'error_count' => 1
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::error('SHJ-10 売上集計処理エラー', [
|
||||||
|
'batch_log_id' => $batchLogId,
|
||||||
|
'exception' => $e->getMessage(),
|
||||||
|
'trace' => $e->getTraceAsString()
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => $errorMessage,
|
||||||
|
'details' => $e->getMessage(),
|
||||||
|
'batch_log_id' => $batchLogId
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【処理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】駐輪場マスタを取得する
|
||||||
|
*
|
||||||
|
* 仕様書のSQLクエリに基づく駐輪場情報取得
|
||||||
|
* SELECT 駐輪場ID, 駐輪場名
|
||||||
|
* FROM 駐輪場マスタ
|
||||||
|
* WHERE 閉設フラグ <> 1
|
||||||
|
* ORDER BY 駐輪場ふりがな
|
||||||
|
*
|
||||||
|
* @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 int 作成された集計レコード数
|
||||||
|
*/
|
||||||
|
private function processFiscalEarningsForPark($park, array $aggregationTarget, array $fiscalPeriod): int
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// 【処理4】既存の売上集計結果を削除
|
||||||
|
$this->deleteExistingFiscalSummary($park->park_id, $aggregationTarget);
|
||||||
|
|
||||||
|
// 【処理3】車種区分毎に算出する
|
||||||
|
$psections = $this->getPsectionInformation();
|
||||||
|
$summaryRecords = 0;
|
||||||
|
|
||||||
|
foreach ($psections as $psection) {
|
||||||
|
$earningsData = $this->calculateFiscalEarningsForPsection(
|
||||||
|
$park->park_id,
|
||||||
|
$psection->psection_id,
|
||||||
|
$aggregationTarget
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($this->hasEarningsData($earningsData)) {
|
||||||
|
// 売上集計結果を登録
|
||||||
|
$this->createFiscalEarningsSummary($park, $psection, $aggregationTarget, $earningsData, $fiscalPeriod);
|
||||||
|
$summaryRecords++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::info('駐輪場財政年度売上集計完了', [
|
||||||
|
'park_id' => $park->park_id,
|
||||||
|
'park_name' => $park->park_name,
|
||||||
|
'summary_records' => $summaryRecords,
|
||||||
|
'fiscal_period' => $fiscalPeriod['target_label']
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $summaryRecords;
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('駐輪場財政年度売上集計エラー', [
|
||||||
|
'park_id' => $park->park_id,
|
||||||
|
'error' => $e->getMessage()
|
||||||
|
]);
|
||||||
|
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 車種区分情報取得
|
||||||
|
*
|
||||||
|
* @return array 車種区分情報
|
||||||
|
*/
|
||||||
|
private function getPsectionInformation(): array
|
||||||
|
{
|
||||||
|
return DB::table('psection')
|
||||||
|
->select(['psection_id', 'psection_subject'])
|
||||||
|
->get()
|
||||||
|
->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【処理3】車種区分毎に財政年度売上を算出する
|
||||||
|
*
|
||||||
|
* 4つの項目を計算:
|
||||||
|
* ①売上・件数
|
||||||
|
* ②一時金売上
|
||||||
|
* ③解約返戻金
|
||||||
|
* ④再発行金額・件数
|
||||||
|
*
|
||||||
|
* @param int $parkId 駐輪場ID
|
||||||
|
* @param int $psectionId 車種区分ID
|
||||||
|
* @param array $aggregationTarget 集計対象
|
||||||
|
* @return array 売上データ
|
||||||
|
*/
|
||||||
|
private function calculateFiscalEarningsForPsection(int $parkId, int $psectionId, array $aggregationTarget): array
|
||||||
|
{
|
||||||
|
$startDate = $aggregationTarget['start_date'];
|
||||||
|
$endDate = $aggregationTarget['end_date'];
|
||||||
|
|
||||||
|
// ①売上・件数(billing_amount)
|
||||||
|
$salesData = DB::table('regular_contract')
|
||||||
|
->select([
|
||||||
|
DB::raw('COUNT(*) as sales_count'),
|
||||||
|
DB::raw('COALESCE(SUM(billing_amount), 0) as sales_amount')
|
||||||
|
])
|
||||||
|
->where('park_id', $parkId)
|
||||||
|
->where('psection_id', $psectionId)
|
||||||
|
->where('contract_flag', 1)
|
||||||
|
->whereBetween('contract_payment_day', [$startDate, $endDate])
|
||||||
|
->whereNull('contract_cancelday')
|
||||||
|
->first();
|
||||||
|
|
||||||
|
// ②一時金売上(contract_money)
|
||||||
|
$temporaryData = DB::table('regular_contract')
|
||||||
|
->select([
|
||||||
|
DB::raw('COUNT(*) as temporary_count'),
|
||||||
|
DB::raw('COALESCE(SUM(contract_money), 0) as temporary_amount')
|
||||||
|
])
|
||||||
|
->where('park_id', $parkId)
|
||||||
|
->where('psection_id', $psectionId)
|
||||||
|
->where('contract_flag', 1)
|
||||||
|
->whereBetween('contract_payment_day', [$startDate, $endDate])
|
||||||
|
->whereNotNull('contract_money')
|
||||||
|
->where('contract_money', '>', 0)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
// ③解約返戻金(refunds)
|
||||||
|
$refundData = DB::table('regular_contract')
|
||||||
|
->select([
|
||||||
|
DB::raw('COUNT(*) as refund_count'),
|
||||||
|
DB::raw('COALESCE(SUM(refunds), 0) as refund_amount')
|
||||||
|
])
|
||||||
|
->where('park_id', $parkId)
|
||||||
|
->where('psection_id', $psectionId)
|
||||||
|
->whereBetween('contract_cancelday', [$startDate, $endDate])
|
||||||
|
->whereNotNull('refunds')
|
||||||
|
->where('refunds', '>', 0)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
// ④再発行金額・件数(seal_reissue_request)
|
||||||
|
$reissueData = DB::table('regular_contract')
|
||||||
|
->select([
|
||||||
|
DB::raw('COUNT(*) as reissue_count'),
|
||||||
|
DB::raw('COALESCE(SUM(contract_seal_issue), 0) as reissue_amount')
|
||||||
|
])
|
||||||
|
->where('park_id', $parkId)
|
||||||
|
->where('psection_id', $psectionId)
|
||||||
|
->where('seal_reissue_request', 1)
|
||||||
|
->whereBetween('updated_at', [$startDate, $endDate])
|
||||||
|
->first();
|
||||||
|
|
||||||
|
return [
|
||||||
|
'sales_count' => $salesData->sales_count ?? 0,
|
||||||
|
'sales_amount' => $salesData->sales_amount ?? 0,
|
||||||
|
'temporary_count' => $temporaryData->temporary_count ?? 0,
|
||||||
|
'temporary_amount' => $temporaryData->temporary_amount ?? 0,
|
||||||
|
'refund_count' => $refundData->refund_count ?? 0,
|
||||||
|
'refund_amount' => $refundData->refund_amount ?? 0,
|
||||||
|
'reissue_count' => $reissueData->reissue_count ?? 0,
|
||||||
|
'reissue_amount' => $reissueData->reissue_amount ?? 0
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 売上データの存在チェック
|
||||||
|
*
|
||||||
|
* @param array $earningsData 売上データ
|
||||||
|
* @return bool データが存在するかどうか
|
||||||
|
*/
|
||||||
|
private function hasEarningsData(array $earningsData): bool
|
||||||
|
{
|
||||||
|
return $earningsData['sales_count'] > 0 ||
|
||||||
|
$earningsData['temporary_count'] > 0 ||
|
||||||
|
$earningsData['refund_count'] > 0 ||
|
||||||
|
$earningsData['reissue_count'] > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【処理4】既存の財政年度売上集計結果を削除
|
||||||
|
*
|
||||||
|
* @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_start_date', $aggregationTarget['start_date'])
|
||||||
|
->where('summary_end_date', $aggregationTarget['end_date'])
|
||||||
|
->where('summary_type', $aggregationTarget['summary_type'])
|
||||||
|
->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 財政年度売上集計結果を登録
|
||||||
|
*
|
||||||
|
* @param object $park 駐輪場情報
|
||||||
|
* @param object $psection 車種区分情報
|
||||||
|
* @param array $aggregationTarget 集計対象
|
||||||
|
* @param array $earningsData 売上データ
|
||||||
|
* @param array $fiscalPeriod 財政期間情報
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function createFiscalEarningsSummary($park, $psection, array $aggregationTarget, array $earningsData, array $fiscalPeriod): void
|
||||||
|
{
|
||||||
|
DB::table('earnings_summary')->insert([
|
||||||
|
'park_id' => $park->park_id,
|
||||||
|
'summary_type' => $aggregationTarget['summary_type'], // 1:年次, 2:月次
|
||||||
|
'summary_start_date' => $aggregationTarget['start_date'],
|
||||||
|
'summary_end_date' => $aggregationTarget['end_date'],
|
||||||
|
'earnings_date' => $aggregationTarget['end_date'], // 集計日として終了日を使用
|
||||||
|
'psection_id' => $psection->psection_id,
|
||||||
|
'usertype_subject1' => $psection->psection_subject,
|
||||||
|
'regular_new_count' => $earningsData['sales_count'],
|
||||||
|
'regular_new_amount' => $earningsData['sales_amount'],
|
||||||
|
'turnsum' => $earningsData['temporary_amount'],
|
||||||
|
'turnsum_count' => $earningsData['temporary_count'],
|
||||||
|
'refunds' => $earningsData['refund_amount'],
|
||||||
|
'reissue_count' => $earningsData['reissue_count'],
|
||||||
|
'reissue_amount' => $earningsData['reissue_amount'],
|
||||||
|
'summary_note' => "SHJ-10 {$fiscalPeriod['target_label']} 財政年度売上集計結果",
|
||||||
|
'created_at' => now(),
|
||||||
|
'updated_at' => now(),
|
||||||
|
'operator_id' => 0 // システム処理
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【処理5】オペレータキュー作成
|
||||||
|
*
|
||||||
|
* @param string $message メッセージ
|
||||||
|
* @param int $batchLogId バッチログID
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function createOperatorQueue(string $message, int $batchLogId): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
DB::table('operator_que')->insert([
|
||||||
|
'que_class' => 10, // SHJ-10用のクラス
|
||||||
|
'user_id' => null,
|
||||||
|
'contract_id' => null,
|
||||||
|
'park_id' => null,
|
||||||
|
'que_comment' => $message,
|
||||||
|
'que_status' => 1, // 完了
|
||||||
|
'que_status_comment' => 'バッチ処理完了',
|
||||||
|
'work_instructions' => "SHJ-10売上集計処理 BatchLogID: {$batchLogId}",
|
||||||
|
'created_at' => now(),
|
||||||
|
'updated_at' => now()
|
||||||
|
]);
|
||||||
|
|
||||||
|
Log::info('オペレータキュー作成完了', [
|
||||||
|
'batch_log_id' => $batchLogId,
|
||||||
|
'message' => $message
|
||||||
|
]);
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('オペレータキュー作成エラー', [
|
||||||
|
'batch_log_id' => $batchLogId,
|
||||||
|
'error' => $e->getMessage()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 集計種別のラベル取得
|
||||||
|
*
|
||||||
|
* @param string $type 集計種別
|
||||||
|
* @return string ラベル
|
||||||
|
*/
|
||||||
|
private function getTypeLabel(string $type): string
|
||||||
|
{
|
||||||
|
switch ($type) {
|
||||||
|
case 'yearly':
|
||||||
|
return '年次';
|
||||||
|
case 'monthly':
|
||||||
|
return '月次';
|
||||||
|
default:
|
||||||
|
return $type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -53,3 +53,5 @@ class UserService
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -26,3 +26,5 @@ class Csv
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -28,3 +28,5 @@ class Files
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
24
create_device_table.sql
Normal file
24
create_device_table.sql
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
--
|
||||||
|
-- SHJ-6 デバイス管理マスタテーブル
|
||||||
|
-- デバイス情報を管理するマスタテーブル
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE `device` (
|
||||||
|
`device_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'デバイスID(PK)',
|
||||||
|
`created_at` datetime DEFAULT NULL COMMENT '登録日時',
|
||||||
|
`updated_at` datetime DEFAULT NULL COMMENT '更新日時',
|
||||||
|
`park_id` int(10) UNSIGNED DEFAULT NULL COMMENT '駐輪場ID',
|
||||||
|
`device_type` varchar(255) DEFAULT NULL COMMENT 'デバイス種別',
|
||||||
|
`device_subject` varchar(255) DEFAULT NULL COMMENT 'デバイス名',
|
||||||
|
`device_identifier` varchar(255) DEFAULT NULL COMMENT '識別子(IP/FQDN)',
|
||||||
|
`device_work` varchar(255) DEFAULT NULL COMMENT '稼働(状態)',
|
||||||
|
`device_workstart` date DEFAULT NULL COMMENT '稼働開始日',
|
||||||
|
`device_replace` date DEFAULT NULL COMMENT 'リプレース予定日',
|
||||||
|
`device_remarks` varchar(255) DEFAULT NULL COMMENT '備考',
|
||||||
|
`operator_id` int(10) UNSIGNED DEFAULT NULL COMMENT '更新オペレータID',
|
||||||
|
PRIMARY KEY (`device_id`),
|
||||||
|
KEY `idx_park_id` (`park_id`),
|
||||||
|
KEY `idx_device_type` (`device_type`),
|
||||||
|
KEY `idx_workstart` (`device_workstart`),
|
||||||
|
KEY `idx_replace` (`device_replace`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='デバイス管理マスタテーブル';
|
||||||
39
create_earnings_summary_table.sql
Normal file
39
create_earnings_summary_table.sql
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
--
|
||||||
|
-- SHJ-9 売上集計結果テーブル
|
||||||
|
-- 日次売上集計データを保存するテーブル
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE `earnings_summary` (
|
||||||
|
`earnings_summary_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '売上集計ID',
|
||||||
|
`park_id` int(10) UNSIGNED NOT NULL COMMENT '駐輪場ID',
|
||||||
|
`summary_type` varchar(255) DEFAULT NULL COMMENT '集計区分',
|
||||||
|
`summary_start_date` date DEFAULT NULL COMMENT '集計開始日',
|
||||||
|
`summary_end_date` date DEFAULT NULL COMMENT '集計終了日',
|
||||||
|
`earnings_date` date DEFAULT NULL COMMENT '売上日',
|
||||||
|
`psection_id` int(10) UNSIGNED DEFAULT NULL COMMENT '車種区分ID',
|
||||||
|
`usertype_subject1` varchar(255) DEFAULT NULL COMMENT '規格',
|
||||||
|
`enable_months` int(10) UNSIGNED DEFAULT NULL COMMENT '期間(月数)',
|
||||||
|
`regular_new_count` int(10) UNSIGNED DEFAULT 0 COMMENT '期間件数',
|
||||||
|
`regular_new_amount` decimal(10,2) DEFAULT 0.00 COMMENT '期間金額',
|
||||||
|
`regular_new_reduction_count` int(10) UNSIGNED DEFAULT 0 COMMENT '期間成免件数',
|
||||||
|
`regular_new_reduction_amount` decimal(10,2) DEFAULT 0.00 COMMENT '期間成免金額',
|
||||||
|
`regular_update_count` int(10) UNSIGNED DEFAULT 0 COMMENT '更新件数',
|
||||||
|
`regular_update_amount` decimal(10,2) DEFAULT 0.00 COMMENT '更新金額',
|
||||||
|
`regular_update_reduction_count` int(10) UNSIGNED DEFAULT 0 COMMENT '更新成免件数',
|
||||||
|
`regular_update_reduction_amount` decimal(10,2) DEFAULT 0.00 COMMENT '更新成免金額',
|
||||||
|
`turnsum_count` int(10) UNSIGNED DEFAULT 0 COMMENT '残金件数',
|
||||||
|
`turnsum` decimal(10,2) DEFAULT 0.00 COMMENT '残金',
|
||||||
|
`refunds` decimal(10,2) DEFAULT 0.00 COMMENT '解時返戻金',
|
||||||
|
`other_income` decimal(10,2) DEFAULT 0.00 COMMENT '分別収入',
|
||||||
|
`other_spending` decimal(10,2) DEFAULT 0.00 COMMENT '分別支出',
|
||||||
|
`reissue_count` int(10) UNSIGNED DEFAULT 0 COMMENT '発行件数',
|
||||||
|
`reissue_amount` decimal(10,2) DEFAULT 0.00 COMMENT '発行金額',
|
||||||
|
`summary_note` text DEFAULT NULL COMMENT '計備考',
|
||||||
|
`created_at` datetime DEFAULT NULL COMMENT '登録日時',
|
||||||
|
`updated_at` datetime DEFAULT NULL COMMENT '更新日時',
|
||||||
|
`operator_id` int(10) UNSIGNED DEFAULT NULL COMMENT '新法・ページID',
|
||||||
|
PRIMARY KEY (`earnings_summary_id`),
|
||||||
|
KEY `idx_park_earnings_date` (`park_id`, `earnings_date`),
|
||||||
|
KEY `idx_psection` (`psection_id`),
|
||||||
|
KEY `idx_earnings_date` (`earnings_date`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='売上集計結果テーブル';
|
||||||
19
create_hardware_check_log_table.sql
Normal file
19
create_hardware_check_log_table.sql
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
--
|
||||||
|
-- SHJ-6 ハードウェアチェックログテーブル
|
||||||
|
-- デバイスのハードウェア状態監視ログを保存するテーブル
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE `hardware_check_log` (
|
||||||
|
`log_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ハードウェアチェックログID(PK)',
|
||||||
|
`device_id` int(10) UNSIGNED NOT NULL COMMENT 'デバイスID',
|
||||||
|
`status` int(10) UNSIGNED DEFAULT NULL COMMENT 'ステータス',
|
||||||
|
`status_comment` varchar(255) DEFAULT NULL COMMENT 'ステータスコメント',
|
||||||
|
`created_at` datetime DEFAULT NULL COMMENT '登録日時',
|
||||||
|
`updated_at` datetime DEFAULT NULL COMMENT '更新日時',
|
||||||
|
`operator_id` int(10) UNSIGNED DEFAULT NULL COMMENT 'オペレータID',
|
||||||
|
PRIMARY KEY (`log_id`),
|
||||||
|
KEY `idx_device_id` (`device_id`),
|
||||||
|
KEY `idx_status` (`status`),
|
||||||
|
KEY `idx_created_at` (`created_at`),
|
||||||
|
KEY `idx_device_created` (`device_id`, `created_at`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='ハードウェアチェックログテーブル';
|
||||||
24
create_print_job_log_table.sql
Normal file
24
create_print_job_log_table.sql
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
--
|
||||||
|
-- SHJ-6 プリンタジョブログテーブル
|
||||||
|
-- プリンタ制御プログラムの実行ログを保存するテーブル
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE `print_job_log` (
|
||||||
|
`log_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '処理ログID(PK)',
|
||||||
|
`park_id` int(10) UNSIGNED DEFAULT NULL COMMENT '駐輪場ID',
|
||||||
|
`user_id` int(10) UNSIGNED DEFAULT NULL COMMENT 'ユーザーID',
|
||||||
|
`contract_id` int(10) UNSIGNED DEFAULT NULL COMMENT '契約ID',
|
||||||
|
`process_name` varchar(255) DEFAULT NULL COMMENT 'プロセス名',
|
||||||
|
`job_name` varchar(255) DEFAULT NULL COMMENT 'ジョブ名',
|
||||||
|
`status` varchar(255) DEFAULT NULL COMMENT 'ステータス',
|
||||||
|
`error_code` int(10) UNSIGNED DEFAULT NULL COMMENT 'エラーコード',
|
||||||
|
`status_comment` varchar(255) DEFAULT NULL COMMENT 'ステータスコメント',
|
||||||
|
`created_at` datetime DEFAULT NULL COMMENT '登録日時',
|
||||||
|
PRIMARY KEY (`log_id`),
|
||||||
|
KEY `idx_park_id` (`park_id`),
|
||||||
|
KEY `idx_user_id` (`user_id`),
|
||||||
|
KEY `idx_contract_id` (`contract_id`),
|
||||||
|
KEY `idx_error_code` (`error_code`),
|
||||||
|
KEY `idx_created_at` (`created_at`),
|
||||||
|
KEY `idx_created_error` (`created_at`, `error_code`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='プリンタジョブログテーブル';
|
||||||
@ -0,0 +1,62 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('earnings_summary', function (Blueprint $table) {
|
||||||
|
$table->id('earnings_summary_id')->comment('売上集計ID');
|
||||||
|
$table->unsignedInteger('park_id')->comment('駐輪場ID');
|
||||||
|
$table->string('summary_type', 255)->nullable()->comment('集計区分');
|
||||||
|
$table->date('summary_start_date')->nullable()->comment('集計開始日');
|
||||||
|
$table->date('summary_end_date')->nullable()->comment('集計終了日');
|
||||||
|
$table->date('earnings_date')->nullable()->comment('売上日');
|
||||||
|
$table->unsignedInteger('psection_id')->nullable()->comment('車種区分ID');
|
||||||
|
$table->string('usertype_subject1', 255)->nullable()->comment('規格');
|
||||||
|
$table->unsignedInteger('enable_months')->nullable()->comment('期間(月数)');
|
||||||
|
$table->unsignedInteger('regular_new_count')->nullable()->comment('期間件数');
|
||||||
|
$table->decimal('regular_new_amount', 10, 2)->nullable()->comment('期間金額');
|
||||||
|
$table->unsignedInteger('regular_new_reduction_count')->nullable()->comment('期間成免件数');
|
||||||
|
$table->decimal('regular_new_reduction_amount', 10, 2)->nullable()->comment('期間成免金額');
|
||||||
|
$table->unsignedInteger('regular_update_count')->nullable()->comment('更新件数');
|
||||||
|
$table->decimal('regular_update_amount', 10, 2)->nullable()->comment('更新金額');
|
||||||
|
$table->unsignedInteger('regular_update_reduction_count')->nullable()->comment('更新成免件数');
|
||||||
|
$table->decimal('regular_update_reduction_amount', 10, 2)->nullable()->comment('更新成免金額');
|
||||||
|
$table->unsignedInteger('turnsum_count')->nullable()->comment('残金件数');
|
||||||
|
$table->decimal('turnsum', 10, 2)->nullable()->comment('残金');
|
||||||
|
$table->decimal('refunds', 10, 2)->nullable()->comment('解時返戻金');
|
||||||
|
$table->decimal('other_income', 10, 2)->nullable()->comment('分別収入');
|
||||||
|
$table->decimal('other_spending', 10, 2)->nullable()->comment('分別支出');
|
||||||
|
$table->unsignedInteger('reissue_count')->nullable()->comment('発行件数');
|
||||||
|
$table->decimal('reissue_amount', 10, 2)->nullable()->comment('発行金額');
|
||||||
|
$table->text('summary_note')->nullable()->comment('計備考');
|
||||||
|
$table->datetime('created_at')->nullable()->comment('登録日時');
|
||||||
|
$table->datetime('updated_at')->nullable()->comment('更新日時');
|
||||||
|
$table->unsignedInteger('operator_id')->nullable()->comment('新法・ページID');
|
||||||
|
|
||||||
|
// インデックス
|
||||||
|
$table->index(['park_id', 'earnings_date'], 'idx_park_earnings_date');
|
||||||
|
$table->index(['psection_id'], 'idx_psection');
|
||||||
|
$table->index(['earnings_date'], 'idx_earnings_date');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('earnings_summary');
|
||||||
|
}
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue
Block a user