| @@ -0,0 +1,90 @@ | |||||
| <?php | |||||
| namespace App\Console\Commands; | |||||
| use App\Jobs\SeasonTicketContract\Selection\FillCandidates; | |||||
| use App\Kintone\Models\DropDown\SeasonTicketContractSelection\SelectionStatus; | |||||
| use App\Kintone\Models\SeasonTicketContractSelection; | |||||
| use App\Util\DBUtil; | |||||
| use Exception; | |||||
| class SeasonTikcetContractSelectionFillCandidates extends BaseCommand | |||||
| { | |||||
| const COMMAND = "season-ticket-contract-selection:fill-candidates"; | |||||
| /** | |||||
| * The name and signature of the console command. | |||||
| * | |||||
| * @var string | |||||
| */ | |||||
| protected $signature = self::COMMAND; | |||||
| /** | |||||
| * The console command description. | |||||
| * | |||||
| * @var string | |||||
| */ | |||||
| protected $description = '定期選考の候補者設定のジョブを登録する'; | |||||
| static public function getCommand() | |||||
| { | |||||
| return self::COMMAND; | |||||
| } | |||||
| /** | |||||
| * Create a new command instance. | |||||
| * | |||||
| * @return void | |||||
| */ | |||||
| public function __construct() | |||||
| { | |||||
| parent::__construct(); | |||||
| $this->managers = collect(); | |||||
| } | |||||
| /** | |||||
| * Execute the console command. | |||||
| * | |||||
| * @return int | |||||
| */ | |||||
| public function service(): int | |||||
| { | |||||
| try { | |||||
| $db = DBUtil::instance(); | |||||
| $db->beginTransaction(); | |||||
| $targets = $this->getTargets(); | |||||
| $this->outputInfo(sprintf("取得対象 %d件", $targets->count())); | |||||
| // データハンドリング | |||||
| foreach ($targets as $data) { | |||||
| $this->handleData($data); | |||||
| } | |||||
| $db->commit(); | |||||
| } catch (Exception $e) { | |||||
| $db->rollBack(); | |||||
| throw $e; | |||||
| } | |||||
| return self::RESULTCODE_SUCCESS; | |||||
| } | |||||
| private function getTargets() | |||||
| { | |||||
| $access = SeasonTicketContractSelection::getAccess(); | |||||
| $query = SeasonTicketContractSelection::getQuery() | |||||
| ->whereIn(SeasonTicketContractSelection::FIELD_STATUS, [SelectionStatus::START]); | |||||
| return $access->all($query); | |||||
| } | |||||
| private function handleData(SeasonTicketContractSelection $data) | |||||
| { | |||||
| FillCandidates::dispatch($data->getRecordId()); | |||||
| } | |||||
| } | |||||
| @@ -2,25 +2,26 @@ | |||||
| namespace App\Http\Controllers; | namespace App\Http\Controllers; | ||||
| use Illuminate\Http\Request; | |||||
| use App\Kintone\Models\Receipt; | |||||
| use App\Logic\ReceiptManager; | |||||
| use PDF; | use PDF; | ||||
| class PDFController extends Controller | class PDFController extends Controller | ||||
| { | { | ||||
| public function index() | |||||
| public function entry() | |||||
| { | { | ||||
| // https://wkhtmltopdf.org/usage/wkhtmltopdf.txt | |||||
| $manager = new ReceiptManager(2); | |||||
| $file = $manager->makePdf(); | |||||
| // $pdf = PDF::loadHTML('<h1>Hello World 岩渕</h1>'); | |||||
| $pdf = PDF::loadView('pdf'); | |||||
| $receipt = $manager->getReceipt(); | |||||
| // キントーンへの保存 | |||||
| $receipt->setFiles(Receipt::FIELD_RECEIPT_PDF_FILE, collect([$file])); | |||||
| $receipt->save(); | |||||
| // はがきサイズを指定 | |||||
| $pdf->setOption('page-height', 148) | |||||
| ->setOption('page-width', 100) | |||||
| ->setOption('encoding', 'utf-8'); | |||||
| return $pdf->inline(); | |||||
| return response() | |||||
| ->file($file->getFullPath()); | |||||
| } | } | ||||
| } | } | ||||
| @@ -2,9 +2,9 @@ | |||||
| namespace App\Http\Controllers\Web\Image; | namespace App\Http\Controllers\Web\Image; | ||||
| use App\Exceptions\AppCommonException; | |||||
| use App\Http\Controllers\Web\WebController; | use App\Http\Controllers\Web\WebController; | ||||
| use App\Kintone\KintoneAccess; | use App\Kintone\KintoneAccess; | ||||
| use App\Kintone\Models\SeasonTicketContract; | |||||
| use Illuminate\Http\Request; | use Illuminate\Http\Request; | ||||
| use Illuminate\Http\Response; | use Illuminate\Http\Response; | ||||
| @@ -30,12 +30,21 @@ abstract class ImageController extends WebController | |||||
| protected function run(Request $request): Response | protected function run(Request $request): Response | ||||
| { | { | ||||
| $access = $this->getAccess(); | |||||
| $file = $access->fileGet($this->param->id); | |||||
| return response($file->body(), 200, [ | |||||
| 'Content-Length' => $file->header('Content-Length'), | |||||
| 'Content-Type' => $file->header('Content-Type'), | |||||
| ]); | |||||
| try { | |||||
| $id = $request->route('id'); | |||||
| if (!$id) { | |||||
| throw new AppCommonException("パラメータ不正"); | |||||
| } | |||||
| $access = $this->getAccess(); | |||||
| $file = $access->fileGet($id); | |||||
| return response($file->body(), 200, [ | |||||
| 'Content-Length' => $file->header('Content-Length'), | |||||
| 'Content-Type' => $file->header('Content-Type'), | |||||
| ]); | |||||
| } catch (Exception $e) { | |||||
| return response(); | |||||
| } | |||||
| } | } | ||||
| abstract protected function getAccess(): KintoneAccess; | abstract protected function getAccess(): KintoneAccess; | ||||
| @@ -0,0 +1,47 @@ | |||||
| <?php | |||||
| namespace App\Jobs\SeasonTicketContract\Selection; | |||||
| use App\Codes\QueueName; | |||||
| use App\Jobs\BaseJob; | |||||
| use App\Logic\SeasonTicketContractSelectionManager; | |||||
| use App\Util\LoggingUtil; | |||||
| use Exception; | |||||
| use Illuminate\Database\Eloquent\ModelNotFoundException; | |||||
| class FillCandidates extends BaseJob | |||||
| { | |||||
| /** | |||||
| * Create a new job instance. | |||||
| * | |||||
| * @return void | |||||
| */ | |||||
| public function __construct( | |||||
| private int $recordNo | |||||
| ) { | |||||
| $this->onQueue(QueueName::JOB->value); | |||||
| } | |||||
| protected function handleJob() | |||||
| { | |||||
| try { | |||||
| $manager = new SeasonTicketContractSelectionManager($this->recordNo); | |||||
| $manager->makeCandidates() | |||||
| ->save(); | |||||
| $selection = $manager->getSelection(); | |||||
| info(sprintf( | |||||
| "候補者設定 駐車場:%s 締日:%s 候補者数:%d件", | |||||
| $selection->parkingName, | |||||
| $selection->selectionFinalDate ? $selection->selectionFinalDate->format('Y/m/d') : "-", | |||||
| $selection->candidateList->count(), | |||||
| )); | |||||
| } catch (ModelNotFoundException $e) { | |||||
| LoggingUtil::errorException($e, sprintf("データ存在なし削除 %s", self::class)); | |||||
| } catch (Exception $e) { | |||||
| LoggingUtil::errorException($e, sprintf("ジョブ失敗->削除 %s", self::class)); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -195,8 +195,16 @@ class KintoneAccess | |||||
| "id" => $model->getRecordId(), | "id" => $model->getRecordId(), | ||||
| "record" => $model->getApiLayout(), | "record" => $model->getApiLayout(), | ||||
| "revision" => $model->getRevision(), | "revision" => $model->getRevision(), | ||||
| ]; | ]; | ||||
| logger([ | |||||
| "ACTION" => "KINTONE UPDATE", | |||||
| "APP" => $this->appName, | |||||
| "RECORD_NO" => $model->getRecordId(), | |||||
| "SEND_DATA" => $sendData, | |||||
| "JSON" => json_encode($sendData, JSON_UNESCAPED_UNICODE), | |||||
| ]); | |||||
| $response = Http::withHeaders([ | $response = Http::withHeaders([ | ||||
| "X-Cybozu-API-Token" => $this->apiToken, | "X-Cybozu-API-Token" => $this->apiToken, | ||||
| ])->put($this->getRecordUrl(), $sendData); | ])->put($this->getRecordUrl(), $sendData); | ||||
| @@ -32,51 +32,83 @@ class KintoneRecordQuery | |||||
| return $ret; | return $ret; | ||||
| } | } | ||||
| /** | |||||
| * @param string|\Closure(static $query): static $column | |||||
| */ | |||||
| public function where(string|Closure $column, string|int|null $condition = null, KintoneRecordQueryOperator $operator = KintoneRecordQueryOperator::EQ) | public function where(string|Closure $column, string|int|null $condition = null, KintoneRecordQueryOperator $operator = KintoneRecordQueryOperator::EQ) | ||||
| { | { | ||||
| return $this->whereQuery("and", $operator->value, $column, $condition); | return $this->whereQuery("and", $operator->value, $column, $condition); | ||||
| } | } | ||||
| /** | |||||
| * @param string|\Closure(static $query): static $column | |||||
| */ | |||||
| public function notWhere(string|Closure $column, string|int|null $condition = null, KintoneRecordQueryOperator $operator = KintoneRecordQueryOperator::NEQ) | public function notWhere(string|Closure $column, string|int|null $condition = null, KintoneRecordQueryOperator $operator = KintoneRecordQueryOperator::NEQ) | ||||
| { | { | ||||
| return $this->whereQuery("and", $operator->value, $column, $condition); | return $this->whereQuery("and", $operator->value, $column, $condition); | ||||
| } | } | ||||
| /** | |||||
| * @param string|\Closure(static $query): static $column | |||||
| */ | |||||
| public function orWhere(string|Closure $column, string|int|null $condition = null, KintoneRecordQueryOperator $operator = KintoneRecordQueryOperator::EQ) | public function orWhere(string|Closure $column, string|int|null $condition = null, KintoneRecordQueryOperator $operator = KintoneRecordQueryOperator::EQ) | ||||
| { | { | ||||
| $this->whereQuery("or", $operator->value, $column, $condition); | $this->whereQuery("or", $operator->value, $column, $condition); | ||||
| return $this; | return $this; | ||||
| } | } | ||||
| /** | |||||
| * @param string|\Closure(static $query): static $column | |||||
| */ | |||||
| public function notOrWhere(string|Closure $column, string|int|null $condition = null, KintoneRecordQueryOperator $operator = KintoneRecordQueryOperator::NEQ) | public function notOrWhere(string|Closure $column, string|int|null $condition = null, KintoneRecordQueryOperator $operator = KintoneRecordQueryOperator::NEQ) | ||||
| { | { | ||||
| return $this->whereQuery("or", $operator->value, $column, $condition); | return $this->whereQuery("or", $operator->value, $column, $condition); | ||||
| } | } | ||||
| /** | |||||
| * @param string|\Closure(static $query): static $column | |||||
| */ | |||||
| public function whereIn(string|Closure $column, array $condition) | public function whereIn(string|Closure $column, array $condition) | ||||
| { | { | ||||
| return $this->whereQuery("and", "in", $column, $condition); | return $this->whereQuery("and", "in", $column, $condition); | ||||
| } | } | ||||
| /** | |||||
| * @param string|\Closure(static $query): static $column | |||||
| */ | |||||
| public function whereNotIn(string|Closure $column, array $condition) | public function whereNotIn(string|Closure $column, array $condition) | ||||
| { | { | ||||
| return $this->whereQuery("and", "not in", $column, $condition); | return $this->whereQuery("and", "not in", $column, $condition); | ||||
| } | } | ||||
| /** | |||||
| * @param string|\Closure(static $query): static $column | |||||
| */ | |||||
| public function orWhereIn(string|Closure $column, array $condition) | public function orWhereIn(string|Closure $column, array $condition) | ||||
| { | { | ||||
| return $this->whereQuery("or", "not in", $column, $condition); | return $this->whereQuery("or", "not in", $column, $condition); | ||||
| } | } | ||||
| public function whereDate(string $column, Carbon $date, KintoneRecordQueryOperator $operator = KintoneRecordQueryOperator::EQ) | |||||
| public function whereDate(string $column, Carbon $date, KintoneRecordQueryOperator $operator = KintoneRecordQueryOperator::EQ, bool $allowNull = false) | |||||
| { | { | ||||
| return $this->whereNotNull($column)->whereQuery("and", $operator->value, $column, $date->format('Y-m-d')); | |||||
| if (!$allowNull) { | |||||
| $this->whereNotNull($column); | |||||
| } | |||||
| return $this->whereQuery("and", $operator->value, $column, $date->format('Y-m-d')); | |||||
| } | } | ||||
| public function whereDateTime(string $column, Carbon $date, KintoneRecordQueryOperator $operator = KintoneRecordQueryOperator::EQ) | |||||
| public function whereDateTime(string $column, Carbon $date, KintoneRecordQueryOperator $operator = KintoneRecordQueryOperator::EQ, bool $allowNull = false) | |||||
| { | { | ||||
| return $this->whereNotNull($column)->whereQuery("and", $operator->value, $column, $date->toIso8601ZuluString()); | |||||
| if (!$allowNull) { | |||||
| $this->whereNotNull($column); | |||||
| } | |||||
| return $this->whereQuery("and", $operator->value, $column, $date->toIso8601ZuluString()); | |||||
| } | } | ||||
| public function orWhereDate(string $column, Carbon $date, KintoneRecordQueryOperator $operator = KintoneRecordQueryOperator::EQ) | |||||
| public function orWhereDate(string $column, Carbon $date, KintoneRecordQueryOperator $operator = KintoneRecordQueryOperator::EQ, bool $allowNull = false) | |||||
| { | { | ||||
| return $this->whereNotNull($column)->whereQuery("or", $operator->value, $column, $date->format('Y-m-d')); | |||||
| if (!$allowNull) { | |||||
| $this->whereNotNull($column); | |||||
| } | |||||
| return $this->whereQuery("or", $operator->value, $column, $date->format('Y-m-d')); | |||||
| } | } | ||||
| public function orWhereDateTime(string $column, Carbon $date, KintoneRecordQueryOperator $operator = KintoneRecordQueryOperator::EQ) | |||||
| public function orWhereDateTime(string $column, Carbon $date, KintoneRecordQueryOperator $operator = KintoneRecordQueryOperator::EQ, bool $allowNull = false) | |||||
| { | { | ||||
| return $this->whereNotNull($column)->whereQuery("or", $operator->value, $column, $date->toIso8601ZuluString()); | |||||
| if (!$allowNull) { | |||||
| $this->whereNotNull($column); | |||||
| } | |||||
| return $this->whereQuery("or", $operator->value, $column, $date->toIso8601ZuluString()); | |||||
| } | } | ||||
| public function whereNull(string $column) | public function whereNull(string $column) | ||||
| { | { | ||||
| @@ -109,6 +141,9 @@ class KintoneRecordQuery | |||||
| return $this; | return $this; | ||||
| } | } | ||||
| /** | |||||
| * @param string|\Closure(static $query): static $column | |||||
| */ | |||||
| private function whereQuery( | private function whereQuery( | ||||
| string $andOr, | string $andOr, | ||||
| string $operator, | string $operator, | ||||
| @@ -0,0 +1,9 @@ | |||||
| <?php | |||||
| namespace App\Kintone\Models\DropDown\SeasonTicketContractEntry; | |||||
| abstract class Status | |||||
| { | |||||
| const RESERVE = "予約"; | |||||
| const WAIT_EMPTY = "空き待ち"; | |||||
| } | |||||
| @@ -0,0 +1,13 @@ | |||||
| <?php | |||||
| namespace App\Kintone\Models\DropDown\SeasonTicketContractSelection; | |||||
| abstract class SelectionStatus | |||||
| { | |||||
| const START = "起票"; | |||||
| const TARGET_SELECTING = "通知者選択中"; | |||||
| const ENTRY_ACCEPTING = "契約希望者受付中"; | |||||
| const RESULT_DECISION = "候補者仮決定"; | |||||
| const FAILED = "選考不調"; | |||||
| const COMPLETE = "終了"; | |||||
| } | |||||
| @@ -137,6 +137,12 @@ abstract class KintoneModel | |||||
| public function __construct() | public function __construct() | ||||
| { | { | ||||
| $this->data = new stdClass(); | $this->data = new stdClass(); | ||||
| foreach (static::FIELDS as $fileCode => $type) { | |||||
| if ($type === FieldType::SUBTABLE) { | |||||
| $this->set($fileCode, collect()); | |||||
| } | |||||
| } | |||||
| } | } | ||||
| public function __get($name) | public function __get($name) | ||||
| @@ -244,12 +250,18 @@ abstract class KintoneModel | |||||
| if ($type === FieldType::SUBTABLE && $this->getFieldType($fieldCode)) { | if ($type === FieldType::SUBTABLE && $this->getFieldType($fieldCode)) { | ||||
| $ret = collect(); | $ret = collect(); | ||||
| foreach ($value as $v) { | foreach ($value as $v) { | ||||
| $rowRet = | |||||
| $rowArray = data_get($v, 'value'); | |||||
| $rowRet = []; | |||||
| $rowArray = data_get($v, 'value'); | |||||
| $isEmptyRow = true; | |||||
| foreach ($rowArray as $subFieldCode => $ele) { | foreach ($rowArray as $subFieldCode => $ele) { | ||||
| $rowRet[$subFieldCode] = $this->readData($ele); | $rowRet[$subFieldCode] = $this->readData($ele); | ||||
| if (!!$rowRet[$subFieldCode]) { | |||||
| $isEmptyRow = false; | |||||
| } | |||||
| } | |||||
| if (!$isEmptyRow) { | |||||
| $ret->push($this->getSubTableData($fieldCode, $rowRet)); | |||||
| } | } | ||||
| $ret->push($this->getSubTableData($fieldCode, $rowRet)); | |||||
| } | } | ||||
| return $ret; | return $ret; | ||||
| } | } | ||||
| @@ -332,7 +344,11 @@ abstract class KintoneModel | |||||
| foreach ($data as $ele) { | foreach ($data as $ele) { | ||||
| if ($ele instanceof SubTableData) { | if ($ele instanceof SubTableData) { | ||||
| $obj = []; | $obj = []; | ||||
| $obj['value'] = $ele->toArray(); | |||||
| $values = $ele->toArray(); | |||||
| foreach ($values as $subFieldCode => $value) { | |||||
| $obj['value'][$subFieldCode]['value'] = $value; | |||||
| } | |||||
| $ret[] = $obj; | $ret[] = $obj; | ||||
| } | } | ||||
| } | } | ||||
| @@ -12,10 +12,14 @@ class ParkingRoom extends KintoneModel | |||||
| const CONFIG_KEY = "KINTONE_APP_PARKING_ROOM"; | const CONFIG_KEY = "KINTONE_APP_PARKING_ROOM"; | ||||
| const FIELD_PARKING_NAME = "定期駐車場"; | const FIELD_PARKING_NAME = "定期駐車場"; | ||||
| const FIELD_ROOM_NO = "車室番号"; | |||||
| const FIELD_ROOM_TYPE = "車室タイプ"; | |||||
| protected const FIELDS = [ | protected const FIELDS = [ | ||||
| ...parent::FIELDS, | ...parent::FIELDS, | ||||
| self::FIELD_PARKING_NAME => FieldType::SINGLE_LINE_TEXT, | self::FIELD_PARKING_NAME => FieldType::SINGLE_LINE_TEXT, | ||||
| self::FIELD_ROOM_NO => FieldType::SINGLE_LINE_TEXT, | |||||
| self::FIELD_ROOM_TYPE => FieldType::DROP_DOWN, | |||||
| ]; | ]; | ||||
| protected const FIELD_NAMES = [ | protected const FIELD_NAMES = [ | ||||
| @@ -7,20 +7,24 @@ use Illuminate\Support\Carbon; | |||||
| /** | /** | ||||
| * アプリ名 定期申込・予約 | * アプリ名 定期申込・予約 | ||||
| * @property string parkingName | * @property string parkingName | ||||
| * @property string status | |||||
| * @property string customerName | * @property string customerName | ||||
| * @property string customerNameKana | * @property string customerNameKana | ||||
| * @property string phoneNo | * @property string phoneNo | ||||
| * @property string address | * @property string address | ||||
| * @property string email | * @property string email | ||||
| * @property Carbon useStartDate | |||||
| * @property ?Carbon useStartDate | |||||
| * @property string vehicleNo | * @property string vehicleNo | ||||
| * @property int carAmount | |||||
| * @property string paymentMethod | * @property string paymentMethod | ||||
| * @property Carbon entryDatetime | |||||
| */ | */ | ||||
| class SeasonTicketContractEntry extends KintoneModel | class SeasonTicketContractEntry extends KintoneModel | ||||
| { | { | ||||
| const CONFIG_KEY = "KINTONE_APP_SEASON_TICEKT_CONTRACT_ENTRY"; | const CONFIG_KEY = "KINTONE_APP_SEASON_TICEKT_CONTRACT_ENTRY"; | ||||
| const FIELD_PARKING_NAME = "駐車場"; | const FIELD_PARKING_NAME = "駐車場"; | ||||
| const FIELD_STATUS = "status"; | |||||
| const FIELD_CUSTOMER_NAME = "氏名"; | const FIELD_CUSTOMER_NAME = "氏名"; | ||||
| const FIELD_CUSTOMER_NAME_KANA = "フリガナ"; | const FIELD_CUSTOMER_NAME_KANA = "フリガナ"; | ||||
| const FIELD_PHONE_NO = "電話番号"; | const FIELD_PHONE_NO = "電話番号"; | ||||
| @@ -28,7 +32,9 @@ class SeasonTicketContractEntry extends KintoneModel | |||||
| const FIELD_EMAIL = "メールアドレス"; | const FIELD_EMAIL = "メールアドレス"; | ||||
| const FIELD_USE_START_DATE = "利用開始希望日"; | const FIELD_USE_START_DATE = "利用開始希望日"; | ||||
| const FIELD_VEHICLE_NO = "車両番号"; | const FIELD_VEHICLE_NO = "車両番号"; | ||||
| const FIELD_CAR_AMOUNT = "台数"; | |||||
| const FIELD_PAYMENT_METHOD = "支払方法"; | const FIELD_PAYMENT_METHOD = "支払方法"; | ||||
| const FIELD_ENTRY_DATETIME = "受付日時"; | |||||
| protected const FIELDS = [ | protected const FIELDS = [ | ||||
| ...parent::FIELDS, | ...parent::FIELDS, | ||||
| @@ -41,6 +47,7 @@ class SeasonTicketContractEntry extends KintoneModel | |||||
| self::FIELD_USE_START_DATE => FieldType::DATE, | self::FIELD_USE_START_DATE => FieldType::DATE, | ||||
| self::FIELD_VEHICLE_NO => FieldType::SINGLE_LINE_TEXT, | self::FIELD_VEHICLE_NO => FieldType::SINGLE_LINE_TEXT, | ||||
| self::FIELD_PAYMENT_METHOD => FieldType::DROP_DOWN, | self::FIELD_PAYMENT_METHOD => FieldType::DROP_DOWN, | ||||
| self::FIELD_ENTRY_DATETIME => FieldType::DATETIME, | |||||
| ]; | ]; | ||||
| protected const FIELD_NAMES = [ | protected const FIELD_NAMES = [ | ||||
| @@ -1,48 +0,0 @@ | |||||
| <?php | |||||
| namespace App\Kintone\Models; | |||||
| use App\Kintone\Models\SubTable\SeasonTicketContractReserve\TargetRoom; | |||||
| use Illuminate\Support\Carbon; | |||||
| use Illuminate\Support\Collection; | |||||
| /** | |||||
| * アプリ名 定期予約選考 | |||||
| * @property string parkingName | |||||
| * @property Collection<int, TargetRoom> targetRoomList | |||||
| */ | |||||
| class SeasonTicketContractReserve extends KintoneModel | |||||
| { | |||||
| const CONFIG_KEY = "KINTONE_APP_SEASON_TICEKT_CONTRACT_RESERVE"; | |||||
| const FIELD_PARKING_NAME = "駐車場"; | |||||
| const FIELD_TARGET_ROOM_LIST = "対象車室一覧"; | |||||
| const FIELD_TARGET_ROOM_LIST_ROOM_NO = "対象車室一覧_車室番号"; | |||||
| const FIELD_TARGET_ROOM_LIST_ROOM_TYPE = "対象車室一覧_車室タイプ"; | |||||
| const FIELD_TARGET_ROOM_LIST_RECORD_NO = "対象車室一覧_車室レコード番号"; | |||||
| protected const FIELDS = [ | |||||
| ...parent::FIELDS, | |||||
| self::FIELD_PARKING_NAME => FieldType::SINGLE_LINE_TEXT, | |||||
| self::FIELD_TARGET_ROOM_LIST => FieldType::SUBTABLE, | |||||
| // self::FIELD_TARGET_ROOM_LIST => [ | |||||
| // self::FIELD_TARGET_ROOM_LIST_RECORD_NO => FieldType::NUMBER, | |||||
| // self::FIELD_TARGET_ROOM_LIST_ROOM_TYPE => FieldType::SINGLE_LINE_TEXT, | |||||
| // self::FIELD_TARGET_ROOM_LIST_ROOM_NO => FieldType::SINGLE_LINE_TEXT, | |||||
| // ], | |||||
| ]; | |||||
| protected const SUB_TABLES = [ | |||||
| self::FIELD_TARGET_ROOM_LIST => TargetRoom::class, | |||||
| ]; | |||||
| protected const FIELD_NAMES = [ | |||||
| ...parent::FIELD_NAMES, | |||||
| ]; | |||||
| protected const RELATIONS = [ | |||||
| SeasonTicketContractEntry::class, | |||||
| ParkingRoom::class, | |||||
| ]; | |||||
| } | |||||
| @@ -0,0 +1,104 @@ | |||||
| <?php | |||||
| namespace App\Kintone\Models; | |||||
| use App\Kintone\Models\SubTable\SeasonTicketContractSelection\Candidate; | |||||
| use App\Kintone\Models\SubTable\SeasonTicketContractSelection\Entry; | |||||
| use App\Kintone\Models\SubTable\SeasonTicketContractSelection\Result; | |||||
| use App\Kintone\Models\SubTable\SeasonTicketContractSelection\TargetRoom; | |||||
| use Illuminate\Support\Carbon; | |||||
| use Illuminate\Support\Collection; | |||||
| /** | |||||
| * アプリ名 定期予約選考 | |||||
| * @property string parkingName | |||||
| * @property string status | |||||
| * @property ?Carbon useStartDate | |||||
| * @property ?Carbon selectionFinalDate | |||||
| * @property Collection<int, TargetRoom> targetRoomList | |||||
| * @property Collection<int, Candidate> candidateList | |||||
| * @property Collection<int, Entry> entryList | |||||
| * @property Collection<int, Result> resultList | |||||
| * @property string selectionMessage | |||||
| */ | |||||
| class SeasonTicketContractSelection extends KintoneModel | |||||
| { | |||||
| const CONFIG_KEY = "KINTONE_APP_SEASON_TICEKT_CONTRACT_SELECTION"; | |||||
| const FIELD_PARKING_NAME = "駐車場名"; | |||||
| const FIELD_STATUS = "選考ステータス"; | |||||
| const FIELD_USE_START_DATE = "利用開始日"; | |||||
| const FIELD_SELECTION_FINAL_DATE = "選考締切日"; | |||||
| const FIELD_TARGET_ROOM_LIST = "対象車室一覧"; | |||||
| const FIELD_TARGET_ROOM_LIST_ROOM_NO = "対象車室一覧_車室番号"; | |||||
| const FIELD_TARGET_ROOM_LIST_ROOM_TYPE = "対象車室一覧_車室タイプ"; | |||||
| const FIELD_TARGET_ROOM_LIST_RECORD_NO = "対象車室一覧_車室レコード番号"; | |||||
| const FIELD_CANDIDATE_LIST = "申込者一覧"; | |||||
| const FIELD_CANDIDATE_EMAIL_SEND_TARGET = "申込者一覧_通知対象"; | |||||
| const FIELD_CANDIDATE_LIST_RECORD_NO = "申込者一覧_申込レコード番号"; | |||||
| const FIELD_CANDIDATE_LIST_STATUS = "申込者一覧_状態"; | |||||
| const FIELD_CANDIDATE_LIST_PLAN = "申込者一覧_プラン"; | |||||
| const FIELD_CANDIDATE_LIST_ENTRY_NO = "申込者一覧_申込番号"; | |||||
| const FIELD_CANDIDATE_LIST_NAME = "申込者一覧_氏名"; | |||||
| const FIELD_CANDIDATE_LIST_ENTRY_DATETIME = "申込者一覧_受付日時"; | |||||
| const FIELD_CANDIDATE_LIST_WANTS_TO_USE_START_DATE = "申込者一覧_利用開始希望日"; | |||||
| const FIELD_CANDIDATE_LIST_CAR_AMOUNT = "申込者一覧_台数"; | |||||
| const FIELD_CANDIDATE_LIST_EMAIL = "申込者一覧_メールアドレス"; | |||||
| const FIELD_ENTRY_LIST = "契約希望者一覧"; | |||||
| const FIELD_ENTRY_LIST_STATUS = "契約希望者一覧_状態"; | |||||
| const FIELD_ENTRY_LIST_PLAN = "契約希望者一覧_プラン"; | |||||
| const FIELD_ENTRY_LIST_RECORD_NO = "契約希望者一覧_申込レコード番号"; | |||||
| const FIELD_ENTRY_LIST_ENTRY_NO = "契約希望者一覧_申込番号"; | |||||
| const FIELD_ENTRY_LIST_NAME = "契約希望者一覧_氏名"; | |||||
| const FIELD_ENTRY_LIST_ENTRY_DATETIME = "契約希望者一覧_受付日時"; | |||||
| const FIELD_ENTRY_LIST_WANTS_TO_USE_START_DATE = "契約希望者一覧_利用開始希望日"; | |||||
| const FIELD_ENTRY_LIST_CAR_AMOUNT = "契約希望者一覧_台数"; | |||||
| const FIELD_RESULT_LIST = "選考結果一覧"; | |||||
| const FIELD_RESULT_LIST_ROOM_RECORD_NO = "選考結果一覧_車室レコード番号"; | |||||
| const FIELD_RESULT_LIST_ROOM_NO = "選考結果一覧_車室番号"; | |||||
| const FIELD_RESULT_LIST_ROOM_TYPE = "選考結果一覧_車室タイプ"; | |||||
| const FIELD_RESULT_LIST_ENTRY_RECORD_NO = "選考結果一覧_申込レコード番号"; | |||||
| const FIELD_RESULT_LIST_STATUS = "選考結果一覧_ステータス"; | |||||
| const FIELD_RESULT_LIST_PLAN = "選考結果一覧_プラン"; | |||||
| const FIELD_RESULT_LIST_ENTRY_NO = "選考結果一覧_申込番号"; | |||||
| const FIELD_RESULT_LIST_NAME = "選考結果一覧_氏名"; | |||||
| const FIELD_SELECTION_MESSAGE = "自動選考メッセージ"; | |||||
| const FIELD_SEARCH_CANDIDATE_LIST_RECORD_NO = "検索用_申込一覧_レコード番号"; | |||||
| const FIELD_SEARCH_ENTRY_LIST_RECORD_NO = "検索用_契約希望者_レコード番号"; | |||||
| const FIELD_SEARCH_RESULT_LIST_ENTRY_RECORD_NO = "検索用_選考結果_レコード番号"; | |||||
| protected const FIELDS = [ | |||||
| ...parent::FIELDS, | |||||
| self::FIELD_PARKING_NAME => FieldType::SINGLE_LINE_TEXT, | |||||
| self::FIELD_STATUS => FieldType::DROP_DOWN, | |||||
| self::FIELD_TARGET_ROOM_LIST => FieldType::SUBTABLE, | |||||
| self::FIELD_CANDIDATE_LIST => FieldType::SUBTABLE, | |||||
| self::FIELD_ENTRY_LIST => FieldType::SUBTABLE, | |||||
| self::FIELD_RESULT_LIST => FieldType::SUBTABLE, | |||||
| self::FIELD_SELECTION_MESSAGE => FieldType::MULTI_LINE_TEXT, | |||||
| ]; | |||||
| protected const SUB_TABLES = [ | |||||
| self::FIELD_TARGET_ROOM_LIST => TargetRoom::class, | |||||
| self::FIELD_CANDIDATE_LIST => Candidate::class, | |||||
| self::FIELD_ENTRY_LIST => Entry::class, | |||||
| self::FIELD_RESULT_LIST => Result::class, | |||||
| ]; | |||||
| protected const FIELD_NAMES = [ | |||||
| ...parent::FIELD_NAMES, | |||||
| ]; | |||||
| protected const RELATIONS = [ | |||||
| SeasonTicketContractEntry::class, | |||||
| ParkingRoom::class, | |||||
| ]; | |||||
| } | |||||
| @@ -1,31 +0,0 @@ | |||||
| <?php | |||||
| namespace App\Kintone\Models\SubTable\SeasonTicketContractReserve; | |||||
| use App\Kintone\Models\SeasonTicketContractReserve; | |||||
| use App\Kintone\Models\SubTable\SubTableData; | |||||
| class TargetRoom extends SubTableData | |||||
| { | |||||
| public string $roomNo; | |||||
| public string $roomType; | |||||
| public int $roomRecordNo; | |||||
| public function __construct(array $data) | |||||
| { | |||||
| $this->roomNo = data_get($data, SeasonTicketContractReserve::FIELD_TARGET_ROOM_LIST_ROOM_NO, ""); | |||||
| $this->roomType = data_get($data, SeasonTicketContractReserve::FIELD_TARGET_ROOM_LIST_ROOM_TYPE, ""); | |||||
| $this->roomRecordNo = intval(data_get($data, SeasonTicketContractReserve::FIELD_TARGET_ROOM_LIST_RECORD_NO, 0)); | |||||
| parent::__construct($data); | |||||
| } | |||||
| public function toArray(): array | |||||
| { | |||||
| return [ | |||||
| SeasonTicketContractReserve::FIELD_TARGET_ROOM_LIST_ROOM_NO => $this->roomNo, | |||||
| SeasonTicketContractReserve::FIELD_TARGET_ROOM_LIST_ROOM_TYPE => $this->roomType, | |||||
| SeasonTicketContractReserve::FIELD_TARGET_ROOM_LIST_RECORD_NO => $this->roomRecordNo, | |||||
| ]; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,47 @@ | |||||
| <?php | |||||
| namespace App\Kintone\Models\SubTable\SeasonTicketContractSelection; | |||||
| use App\Kintone\Models\SeasonTicketContractSelection; | |||||
| use App\Kintone\Models\SubTable\SubTableData; | |||||
| use App\Util\DateUtil; | |||||
| use Illuminate\Support\Carbon; | |||||
| class Candidate extends SubTableData | |||||
| { | |||||
| public bool $emailSendTarget; | |||||
| public int $entryRecordNo; | |||||
| public string $status; | |||||
| public string $planName; | |||||
| public string $entryNo; | |||||
| public string $name; | |||||
| public ?Carbon $entryDatetime; | |||||
| public ?Carbon $wantsToUseStartDate; | |||||
| public int $carAmount; | |||||
| public string $email; | |||||
| public function __construct(array $data = []) | |||||
| { | |||||
| $this->emailSendTarget = count(data_get($data, SeasonTicketContractSelection::FIELD_CANDIDATE_EMAIL_SEND_TARGET, [])) !== 0; | |||||
| $this->entryRecordNo = intval(data_get($data, SeasonTicketContractSelection::FIELD_CANDIDATE_LIST_RECORD_NO, 0)); | |||||
| $this->planName = data_get($data, SeasonTicketContractSelection::FIELD_CANDIDATE_LIST_STATUS, ""); | |||||
| $this->planName = data_get($data, SeasonTicketContractSelection::FIELD_CANDIDATE_LIST_PLAN, ""); | |||||
| $this->entryNo = data_get($data, SeasonTicketContractSelection::FIELD_CANDIDATE_LIST_PLAN, ""); | |||||
| $this->name = data_get($data, SeasonTicketContractSelection::FIELD_CANDIDATE_LIST_NAME, ""); | |||||
| $this->entryDatetime = DateUtil::parse(data_get($data, SeasonTicketContractSelection::FIELD_TARGET_ROOM_LIST_ROOM_NO, "")); | |||||
| $this->wantsToUseStartDate = DateUtil::parse(data_get($data, SeasonTicketContractSelection::FIELD_CANDIDATE_LIST_WANTS_TO_USE_START_DATE, "")); | |||||
| $this->carAmount = intval(data_get($data, SeasonTicketContractSelection::FIELD_CANDIDATE_LIST_CAR_AMOUNT, 0)); | |||||
| $this->email = data_get($data, SeasonTicketContractSelection::FIELD_TARGET_ROOM_LIST_ROOM_NO, ""); | |||||
| parent::__construct($data); | |||||
| } | |||||
| public function toArray(): array | |||||
| { | |||||
| return [ | |||||
| SeasonTicketContractSelection::FIELD_CANDIDATE_EMAIL_SEND_TARGET => $this->emailSendTarget ? ["〇"] : [], | |||||
| SeasonTicketContractSelection::FIELD_CANDIDATE_LIST_RECORD_NO => $this->entryRecordNo, | |||||
| ]; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,42 @@ | |||||
| <?php | |||||
| namespace App\Kintone\Models\SubTable\SeasonTicketContractSelection; | |||||
| use App\Kintone\Models\SeasonTicketContractSelection; | |||||
| use App\Kintone\Models\SubTable\SubTableData; | |||||
| use App\Util\DateUtil; | |||||
| use Illuminate\Support\Carbon; | |||||
| class Entry extends SubTableData | |||||
| { | |||||
| public int $entryRecordNo; | |||||
| public string $status; | |||||
| public string $planName; | |||||
| public string $entryNo; | |||||
| public string $name; | |||||
| public ?Carbon $entryDatetime; | |||||
| public ?Carbon $wantsToUseStartDate; | |||||
| public int $carAmount; | |||||
| public function __construct(array $data = []) | |||||
| { | |||||
| $this->entryRecordNo = intval(data_get($data, SeasonTicketContractSelection::FIELD_ENTRY_LIST_RECORD_NO, 0)); | |||||
| $this->status = data_get($data, SeasonTicketContractSelection::FIELD_ENTRY_LIST_STATUS, ""); | |||||
| $this->planName = data_get($data, SeasonTicketContractSelection::FIELD_ENTRY_LIST_PLAN, ""); | |||||
| $this->entryNo = data_get($data, SeasonTicketContractSelection::FIELD_ENTRY_LIST_ENTRY_NO, ""); | |||||
| $this->name = data_get($data, SeasonTicketContractSelection::FIELD_ENTRY_LIST_NAME, ""); | |||||
| $this->entryDatetime = DateUtil::parse(data_get($data, SeasonTicketContractSelection::FIELD_ENTRY_LIST_ENTRY_DATETIME, "")); | |||||
| $this->wantsToUseStartDate = DateUtil::parse(data_get($data, SeasonTicketContractSelection::FIELD_ENTRY_LIST_WANTS_TO_USE_START_DATE, "")); | |||||
| $this->carAmount = intval(data_get($data, SeasonTicketContractSelection::FIELD_ENTRY_LIST_CAR_AMOUNT, 0)); | |||||
| parent::__construct($data); | |||||
| } | |||||
| public function toArray(): array | |||||
| { | |||||
| return [ | |||||
| SeasonTicketContractSelection::FIELD_ENTRY_LIST_RECORD_NO => $this->entryRecordNo, | |||||
| ]; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,42 @@ | |||||
| <?php | |||||
| namespace App\Kintone\Models\SubTable\SeasonTicketContractSelection; | |||||
| use App\Kintone\Models\SeasonTicketContractSelection; | |||||
| use App\Kintone\Models\SubTable\SubTableData; | |||||
| class Result extends SubTableData | |||||
| { | |||||
| public int $roomRecordNo; | |||||
| public string $roomNo; | |||||
| public string $roomType; | |||||
| public int $entryRecordNo; | |||||
| public string $status; | |||||
| public string $planName; | |||||
| public string $entryNo; | |||||
| public string $name; | |||||
| public function __construct(array $data = []) | |||||
| { | |||||
| $this->roomRecordNo = intval(data_get($data, SeasonTicketContractSelection::FIELD_RESULT_LIST_ROOM_RECORD_NO, 0)); | |||||
| $this->roomNo = data_get($data, SeasonTicketContractSelection::FIELD_RESULT_LIST_ROOM_NO, ""); | |||||
| $this->roomType = data_get($data, SeasonTicketContractSelection::FIELD_RESULT_LIST_ROOM_TYPE, ""); | |||||
| $this->entryRecordNo = intval(data_get($data, SeasonTicketContractSelection::FIELD_RESULT_LIST_ENTRY_RECORD_NO, 0)); | |||||
| $this->status = data_get($data, SeasonTicketContractSelection::FIELD_RESULT_LIST_STATUS, ""); | |||||
| $this->planName = data_get($data, SeasonTicketContractSelection::FIELD_RESULT_LIST_PLAN, ""); | |||||
| $this->entryNo = data_get($data, SeasonTicketContractSelection::FIELD_RESULT_LIST_ENTRY_NO, ""); | |||||
| $this->name = data_get($data, SeasonTicketContractSelection::FIELD_RESULT_LIST_NAME, ""); | |||||
| parent::__construct($data); | |||||
| } | |||||
| public function toArray(): array | |||||
| { | |||||
| return [ | |||||
| SeasonTicketContractSelection::FIELD_RESULT_LIST_ROOM_RECORD_NO => $this->roomRecordNo, | |||||
| SeasonTicketContractSelection::FIELD_RESULT_LIST_ENTRY_RECORD_NO => $this->entryRecordNo, | |||||
| ]; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,31 @@ | |||||
| <?php | |||||
| namespace App\Kintone\Models\SubTable\SeasonTicketContractSelection; | |||||
| use App\Kintone\Models\SeasonTicketContractSelection; | |||||
| use App\Kintone\Models\SubTable\SubTableData; | |||||
| class TargetRoom extends SubTableData | |||||
| { | |||||
| public string $roomNo; | |||||
| public string $roomType; | |||||
| public int $roomRecordNo; | |||||
| public function __construct(array $data = []) | |||||
| { | |||||
| $this->roomNo = data_get($data, SeasonTicketContractSelection::FIELD_TARGET_ROOM_LIST_ROOM_NO, ""); | |||||
| $this->roomType = data_get($data, SeasonTicketContractSelection::FIELD_TARGET_ROOM_LIST_ROOM_TYPE, ""); | |||||
| $this->roomRecordNo = intval(data_get($data, SeasonTicketContractSelection::FIELD_TARGET_ROOM_LIST_RECORD_NO, 0)); | |||||
| parent::__construct($data); | |||||
| } | |||||
| public function toArray(): array | |||||
| { | |||||
| return [ | |||||
| SeasonTicketContractSelection::FIELD_TARGET_ROOM_LIST_ROOM_NO => $this->roomNo, | |||||
| SeasonTicketContractSelection::FIELD_TARGET_ROOM_LIST_ROOM_TYPE => $this->roomType, | |||||
| SeasonTicketContractSelection::FIELD_TARGET_ROOM_LIST_RECORD_NO => $this->roomRecordNo, | |||||
| ]; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,242 @@ | |||||
| <?php | |||||
| namespace App\Logic; | |||||
| use App\Exceptions\AppCommonException; | |||||
| use App\Kintone\KintoneRecordQuery; | |||||
| use App\Kintone\KintoneRecordQueryOperator; | |||||
| use App\Kintone\Models\DropDown\SeasonTicketContractEntry\Status; | |||||
| use App\Kintone\Models\SeasonTicketContractEntry as EntryModel; | |||||
| use App\Kintone\Models\SeasonTicketContractSelection as SelectionModel; | |||||
| use App\Kintone\Models\SubTable\SeasonTicketContractSelection\Entry; | |||||
| use App\Kintone\Models\DropDown\SeasonTicketContractSelection\SelectionStatus; | |||||
| use App\Kintone\Models\SubTable\SeasonTicketContractSelection\Candidate; | |||||
| use App\Kintone\Models\SubTable\SeasonTicketContractSelection\Result; | |||||
| use App\Kintone\Models\SubTable\SeasonTicketContractSelection\TargetRoom; | |||||
| use App\Util\DateUtil; | |||||
| use Illuminate\Support\Collection; | |||||
| class SeasonTicketContractSelectionManager | |||||
| { | |||||
| private SelectionModel $selection; | |||||
| public function __construct(?int $recordNo = null) | |||||
| { | |||||
| if ($recordNo) { | |||||
| $this->selection = SelectionModel::find($recordNo); | |||||
| } else { | |||||
| $this->selection = new SelectionModel(); | |||||
| $this->selection->status = SelectionStatus::START; | |||||
| } | |||||
| } | |||||
| public function makeCandidates() | |||||
| { | |||||
| if ($this->selection->status !== SelectionStatus::START) { | |||||
| new AppCommonException( | |||||
| sprintf( | |||||
| "ステータス不正 候補者一覧を設定するにはステータスが%[s]である必要がある。現ステータス[%s]", | |||||
| SelectionStatus::START, | |||||
| $this->selection->status, | |||||
| ) | |||||
| ); | |||||
| } | |||||
| $candidateList = $this->selection->candidateList->empty(); | |||||
| // 対象の申込を取得する | |||||
| // TODO 空き車室に対応したプランの申込に絞る必要あり | |||||
| $access = EntryModel::getAccess(); | |||||
| $getBaseQuery = function () { | |||||
| $baseQuery = EntryModel::getQuery(); | |||||
| $baseQuery->where(EntryModel::FIELD_PARKING_NAME, $this->selection->parkingName) | |||||
| ->orderByAsc(EntryModel::FIELD_ENTRY_DATETIME); | |||||
| if ($this->selection->useStartDate) { | |||||
| $useStartDateQuery = function (KintoneRecordQuery $query) { | |||||
| return $query->whereNull(EntryModel::FIELD_USE_START_DATE) | |||||
| ->orWhereDate(EntryModel::FIELD_USE_START_DATE, $this->selection->useStartDate, KintoneRecordQueryOperator::GE, true); | |||||
| }; | |||||
| $baseQuery->where($useStartDateQuery); | |||||
| } | |||||
| return $baseQuery; | |||||
| }; | |||||
| $reserveQuery = $getBaseQuery()->whereIn(EntryModel::FIELD_STATUS, [Status::RESERVE]); | |||||
| $waitQuery = $getBaseQuery()->whereIn(EntryModel::FIELD_STATUS, [Status::WAIT_EMPTY]); | |||||
| $reserveList = $access->all($reserveQuery); | |||||
| $waitList = $access->all($waitQuery); | |||||
| $list = $reserveList->merge($waitList); | |||||
| foreach ($list as $ele) { | |||||
| $candidate = new Candidate(); | |||||
| $candidate->entryRecordNo = $ele->getRecordId(); | |||||
| $candidateList->push($candidate); | |||||
| } | |||||
| $this->selection->candidateList = $candidateList; | |||||
| $this->selection->status = SelectionStatus::TARGET_SELECTING; | |||||
| return $this; | |||||
| } | |||||
| public function sendNotine() | |||||
| { | |||||
| // メール送信 | |||||
| return $this; | |||||
| } | |||||
| public function makeResult() | |||||
| { | |||||
| $messages = $this->doSelection(); | |||||
| $this->selection->selectionMessage = $messages->implode("\r\n"); | |||||
| return $this; | |||||
| } | |||||
| public function save() | |||||
| { | |||||
| // レコード保存 | |||||
| $this->selection->save(); | |||||
| return $this; | |||||
| } | |||||
| public function entry(int $recordNo, string $hashPassword) | |||||
| { | |||||
| if (!$this->checkHash($recordNo, $hashPassword)) { | |||||
| throw new AppCommonException("認証エラー"); | |||||
| } | |||||
| $list = $this->selection->entryList; | |||||
| if ($this->hasAlreadyEnterd($recordNo)) { | |||||
| // すでにエントリー済みのためスキップ | |||||
| return $this; | |||||
| } | |||||
| $entry = new Entry(); | |||||
| $entry->entryRecordNo = $recordNo; | |||||
| $list->push($entry); | |||||
| $this->selection->entryList = $list; | |||||
| return $this; | |||||
| } | |||||
| public function hasAlreadyEnterd(int $recordNo): bool | |||||
| { | |||||
| $list = $this->selection->entryList; | |||||
| return $list->search(function (Entry $item) use ($recordNo) { | |||||
| return $recordNo === $item->entryRecordNo; | |||||
| }) !== false; | |||||
| } | |||||
| public function getSelection() | |||||
| { | |||||
| return $this->selection; | |||||
| } | |||||
| public function getHash(int $recordNo): string | |||||
| { | |||||
| $source = sprintf("%010d-%010d", $recordNo, intval($this->selection->getRecordId())); | |||||
| return hash('sha256', $source); | |||||
| } | |||||
| private function checkHash(int $recordNo, string $hash): bool | |||||
| { | |||||
| $expect = $this->getHash($recordNo); | |||||
| return $expect === $hash; | |||||
| } | |||||
| // 抽選用------------------------ | |||||
| private function doSelection() | |||||
| { | |||||
| /** | |||||
| * @var Collection<int, string> | |||||
| */ | |||||
| $messages = collect(); | |||||
| $resultList = $this->selection->resultList->empty(); | |||||
| // 候補者 | |||||
| if ($this->selection->entryList->isEmpty()) { | |||||
| $this->selection->status = SelectionStatus::FAILED; | |||||
| $messages->push("契約希望者不在のため、選考不調"); | |||||
| return $messages; | |||||
| } | |||||
| // 希望者一覧のコピー | |||||
| $entryList = $this->selection->entryList->empty(); | |||||
| foreach ($this->selection->entryList as $entry) { | |||||
| $entryList->push($entry); | |||||
| } | |||||
| // 選考結果の設定 | |||||
| $totalRoomAmount = 0; | |||||
| foreach ($this->selection->targetRoomList as $room) { | |||||
| $entry = $this->selectionByRoom($room, $entryList); | |||||
| if ($entry) { | |||||
| $result = new Result(); | |||||
| $result->entryRecordNo = $entry->entryRecordNo; | |||||
| $result->roomRecordNo = $room->roomRecordNo; | |||||
| $totalRoomAmount += $entry->carAmount; | |||||
| $resultList->push($result); | |||||
| } | |||||
| } | |||||
| if ($this->selection->targetRoomList->count() < $totalRoomAmount) { | |||||
| $messages->push("!警告:空き枠以上の台数を抽選したため調整してください"); | |||||
| } | |||||
| $this->selection->status = $resultList->isNotEmpty() ? | |||||
| SelectionStatus::COMPLETE : SelectionStatus::FAILED; | |||||
| $this->selection->resultList = $resultList; | |||||
| return $messages; | |||||
| } | |||||
| /** | |||||
| * @param TargetRoom $room | |||||
| * @param Collection<int, Entry> $entries | |||||
| */ | |||||
| private function selectionByRoom(TargetRoom $room, Collection $entries): ?Entry | |||||
| { | |||||
| // 予約者確認 | |||||
| $entry = $entries->filter(function (Entry $entry) { | |||||
| return $entry->status === Status::RESERVE; | |||||
| })->sort(function (Entry $a, Entry $b) { | |||||
| return $a->entryDatetime->lt($b->entryDatetime) ? -1 : 1; | |||||
| })->first(); | |||||
| if ($entry) { | |||||
| return $entry; | |||||
| } | |||||
| // 空き待ちで抽選 | |||||
| $entry = $entries->filter(function (Entry $entry) { | |||||
| return $entry->status === Status::WAIT_EMPTY; | |||||
| })->shuffle(intval(DateUtil::now()->timestamp))->first(); | |||||
| if ($entry) { | |||||
| return $entry; | |||||
| } | |||||
| return null; | |||||
| } | |||||
| } | |||||
| @@ -24,8 +24,11 @@ class DateUtil | |||||
| return new Carbon(); | return new Carbon(); | ||||
| } | } | ||||
| public static function parse(string $source): Carbon|null | |||||
| public static function parse(?string $source): Carbon|null | |||||
| { | { | ||||
| if ($source === null) { | |||||
| return null; | |||||
| } | |||||
| $date = Carbon::parse($source); | $date = Carbon::parse($source); | ||||
| if ($date->isValid()) { | if ($date->isValid()) { | ||||
| return $date->timezone(config('app.timezone')); | return $date->timezone(config('app.timezone')); | ||||
| @@ -0,0 +1,41 @@ | |||||
| <?php | |||||
| namespace App\Util; | |||||
| use Exception; | |||||
| use Illuminate\Support\Facades\Log; | |||||
| class LoggingUtil | |||||
| { | |||||
| public static function infoException(Exception $e, string|array $messages = []) | |||||
| { | |||||
| Log::error(self::getExceptionContents($e, $messages)); | |||||
| } | |||||
| public static function warnException(Exception $e, string|array $messages = []) | |||||
| { | |||||
| Log::error(self::getExceptionContents($e, $messages)); | |||||
| } | |||||
| public static function errorException(Exception $e, string|array $messages = []) | |||||
| { | |||||
| Log::error(self::getExceptionContents($e, $messages)); | |||||
| } | |||||
| private static function getExceptionContents(Exception $e, string|array $messages) | |||||
| { | |||||
| if (is_string($messages)) { | |||||
| $message = $messages; | |||||
| $messages = []; | |||||
| $messages[] = $message; | |||||
| } | |||||
| return [ | |||||
| ...$messages, | |||||
| '_message' => $e->getMessage(), | |||||
| '_file' => $e->getFile(), | |||||
| '_line' => $e->getLine(), | |||||
| '_exceptionType' => $e::class, | |||||
| ]; | |||||
| } | |||||
| } | |||||
| @@ -33,7 +33,7 @@ return [ | |||||
| ...App\Kintone\Models\SeasonTicketContract::setConfig(), | ...App\Kintone\Models\SeasonTicketContract::setConfig(), | ||||
| ...App\Kintone\Models\SeasonTicketContractPlan::setConfig(), | ...App\Kintone\Models\SeasonTicketContractPlan::setConfig(), | ||||
| ...App\Kintone\Models\SeasonTicketContractEntry::setConfig(), | ...App\Kintone\Models\SeasonTicketContractEntry::setConfig(), | ||||
| ...App\Kintone\Models\SeasonTicketContractReserve::setConfig(), | |||||
| ...App\Kintone\Models\SeasonTicketContractSelection::setConfig(), | |||||
| ...App\Kintone\Models\PaymentPlan::setConfig(), | ...App\Kintone\Models\PaymentPlan::setConfig(), | ||||
| ...App\Kintone\Models\GeneralApplication::setConfig(), | ...App\Kintone\Models\GeneralApplication::setConfig(), | ||||
| ...App\Kintone\Models\FAQ::setConfig(), | ...App\Kintone\Models\FAQ::setConfig(), | ||||