diff --git a/app/Console/Commands/SeasonTikcetContractSelectionFillCandidates.php b/app/Console/Commands/SeasonTikcetContractSelectionFillCandidates.php
new file mode 100644
index 0000000..1b5e64d
--- /dev/null
+++ b/app/Console/Commands/SeasonTikcetContractSelectionFillCandidates.php
@@ -0,0 +1,90 @@
+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());
+ }
+}
diff --git a/app/Http/Controllers/PDFController.php b/app/Http/Controllers/PDFController.php
index 6f4c5a5..164bb1d 100644
--- a/app/Http/Controllers/PDFController.php
+++ b/app/Http/Controllers/PDFController.php
@@ -2,25 +2,26 @@
namespace App\Http\Controllers;
-use Illuminate\Http\Request;
+use App\Kintone\Models\Receipt;
+use App\Logic\ReceiptManager;
use PDF;
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('
Hello World 岩渕
');
- $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());
}
}
diff --git a/app/Http/Controllers/Web/Image/ImageController.php b/app/Http/Controllers/Web/Image/ImageController.php
index 732d72d..abe0e47 100644
--- a/app/Http/Controllers/Web/Image/ImageController.php
+++ b/app/Http/Controllers/Web/Image/ImageController.php
@@ -2,9 +2,9 @@
namespace App\Http\Controllers\Web\Image;
+use App\Exceptions\AppCommonException;
use App\Http\Controllers\Web\WebController;
use App\Kintone\KintoneAccess;
-use App\Kintone\Models\SeasonTicketContract;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
@@ -30,12 +30,21 @@ abstract class ImageController extends WebController
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;
diff --git a/app/Jobs/SeasonTicketContract/Selection/FillCandidates.php b/app/Jobs/SeasonTicketContract/Selection/FillCandidates.php
new file mode 100644
index 0000000..cb585ab
--- /dev/null
+++ b/app/Jobs/SeasonTicketContract/Selection/FillCandidates.php
@@ -0,0 +1,47 @@
+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));
+ }
+ }
+}
diff --git a/app/Kintone/KintoneAccess.php b/app/Kintone/KintoneAccess.php
index 21a3710..cf3d51e 100644
--- a/app/Kintone/KintoneAccess.php
+++ b/app/Kintone/KintoneAccess.php
@@ -195,8 +195,16 @@ class KintoneAccess
"id" => $model->getRecordId(),
"record" => $model->getApiLayout(),
"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([
"X-Cybozu-API-Token" => $this->apiToken,
])->put($this->getRecordUrl(), $sendData);
diff --git a/app/Kintone/KintoneRecordQuery.php b/app/Kintone/KintoneRecordQuery.php
index e0b0a6c..9033d0c 100644
--- a/app/Kintone/KintoneRecordQuery.php
+++ b/app/Kintone/KintoneRecordQuery.php
@@ -32,51 +32,83 @@ class KintoneRecordQuery
return $ret;
}
+ /**
+ * @param string|\Closure(static $query): static $column
+ */
public function where(string|Closure $column, string|int|null $condition = null, KintoneRecordQueryOperator $operator = KintoneRecordQueryOperator::EQ)
{
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)
{
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)
{
$this->whereQuery("or", $operator->value, $column, $condition);
return $this;
}
+ /**
+ * @param string|\Closure(static $query): static $column
+ */
public function notOrWhere(string|Closure $column, string|int|null $condition = null, KintoneRecordQueryOperator $operator = KintoneRecordQueryOperator::NEQ)
{
return $this->whereQuery("or", $operator->value, $column, $condition);
}
+ /**
+ * @param string|\Closure(static $query): static $column
+ */
public function whereIn(string|Closure $column, array $condition)
{
return $this->whereQuery("and", "in", $column, $condition);
}
+ /**
+ * @param string|\Closure(static $query): static $column
+ */
public function whereNotIn(string|Closure $column, array $condition)
{
return $this->whereQuery("and", "not in", $column, $condition);
}
+ /**
+ * @param string|\Closure(static $query): static $column
+ */
public function orWhereIn(string|Closure $column, array $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)
{
@@ -109,6 +141,9 @@ class KintoneRecordQuery
return $this;
}
+ /**
+ * @param string|\Closure(static $query): static $column
+ */
private function whereQuery(
string $andOr,
string $operator,
diff --git a/app/Kintone/Models/DropDown/SeasonTicketContractEntry/Status.php b/app/Kintone/Models/DropDown/SeasonTicketContractEntry/Status.php
new file mode 100644
index 0000000..c521bfe
--- /dev/null
+++ b/app/Kintone/Models/DropDown/SeasonTicketContractEntry/Status.php
@@ -0,0 +1,9 @@
+data = new stdClass();
+
+ foreach (static::FIELDS as $fileCode => $type) {
+ if ($type === FieldType::SUBTABLE) {
+ $this->set($fileCode, collect());
+ }
+ }
}
public function __get($name)
@@ -244,12 +250,18 @@ abstract class KintoneModel
if ($type === FieldType::SUBTABLE && $this->getFieldType($fieldCode)) {
$ret = collect();
foreach ($value as $v) {
- $rowRet =
- $rowArray = data_get($v, 'value');
+ $rowRet = [];
+ $rowArray = data_get($v, 'value');
+ $isEmptyRow = true;
foreach ($rowArray as $subFieldCode => $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;
}
@@ -332,7 +344,11 @@ abstract class KintoneModel
foreach ($data as $ele) {
if ($ele instanceof SubTableData) {
$obj = [];
- $obj['value'] = $ele->toArray();
+
+ $values = $ele->toArray();
+ foreach ($values as $subFieldCode => $value) {
+ $obj['value'][$subFieldCode]['value'] = $value;
+ }
$ret[] = $obj;
}
}
diff --git a/app/Kintone/Models/ParkingRoom.php b/app/Kintone/Models/ParkingRoom.php
index 3dd7968..5ba8a4e 100644
--- a/app/Kintone/Models/ParkingRoom.php
+++ b/app/Kintone/Models/ParkingRoom.php
@@ -12,10 +12,14 @@ class ParkingRoom extends KintoneModel
const CONFIG_KEY = "KINTONE_APP_PARKING_ROOM";
const FIELD_PARKING_NAME = "定期駐車場";
+ const FIELD_ROOM_NO = "車室番号";
+ const FIELD_ROOM_TYPE = "車室タイプ";
protected const FIELDS = [
...parent::FIELDS,
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 = [
diff --git a/app/Kintone/Models/SeasonTicketContractEntry.php b/app/Kintone/Models/SeasonTicketContractEntry.php
index 67fe9a2..aaa3061 100644
--- a/app/Kintone/Models/SeasonTicketContractEntry.php
+++ b/app/Kintone/Models/SeasonTicketContractEntry.php
@@ -7,20 +7,24 @@ use Illuminate\Support\Carbon;
/**
* アプリ名 定期申込・予約
* @property string parkingName
+ * @property string status
* @property string customerName
* @property string customerNameKana
* @property string phoneNo
* @property string address
* @property string email
- * @property Carbon useStartDate
+ * @property ?Carbon useStartDate
* @property string vehicleNo
+ * @property int carAmount
* @property string paymentMethod
+ * @property Carbon entryDatetime
*/
class SeasonTicketContractEntry extends KintoneModel
{
const CONFIG_KEY = "KINTONE_APP_SEASON_TICEKT_CONTRACT_ENTRY";
const FIELD_PARKING_NAME = "駐車場";
+ const FIELD_STATUS = "status";
const FIELD_CUSTOMER_NAME = "氏名";
const FIELD_CUSTOMER_NAME_KANA = "フリガナ";
const FIELD_PHONE_NO = "電話番号";
@@ -28,7 +32,9 @@ class SeasonTicketContractEntry extends KintoneModel
const FIELD_EMAIL = "メールアドレス";
const FIELD_USE_START_DATE = "利用開始希望日";
const FIELD_VEHICLE_NO = "車両番号";
+ const FIELD_CAR_AMOUNT = "台数";
const FIELD_PAYMENT_METHOD = "支払方法";
+ const FIELD_ENTRY_DATETIME = "受付日時";
protected const FIELDS = [
...parent::FIELDS,
@@ -41,6 +47,7 @@ class SeasonTicketContractEntry extends KintoneModel
self::FIELD_USE_START_DATE => FieldType::DATE,
self::FIELD_VEHICLE_NO => FieldType::SINGLE_LINE_TEXT,
self::FIELD_PAYMENT_METHOD => FieldType::DROP_DOWN,
+ self::FIELD_ENTRY_DATETIME => FieldType::DATETIME,
];
protected const FIELD_NAMES = [
diff --git a/app/Kintone/Models/SeasonTicketContractReserve.php b/app/Kintone/Models/SeasonTicketContractReserve.php
deleted file mode 100644
index 28bbe50..0000000
--- a/app/Kintone/Models/SeasonTicketContractReserve.php
+++ /dev/null
@@ -1,48 +0,0 @@
- 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,
- ];
-}
diff --git a/app/Kintone/Models/SeasonTicketContractSelection.php b/app/Kintone/Models/SeasonTicketContractSelection.php
new file mode 100644
index 0000000..7c34583
--- /dev/null
+++ b/app/Kintone/Models/SeasonTicketContractSelection.php
@@ -0,0 +1,104 @@
+ targetRoomList
+ * @property Collection candidateList
+ * @property Collection entryList
+ * @property Collection 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,
+ ];
+}
diff --git a/app/Kintone/Models/SubTable/SeasonTicketContractReserve/TargetRoom.php b/app/Kintone/Models/SubTable/SeasonTicketContractReserve/TargetRoom.php
deleted file mode 100644
index 8369bae..0000000
--- a/app/Kintone/Models/SubTable/SeasonTicketContractReserve/TargetRoom.php
+++ /dev/null
@@ -1,31 +0,0 @@
-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,
- ];
- }
-}
diff --git a/app/Kintone/Models/SubTable/SeasonTicketContractSelection/Candidate.php b/app/Kintone/Models/SubTable/SeasonTicketContractSelection/Candidate.php
new file mode 100644
index 0000000..e1da1de
--- /dev/null
+++ b/app/Kintone/Models/SubTable/SeasonTicketContractSelection/Candidate.php
@@ -0,0 +1,47 @@
+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,
+ ];
+ }
+}
diff --git a/app/Kintone/Models/SubTable/SeasonTicketContractSelection/Entry.php b/app/Kintone/Models/SubTable/SeasonTicketContractSelection/Entry.php
new file mode 100644
index 0000000..6c5f9d9
--- /dev/null
+++ b/app/Kintone/Models/SubTable/SeasonTicketContractSelection/Entry.php
@@ -0,0 +1,42 @@
+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,
+ ];
+ }
+}
diff --git a/app/Kintone/Models/SubTable/SeasonTicketContractSelection/Result.php b/app/Kintone/Models/SubTable/SeasonTicketContractSelection/Result.php
new file mode 100644
index 0000000..d5498e5
--- /dev/null
+++ b/app/Kintone/Models/SubTable/SeasonTicketContractSelection/Result.php
@@ -0,0 +1,42 @@
+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,
+ ];
+ }
+}
diff --git a/app/Kintone/Models/SubTable/SeasonTicketContractSelection/TargetRoom.php b/app/Kintone/Models/SubTable/SeasonTicketContractSelection/TargetRoom.php
new file mode 100644
index 0000000..4cd5a84
--- /dev/null
+++ b/app/Kintone/Models/SubTable/SeasonTicketContractSelection/TargetRoom.php
@@ -0,0 +1,31 @@
+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,
+ ];
+ }
+}
diff --git a/app/Logic/SeasonTicketContractSelectionManager.php b/app/Logic/SeasonTicketContractSelectionManager.php
new file mode 100644
index 0000000..f127f6c
--- /dev/null
+++ b/app/Logic/SeasonTicketContractSelectionManager.php
@@ -0,0 +1,242 @@
+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
+ */
+ $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 $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;
+ }
+}
diff --git a/app/Util/DateUtil.php b/app/Util/DateUtil.php
index 92e0b15..8d2a74e 100644
--- a/app/Util/DateUtil.php
+++ b/app/Util/DateUtil.php
@@ -24,8 +24,11 @@ class DateUtil
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);
if ($date->isValid()) {
return $date->timezone(config('app.timezone'));
diff --git a/app/Util/LoggingUtil.php b/app/Util/LoggingUtil.php
new file mode 100644
index 0000000..d114762
--- /dev/null
+++ b/app/Util/LoggingUtil.php
@@ -0,0 +1,41 @@
+ $e->getMessage(),
+ '_file' => $e->getFile(),
+ '_line' => $e->getLine(),
+ '_exceptionType' => $e::class,
+ ];
+ }
+}
diff --git a/config/kintone.php b/config/kintone.php
index 0b87b03..801490b 100644
--- a/config/kintone.php
+++ b/config/kintone.php
@@ -33,7 +33,7 @@ return [
...App\Kintone\Models\SeasonTicketContract::setConfig(),
...App\Kintone\Models\SeasonTicketContractPlan::setConfig(),
...App\Kintone\Models\SeasonTicketContractEntry::setConfig(),
- ...App\Kintone\Models\SeasonTicketContractReserve::setConfig(),
+ ...App\Kintone\Models\SeasonTicketContractSelection::setConfig(),
...App\Kintone\Models\PaymentPlan::setConfig(),
...App\Kintone\Models\GeneralApplication::setConfig(),
...App\Kintone\Models\FAQ::setConfig(),