104 lines
3.3 KiB
PHP
104 lines
3.3 KiB
PHP
<?php
|
||
|
||
namespace App\Services;
|
||
|
||
use Illuminate\Support\Facades\DB;
|
||
use Illuminate\Support\Collection;
|
||
use App\Models\Park;
|
||
|
||
/**
|
||
* 利用率状況サービス
|
||
* - 旧 UsingStatusHelper の機能をサービスとして集約
|
||
* - 画面やAPIから本サービスを経由して取得する
|
||
*/
|
||
class UsingStatusService
|
||
{
|
||
/**
|
||
* 駐輪場別利用率統計を取得
|
||
*
|
||
* @param int|null $parkId 駐輪場ID(null の場合は全て)
|
||
* @return Collection 統計データのコレクション
|
||
*/
|
||
public function getUtilizationStats(?int $parkId = null): Collection
|
||
{
|
||
// 暫定的な収容台数(実DBに無いカラムのため)
|
||
$defaultCapacity = [
|
||
1 => 100, // 自転車
|
||
2 => 50, // 原付
|
||
3 => 30, // その他
|
||
];
|
||
|
||
$query = DB::table('park as p')
|
||
->leftJoin('price_a as pr', 'p.park_id', '=', 'pr.park_id')
|
||
->leftJoin('ptype as pt', 'pr.price_ptypeid', '=', 'pt.ptype_id')
|
||
->leftJoin('regular_contract as rc', function ($join) {
|
||
$join->on('pr.price_parkplaceid', '=', 'rc.price_parkplaceid')
|
||
->where('rc.contract_cancel_flag', '=', 0);
|
||
})
|
||
->select([
|
||
'p.park_id',
|
||
'p.park_name',
|
||
'pt.ptype_id',
|
||
'pt.ptype_subject',
|
||
DB::raw('COUNT(rc.contract_id) as current_count'),
|
||
])
|
||
->whereNotNull('pr.price_parkplaceid')
|
||
->whereNotNull('pt.ptype_id')
|
||
->where('p.park_close_flag', '!=', 1);
|
||
|
||
if ($parkId) {
|
||
$query->where('p.park_id', $parkId);
|
||
}
|
||
|
||
$results = $query
|
||
->groupBy(['p.park_id', 'p.park_name', 'pt.ptype_id', 'pt.ptype_subject'])
|
||
->orderBy('p.park_name')
|
||
->orderBy('pt.ptype_subject')
|
||
->get();
|
||
|
||
// 後計算で容量・空き・利用率を付与
|
||
foreach ($results as $result) {
|
||
$capacity = $defaultCapacity[$result->ptype_id] ?? 50;
|
||
$result->park_limit = $capacity;
|
||
$result->available = $capacity - $result->current_count;
|
||
$result->usage_rate = $capacity > 0 ? round(($result->current_count / $capacity * 100), 1) : 0;
|
||
}
|
||
|
||
return $results;
|
||
}
|
||
|
||
/**
|
||
* 駐輪場一覧を取得(選択用)
|
||
*/
|
||
public function getParkList(): Collection
|
||
{
|
||
return Park::select('park_id', 'park_name')
|
||
->where('park_close_flag', '!=', 1)
|
||
->orderBy('park_name')
|
||
->get();
|
||
}
|
||
|
||
/**
|
||
* 合計行の計算
|
||
*
|
||
* @param Collection $stats
|
||
* @return array{total_limit:int,total_current:int,total_available:int,total_usage_rate:float}
|
||
*/
|
||
public function calculateTotals(Collection $stats): array
|
||
{
|
||
$totalLimit = (int) $stats->sum('park_limit');
|
||
$totalCurrent = (int) $stats->sum('current_count');
|
||
$totalAvailable = $totalLimit - $totalCurrent;
|
||
$totalUsageRate = $totalLimit > 0 ? round(($totalCurrent / $totalLimit * 100), 1) : 0.0;
|
||
|
||
return [
|
||
'total_limit' => $totalLimit,
|
||
'total_current' => $totalCurrent,
|
||
'total_available' => $totalAvailable,
|
||
'total_usage_rate' => $totalUsageRate,
|
||
];
|
||
}
|
||
}
|
||
|
||
|