selection = SelectionModel::find($recordNo); } else if ($recordNo instanceof SelectionModel) { $this->selection = $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; // 検索用文字列の作成 $search = collect(); foreach ($this->selection->candidateList as $ele) { $search->push(sprintf("c%dc", $ele->entryRecordNo)); } $this->selection->searchCandidateListRecordNo = $search->implode(","); return $this; } public function sendNotice() { // メール送信 foreach ($this->selection->candidateList as $candidate) { if ($candidate->emailSendTarget) { $entry = SeasonTicketContractEntry::find($candidate->entryRecordNo); if (!in_array($entry->status, [Status::RESERVE, Status::WAIT_EMPTY])) { continue; } if (!$entry->email) { continue; } $email = new SelectionNotice($this->selection, $entry); (new EmailManager($email->setEmail($entry->email)))->confirm(); } } $this->selection->status = SelectionStatus::ENTRY_ACCEPTING; return $this; } public function makeResult() { $messages = $this->doSelection(); $this->selection->selectionMessage = $messages->implode("\r\n"); // 検索用文字列の作成 $search = collect(); foreach ($this->selection->resultList as $ele) { $search->push(sprintf("r%dr", $ele->entryRecordNo)); } $this->selection->searchResultListEntryRecordNo = $search->implode(","); 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("認証エラー"); } if ($this->selection->status !== SelectionStatus::ENTRY_ACCEPTING) { throw new GeneralErrorMessageException("募集期間が終了しています"); } $list = $this->selection->entryList; if ($this->hasAlreadyEnterd($recordNo)) { // すでにエントリー済みのためスキップ return $this; } $entry = new Entry(); $entry->entryRecordNo = $recordNo; $list->push($entry); $this->selection->entryList = $list; // 検索用文字列の作成 $search = collect(); foreach ($this->selection->entryList as $ele) { $search->push(sprintf("e%de", $ele->entryRecordNo)); } $this->selection->searchEntryListRecordNo = $search->implode(","); 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 getEntry(int $entryRecordNo) { return SeasonTicketContractEntry::find($entryRecordNo); } /** * @param integer $recordNo 申込レコード番号 * @return string */ public function getHash(int $recordNo): string { $source = sprintf("%010d-%010d", $recordNo, intval($this->selection->getRecordId())); return hash('sha256', $source); } public function checkHash(int $recordNo, string $hash): bool { $expect = $this->getHash($recordNo); return $expect === $hash; } // 抽選用------------------------ private function doSelection() { /** * @var Collection */ $messages = collect(); $resultList = $this->selection->resultList->empty(); // 候補者 if ($this->selection->entryList->isEmpty()) { $this->selection->status = SelectionStatus::FAILED; $messages->push("契約希望者不在のため、選考不調"); $this->selection->resultList = $this->selection->resultList->empty(); 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; $result->name = $entry->name; $result->entryNo = $entry->entryNo; $totalRoomAmount += $entry->carAmount; $resultList->push($result); } } if ($this->selection->targetRoomList->count() < $totalRoomAmount) { $messages->push("!警告:空き枠以上の台数を抽選したため調整してください"); } $this->selection->status = $resultList->isNotEmpty() ? SelectionStatus::RESULT_DECISION : SelectionStatus::FAILED; $this->selection->resultList = $resultList; return $messages; } /** * @param TargetRoom $room * @param Collection $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; } }