diff --git a/app/Console/Commands/TestMail.php b/app/Console/Commands/TestEmail.php similarity index 79% rename from app/Console/Commands/TestMail.php rename to app/Console/Commands/TestEmail.php index b0b55ea..71ef4f0 100644 --- a/app/Console/Commands/TestMail.php +++ b/app/Console/Commands/TestEmail.php @@ -2,10 +2,11 @@ namespace App\Console\Commands; +use App\Files\TmpFile; use App\Logic\EmailManager; -use App\Mail\Test; +use App\Email\Test; -class TestMail extends BaseCommand +class TestEmail extends BaseCommand { const COMMAND = "mail:test {email}"; @@ -49,11 +50,17 @@ class TestMail extends BaseCommand { $email = $this->argument('email'); + $file = new TmpFile(); + $file->put("iwabuchi text"); + + $mailer = new Test(); $mailer->setEmail($email); $manager = new EmailManager($mailer); - $manager->confirm(); + $manager + ->attach($file->getFullPath(), "test.txt", "text/plain") + ->confirm(); return self::RESULTCODE_SUCCESS; } diff --git a/app/Mail/BaseMailer.php b/app/Email/BaseEmailer.php similarity index 83% rename from app/Mail/BaseMailer.php rename to app/Email/BaseEmailer.php index 3ca9856..ed22a2f 100644 --- a/app/Mail/BaseMailer.php +++ b/app/Email/BaseEmailer.php @@ -1,18 +1,20 @@ |null + */ + protected ?Collection $__attachments = null; public function sendEmail(string $email) { @@ -67,9 +74,25 @@ abstract class BaseMailer extends Mailable public function build() { - return $this->text($this->getTemplateName()) + $this->text($this->getTemplateName()) ->subject($this->getSubject()) ->with($this->getParams()); + + // 添付ファイル処理 + if ($this->__attachments !== null) { + $count = $this->__attachments->count(); + foreach ($this->__attachments as $attachment) { + $filepath = $attachment->filepath; + $as = $attachment->send_filename; + $mime = $attachment->mime; + $this->attach($filepath, [ + 'as' => $as, + 'mime' => $mime, + ]); + } + } + + return $this; } public function setConfigDefault() diff --git a/app/Mail/Guests/Guest.php b/app/Email/Guests/Guest.php similarity index 64% rename from app/Mail/Guests/Guest.php rename to app/Email/Guests/Guest.php index 104aecf..641411d 100644 --- a/app/Mail/Guests/Guest.php +++ b/app/Email/Guests/Guest.php @@ -1,10 +1,10 @@ $this->order->receipt_shop_name, + 'useDate' => $this->order->receipt_use_date->format('Y/m/d'), + 'amount' => number_format($this->order->receipt_amount), + ]; + } +} diff --git a/app/Mail/Sender.php b/app/Email/Sender.php similarity index 87% rename from app/Mail/Sender.php rename to app/Email/Sender.php index 8ed84eb..3862fac 100644 --- a/app/Mail/Sender.php +++ b/app/Email/Sender.php @@ -1,8 +1,7 @@ email) - ->send(new TextMail($email->subject, $email->content)); + ->send(new TextEmail($email->subject, $email->content, $email->emailAttachments)); } catch (Exception $e) { Log::error("メール送信失敗", [ 'id' => $email->id, diff --git a/app/Mail/Test.php b/app/Email/Test.php similarity index 83% rename from app/Mail/Test.php rename to app/Email/Test.php index 9f0c1e0..149f114 100644 --- a/app/Mail/Test.php +++ b/app/Email/Test.php @@ -1,8 +1,8 @@ __subject = $subject; $this->__contents = $contents; + $this->__attachments = $attachments; } public function getTemplateName(): string diff --git a/app/Events/Mail/ConfirmEvent.php b/app/Events/Email/ConfirmEvent.php similarity index 50% rename from app/Events/Mail/ConfirmEvent.php rename to app/Events/Email/ConfirmEvent.php index 715227b..81cb003 100644 --- a/app/Events/Mail/ConfirmEvent.php +++ b/app/Events/Email/ConfirmEvent.php @@ -1,10 +1,12 @@ email = $email; @@ -27,5 +29,14 @@ class ConfirmEvent $this->email = $email->makeModel(); $this->email->save(); } + if ($attachments !== null) { + foreach ($attachments as $attachment) { + if (!($attachment instanceof EmailAttachment)) continue; + + $emailId = $this->email->id; + $attachment->email_id = $emailId; + $attachment->save(); + } + } } } diff --git a/app/Events/ReceiptIssuingOrder/EmailOrderEvent.php b/app/Events/ReceiptIssuingOrder/EmailOrderEvent.php new file mode 100644 index 0000000..d8dfdd9 --- /dev/null +++ b/app/Events/ReceiptIssuingOrder/EmailOrderEvent.php @@ -0,0 +1,14 @@ +param; + } + + protected function run(Request $request): JsonResponse + { + $param = $this->param; + + $file = $this->pdf->initByToken($param->accessToken) + ->checkTimestamp($param->timestamp) + ->getA4File(); + + $this->manager->initByToken($param->accessToken) + ->checkTimestamp($param->timestamp) + ->emailOrder($param->email, $file) + ->update(); + + return $this->successResponse(); + } +} diff --git a/app/Http/Controllers/Web/ReceiptIssuingOrder/EmailOrderParam.php b/app/Http/Controllers/Web/ReceiptIssuingOrder/EmailOrderParam.php new file mode 100644 index 0000000..0e2f6b2 --- /dev/null +++ b/app/Http/Controllers/Web/ReceiptIssuingOrder/EmailOrderParam.php @@ -0,0 +1,27 @@ + $this->str(), + ReceiptIssuingOrder::COL_NAME_EMAIL => $this->str([...Rule::email()]), + ], + $this->timestamp(), + ); + } +} diff --git a/app/Http/Controllers/Web/Rule.php b/app/Http/Controllers/Web/Rule.php new file mode 100644 index 0000000..265f533 --- /dev/null +++ b/app/Http/Controllers/Web/Rule.php @@ -0,0 +1,14 @@ +onQueue(QueueName::JOB->value); + } + + /** + * Execute the job. + * + * @return void + */ + public function handle() + { + info("領収証Emailポーリング:" . $this->order->receipt_pdf_email_id); + + $email = Email::findOrFail($this->order->receipt_pdf_email_id); + $sendDatetime = $email->send_datetime; + + if ($email->send_datetime !== null) { + // ポーリング終了 + $this->donePolling($sendDatetime); + } else if ($email->is_failed) { + // ポーリング終了 + $this->donePolling($sendDatetime); + } else { + $limit = $this->order->status_receipt_email_send_order_datetime->clone()->addDays(3); + if (DateUtil::now()->gt($limit)) { + // ポーリング終了(未完了) + $this->donePolling($sendDatetime); + Log::warning("領収証Email送信未完了検知 OrderID:%s", $this->order->id); + } else { + // ポーリング継続 + $this->continuePolling(); + } + } + } + + private function donePolling(Carbon $sendDatetime) + { + $this->order->status_receipt_email_send_datetime = $sendDatetime; + $this->order->save(); + info("領収証Emailポーリング完了:" . $this->order->receipt_pdf_email_id); + } + + private function continuePolling() + { + static::dispatch($this->order) + ->delay(DateUtil::now()->addMinutes(5)); + info("領収証Emailポーリング継続:" . $this->order->receipt_pdf_email_id); + } +} diff --git a/app/Listeners/Mail/MailSendJobRegister.php b/app/Listeners/Email/EmailSendJobRegister.php similarity index 75% rename from app/Listeners/Mail/MailSendJobRegister.php rename to app/Listeners/Email/EmailSendJobRegister.php index 0f8f10c..8ede54c 100644 --- a/app/Listeners/Mail/MailSendJobRegister.php +++ b/app/Listeners/Email/EmailSendJobRegister.php @@ -1,12 +1,12 @@ confirm_datetime = DateUtil::now(); $email->save(); - SimpleMail::dispatch($event->email); + + SimpleEmail::dispatch($event->email); } } } diff --git a/app/Logic/EmailManager.php b/app/Logic/EmailManager.php index e3b9329..060c407 100644 --- a/app/Logic/EmailManager.php +++ b/app/Logic/EmailManager.php @@ -2,11 +2,13 @@ namespace App\Logic; -use App\Events\Mail\ConfirmEvent; +use App\Events\Email\ConfirmEvent; use App\Exceptions\AppCommonException; -use App\Mail\BaseMailer; +use App\Email\BaseEmailer; use App\Models\Email; +use App\Models\EmailAttachment; use Exception; +use Illuminate\Database\Eloquent\Collection; use Illuminate\Support\Carbon; use Validator; @@ -17,13 +19,18 @@ class EmailManager private bool $canSend = false; - public function __construct(int|BaseMailer $param) + /** + * @var Collection|null + */ + private ?Collection $attachments = null; + + public function __construct(int|BaseEmailer $param) { if (is_numeric($param)) { $this->model = Email::lockForUpdate()->findOrfail($param); $this->canSend = $this->model->send_datetime === null; if (!$this->checkAuth()) throw new AppCommonException("メール権限エラー"); - } else if ($param instanceof BaseMailer) { + } else if ($param instanceof BaseEmailer) { $this->model = $param->makeModel(); } } @@ -35,6 +42,7 @@ class EmailManager public function getEmailId() { + $this->model->setId(); return $this->model->id; } @@ -70,6 +78,22 @@ class EmailManager return $this; } + public function attach(string $filepath, string $filename, string $mimeType) + { + + if ($this->attachments === null) { + $this->attachments = new Collection(); + } + $attachment = new EmailAttachment(); + $attachment->filepath = $filepath; + $attachment->send_filename = $filename; + $attachment->mime = $mimeType; + + $this->attachments->push($attachment); + + return $this; + } + public function update() { $this->model->save(); @@ -88,7 +112,8 @@ class EmailManager } if ($this->canSend() !== null) { - ConfirmEvent::dispatch($this->model); + $this->model->setId(); + ConfirmEvent::dispatch($this->model, $this->attachments); } else { throw new AppCommonException("送信済みエラー"); } diff --git a/app/Logic/ReceiptIssuingOrder/PDFDownLoadManager.php b/app/Logic/ReceiptIssuingOrder/PDFDownLoadManager.php index 7ad3132..dc13f23 100644 --- a/app/Logic/ReceiptIssuingOrder/PDFDownLoadManager.php +++ b/app/Logic/ReceiptIssuingOrder/PDFDownLoadManager.php @@ -5,9 +5,12 @@ namespace App\Logic\ReceiptIssuingOrder; use App\Codes\PrefCode; use App\Events\ReceiptIssuingOrder\DownloadedEvent; use App\Exceptions\AppCommonException; +use App\Files\PDF\Receipt\A4Receipt; +use App\Files\TmpFile; use App\Models\ReceiptIssuingOrder; use App\Models\ReceiptIssuingOrderTax; use App\Util\DateUtil; +use Barryvdh\Snappy\PdfWrapper; use PDF; class PDFDownLoadManager extends ReceiptIssuingOrderManager @@ -25,13 +28,7 @@ class PDFDownLoadManager extends ReceiptIssuingOrderManager { $order = $this->order; - $data = $this->getPDFData(); - - - $pdf = PDF::loadView('pdf/receipt_a4', $data); - // はがきサイズを指定 - $ret = $pdf->setPaper('A4') - ->setOption('encoding', 'utf-8') + $ret = $this->makeA4() ->inline(); if ($order->status_receipt_download_datetime === null) { @@ -44,6 +41,30 @@ class PDFDownLoadManager extends ReceiptIssuingOrderManager return $ret; } + + public function getA4File(): A4Receipt + { + $ret = $this->makeA4() + ->output(); + + $file = new A4Receipt(); + $file->put($ret); + + return $file; + } + + protected function makeA4(): PdfWrapper + { + $data = $this->getPDFData(); + + $pdf = PDF::loadView('pdf/receipt_a4', $data); + // はがきサイズを指定 + $ret = $pdf->setPaper('A4') + ->setOption('encoding', 'utf-8'); + + return $ret; + } + public function downlaodLetter() { $data = $this->getPDFData(); diff --git a/app/Logic/ReceiptIssuingOrder/UpdateManager.php b/app/Logic/ReceiptIssuingOrder/UpdateManager.php index b63a160..5fc03b7 100644 --- a/app/Logic/ReceiptIssuingOrder/UpdateManager.php +++ b/app/Logic/ReceiptIssuingOrder/UpdateManager.php @@ -2,11 +2,16 @@ namespace App\Logic\ReceiptIssuingOrder; +use App\Email\Guests\ReceiptA4; use App\Events\ReceiptIssuingOrder\ChangeHandlerEvent; use App\Events\ReceiptIssuingOrder\ConfirmedEvent; +use App\Events\ReceiptIssuingOrder\EmailOrderEvent; use App\Events\ReceiptIssuingOrder\MailOrderEvent; use App\Events\ReceiptIssuingOrder\MailPostedEvent; use App\Exceptions\AppCommonException; +use App\Files\PDF\Receipt\A4Receipt; +use App\Jobs\ReceiptIssuingOrder\PollEmailSendStatus; +use App\Logic\EmailManager; use App\Logic\SMS\SMSManager; use App\Models\ReceiptIssuingOrder; use App\Models\User; @@ -71,6 +76,43 @@ class UpdateManager extends ReceiptIssuingOrderManager return $this; } + /** + * 郵送投函完了 + * + * @param array $attr + * @return static + */ + public function emailOrder(string $email, A4Receipt $file, array $attr = []): static + { + $this->fill([ + ReceiptIssuingOrder::COL_NAME_EMAIL => $email, + ReceiptIssuingOrder::COL_NAME_STATUS_RECEIPT_EMAIL_SEND_ORDER_DATETIME => DateUtil::now(), + ...$attr, + ]); + + // メール送信 + $mail = new ReceiptA4($this->order); + $mail->setEmail($this->order->email); + $manager = new EmailManager($mail); + + $filename = sprintf("領収証_%s.pdf", $this->order->receipt_no); + + $manager->attach($file->getFullPath(), $filename, "application/pdf") + ->confirm(); + + + $this->fill([ + ReceiptIssuingOrder::COL_NAME_RECEIPT_PDF_EMAIL_ID => $manager->getEmailId() + ]); + + + // イベント登録 + EmailOrderEvent::dispatch($this->order); + PollEmailSendStatus::dispatch($this->order); + + return $this; + } + /** * 領収証確定 * diff --git a/app/Mail/Admins/Admin.php b/app/Mail/Admins/Admin.php deleted file mode 100644 index ca51c23..0000000 --- a/app/Mail/Admins/Admin.php +++ /dev/null @@ -1,15 +0,0 @@ -getAdminParams(), []); - } - - abstract public function getAdminParams(): array; -} diff --git a/app/Mail/Admins/Ask.php b/app/Mail/Admins/Ask.php deleted file mode 100644 index ceb15f1..0000000 --- a/app/Mail/Admins/Ask.php +++ /dev/null @@ -1,92 +0,0 @@ -setValues($data); - if ($seasonTicketContract) { - $this->seasonTicketSeqNo = $seasonTicketContract->season_ticket_seq_no; - } - if ($subscription) { - $this->subscribeDatetime = $subscription->subscribe_datetime; - } - if ($user) { - $this->userEmail = $user->email; - } - if ($userDetail) { - $this->userName = sprintf( - "%s %s", - $userDetail->first_name, - $userDetail->last_name - ); - } - if ($parking) { - $this->parkName = $parking->park_name; - } - } - - public function getTemplateName(): string - { - return 'mails.admins.ask'; - } - - public function getSubject(): string - { - return sprintf( - '【スマートパーキングパス】【問い合わせ】【%s】%s', - $this->userName, - $this->askSubject - ); - } - - private function memberRegistration(): string - { - if ($this->seasonTicketSeqNo !== null || $this->subscribeDatetime !== null) { - return "あり"; - } - return "なし"; - } - - public function getAdminParams(): array - { - return [ - 'askSubject' => $this->askSubject, - 'askContents' => $this->askContents, - - 'parkName' => $this->parkName, - 'userName' => $this->userName, - 'userEmail' => $this->userEmail, - - 'seasonTicketSeqNo' => $this->seasonTicketSeqNo, - 'subscribeDatetime' => $this->subscribeDatetime ? $this->subscribeDatetime->format('Y/m/d H:i:s') : null, - - 'memberRegistration' => $this->memberRegistration(), - ]; - } -} diff --git a/app/Mail/Common/AskConfirmation.php b/app/Mail/Common/AskConfirmation.php deleted file mode 100644 index bd7cb55..0000000 --- a/app/Mail/Common/AskConfirmation.php +++ /dev/null @@ -1,70 +0,0 @@ -setValues($data); - if ($user) { - $this->userEmail = $user->email; - $this->forMember = true; - } - if ($userDetail) { - $this->userName = sprintf( - "%s %s", - $userDetail->first_name, - $userDetail->last_name - ); - $this->forMember = true; - } - if ($parking) { - $this->parkName = $parking->park_name; - } - } - - public function getTemplateName(): string - { - return $this->forMember ? 'mails.members.ask_confirmation' : 'mails.guests.ask_confirmation'; - } - - public function getSubject(): string - { - return '【スマートパーキングパス】お問い合わせ内容の確認'; - } - - protected function getAskConfirmationParams(): array - { - return [ - 'askSubject' => $this->askSubject, - 'askContents' => $this->askContents, - - 'parkName' => $this->parkName, - 'userName' => $this->userName, - 'userEmail' => $this->userEmail, - ]; - } -} diff --git a/app/Mail/Guests/AskConfirmation.php b/app/Mail/Guests/AskConfirmation.php deleted file mode 100644 index af804be..0000000 --- a/app/Mail/Guests/AskConfirmation.php +++ /dev/null @@ -1,27 +0,0 @@ -setAskConfirmationData($data, $user, $userDetail, $parking); - } - - public function getGuestParams(): array - { - return $this->getAskConfirmationParams(); - } -} diff --git a/app/Mail/Guests/ChangeEmailStart.php b/app/Mail/Guests/ChangeEmailStart.php deleted file mode 100644 index c562030..0000000 --- a/app/Mail/Guests/ChangeEmailStart.php +++ /dev/null @@ -1,63 +0,0 @@ - 'datetime', - ]; - - /** - * Create a new message instance. - * - * @return void - */ - public function __construct(ChangeEmail $model) - { - logger($model->toArray()); - $this->setValues($model->toArray()); - } - - public function getTemplateName(): string - { - return 'mails.guests.change_email_start'; - } - - public function getSubject(): string - { - return '【スマートパーキングパス】Email変更手続きのご案内'; - } - - public function getGuestParams(): array - { - return [ - 'url' => $this->getUrl(), - 'expiresAt' => $this->getExpiresAt(), - ]; - } - - private function getUrl() - { - return implode( - "/", - [ - config("app.url"), - 'change-email', - $this->token - ] - ); - } - private function getExpiresAt() - { - return $this->expiresAt->format('Y/m/d H:i'); - } -} diff --git a/app/Mail/Guests/EmailVerify.php b/app/Mail/Guests/EmailVerify.php deleted file mode 100644 index 4b64333..0000000 --- a/app/Mail/Guests/EmailVerify.php +++ /dev/null @@ -1,65 +0,0 @@ - 'datetime', - ]; - - /** - * Create a new message instance. - * - * @return void - */ - public function __construct(ModelsEmailVerify $model) - { - $this->setValues($model->toArray()); - } - - public function getTemplateName(): string - { - return 'mails.guests.email_verify'; - } - - public function getSubject(): string - { - return '【スマートパーキングパス】会員登録のご案内'; - } - - public function getGuestParams(): array - { - return [ - 'url' => $this->getUrl(), - 'expiresAt' => $this->getExpiresAt(), - ]; - } - - private function getUrl() - { - return implode( - "/", - [ - config("app.url"), - 'register/user', - $this->token - ] - ); - } - private function getExpiresAt() - { - $date = $this->expiresAt; - if ($date !== null) { - return $date->format('Y/m/d H:i'); - } - throw new Exception("有効期限日付不正"); - } -} diff --git a/app/Mail/Members/AskConfirmation.php b/app/Mail/Members/AskConfirmation.php deleted file mode 100644 index f16ccce..0000000 --- a/app/Mail/Members/AskConfirmation.php +++ /dev/null @@ -1,27 +0,0 @@ -setAskConfirmationData($data, $user, $userDetail, $parking); - } - - public function getMemberParams(): array - { - return $this->getAskConfirmationParams(); - } -} diff --git a/app/Mail/Members/AutoCancelSeasonTicketContract.php b/app/Mail/Members/AutoCancelSeasonTicketContract.php deleted file mode 100644 index 5c3e504..0000000 --- a/app/Mail/Members/AutoCancelSeasonTicketContract.php +++ /dev/null @@ -1,42 +0,0 @@ -setValues($parking->toArray()); - $this->setValues($seasonTicketContract->toArray()); - } - - public function getTemplateName(): string - { - return 'mails.members.auto_cancel_season_ticket_contract'; - } - - public function getSubject(): string - { - return '【スマートパーキングパス】駐車場利用停止のお知らせ'; - } - - public function getMemberParams(): array - { - return [ - 'parkName' => $this->parkName, - 'seasonTicketSeqNo' => $this->seasonTicketSeqNo, - ]; - } -} diff --git a/app/Mail/Members/Bulk.php b/app/Mail/Members/Bulk.php deleted file mode 100644 index e777f0e..0000000 --- a/app/Mail/Members/Bulk.php +++ /dev/null @@ -1,37 +0,0 @@ -__subject = $subject; - $this->__contents = $contents; - } - - public function getTemplateName(): string - { - return 'mails.members.bulk'; - } - - public function getSubject(): string - { - return $this->__subject; - } - - public function getMemberParams(): array - { - return [ - 'contents' => $this->__contents, - ]; - } -} diff --git a/app/Mail/Members/Member.php b/app/Mail/Members/Member.php deleted file mode 100644 index 0499d13..0000000 --- a/app/Mail/Members/Member.php +++ /dev/null @@ -1,17 +0,0 @@ -getMemberParams(), [ - 'email' => $this->__email - ]); - } - - abstract public function getMemberParams(): array; -} diff --git a/app/Mail/Members/ResetIDm.php b/app/Mail/Members/ResetIDm.php deleted file mode 100644 index acdc6c1..0000000 --- a/app/Mail/Members/ResetIDm.php +++ /dev/null @@ -1,42 +0,0 @@ -context(); - - $seasonTicketContract = $context->getSeasonTicketContract(); - if ($seasonTicketContract === null) { - throw new AppCommonException("コンテキスト不正 定期契約情報"); - } - - $this->confirmationCode = $seasonTicketContract->confirmation_code; - $this->seasonTicketSeqNo = $seasonTicketContract->season_ticket_seq_no; - } - - public function getTemplateName(): string - { - return 'mails.members.reset_idm'; - } - - public function getSubject(): string - { - return '【スマートパーキングパス】ICカードリセットのお知らせ'; - } - - public function getMemberParams(): array - { - return [ - 'confirmationCode' => $this->confirmationCode, - 'seasonTicketSeqNo' => $this->seasonTicketSeqNo, - ]; - } -} diff --git a/app/Mail/Members/ResetPasswordStart.php b/app/Mail/Members/ResetPasswordStart.php deleted file mode 100644 index 094e1be..0000000 --- a/app/Mail/Members/ResetPasswordStart.php +++ /dev/null @@ -1,61 +0,0 @@ - 'datetime', - ]; - - /** - * Create a new message instance. - * - * @return void - */ - public function __construct(ResetPassword $model) - { - $this->setValues($model->toArray()); - } - - public function getTemplateName(): string - { - return 'mails.members.reset_password_start'; - } - - public function getSubject(): string - { - return '【スマートパーキングパス】パスワードリセット手続きのご案内'; - } - - public function getMemberParams(): array - { - return [ - 'url' => $this->getUrl(), - 'expiresAt' => $this->getExpiresAt(), - ]; - } - - private function getUrl() - { - return implode( - "/", - [ - config("app.url"), - 'password-reset', - $this->token - ] - ); - } - private function getExpiresAt() - { - return $this->expiresAt->format('Y/m/d H:i'); - } -} diff --git a/app/Mail/Members/SeasonTicketContractExpireRemind.php b/app/Mail/Members/SeasonTicketContractExpireRemind.php deleted file mode 100644 index 14de7f2..0000000 --- a/app/Mail/Members/SeasonTicketContractExpireRemind.php +++ /dev/null @@ -1,45 +0,0 @@ - 'datetime', - ]; - - /** - * Create a new message instance. - * - * @return void - */ - public function __construct(\stdClass $data) - { - $this->setValues($data); - } - - public function getTemplateName(): string - { - return 'mails.members.season_ticket_contract_expires_remind'; - } - - public function getSubject(): string - { - return '【スマートパーキングパス】定期期限切れ予告通知'; - } - - public function getMemberParams(): array - { - return [ - 'parkName' => $this->parkName, - 'seasonTicketSeqNo' => $this->seasonTicketSeqNo, - 'expirationEndDate' => $this->expirationEndDate, - ]; - } -} diff --git a/app/Mail/Members/Subscription/Approve.php b/app/Mail/Members/Subscription/Approve.php deleted file mode 100644 index e4a4c7b..0000000 --- a/app/Mail/Members/Subscription/Approve.php +++ /dev/null @@ -1,111 +0,0 @@ -email = $user->email; - $this->parkName = $parking->park_name; - $this->useStartRequestDate = $subscription ? $subscription->use_start_request_date : null; - $this->vehicleType = $seasonTicketContract->vehicle_type; - $this->contractorTypeName = $contractorTypeName; - $this->seasonTicketSeqNo = $seasonTicketContract->season_ticket_seq_no; - $this->confirmationCode = $seasonTicketContract->confirmation_code; - $this->parkingUseType = $seasonTicketContract->parking_use_type; - - $this->customerCode = $seasonTicketContract->customer_code; - $this->parkingManagementCode = $seasonTicketContract->parking_management_code; - } - - public function getTemplateName(): string - { - return 'mails.members.subscription.approve'; - } - - public function getSubject(): string - { - return '【スマートパーキングパス】定期申し込み完了'; - } - - public function getMemberParams(): array - { - return [ - 'email' => $this->email, - 'park_name' => $this->parkName, - 'use_start_request_date' => $this->getUseStartRequestDate(), - 'vehicle_type' => $this->getVehicleType(), - 'contractor_type_name' => $this->contractorTypeName, - 'how_to_use' => $this->getHowToUse(), - 'season_ticket_seq_no' => $this->seasonTicketSeqNo, - 'confirmation_code' => $this->confirmationCode, - 'ic_card_rental_request' => $this->parkingUseType === ParkingUseTypeCode::IC_RENTAL, - 'ic_self_card_request' => $this->parkingUseType === ParkingUseTypeCode::IC_SELF, - 'ic_qr_code_request' => $this->parkingUseType === ParkingUseTypeCode::QR, - 'my_qr_code_url' => $this->getMyQrCodeUrl(), - ]; - } - - private function getUseStartRequestDate() - { - if ($this->useStartRequestDate === null) return "-"; - return $this->useStartRequestDate->format("Y年m月d日"); - } - - private function getVehicleType() - { - return VehicleTypeCode::getName($this->vehicleType); - } - - private function getHowToUse() - { - switch ($this->parkingUseType) { - case ParkingUseTypeCode::IC_RENTAL: - return "貸与ICカード"; - case ParkingUseTypeCode::IC_SELF: - return "個人ICカード"; - case ParkingUseTypeCode::QR: - return "QRコード"; - } - throw new LogicException(sprintf("不適切な駐車場利用方法 %d", $this->parkingUseType->value)); - } - - private function getMyQrCodeUrl() - { - return $this->getAppUrl(['app', 'qrcode', 'detail', $this->customerCode, $this->parkingManagementCode]); - } -} diff --git a/app/Mail/Members/Subscription/Cancel.php b/app/Mail/Members/Subscription/Cancel.php deleted file mode 100644 index eb033d7..0000000 --- a/app/Mail/Members/Subscription/Cancel.php +++ /dev/null @@ -1,45 +0,0 @@ -context(); - $parking = $context->getParking(); - if ($parking === null) { - throw new AppCommonException("コンテキスト不正 駐車場情報"); - } - - $this->parkName = $parking->park_name; - } - - public function getTemplateName(): string - { - return 'mails.members.subscription.cancel'; - } - - public function getSubject(): string - { - return '【スマートパーキングパス】申込キャンセルのお知らせ'; - } - - public function getMemberParams(): array - { - return [ - 'parkName' => $this->parkName, - ]; - } -} diff --git a/app/Mail/Members/Subscription/Entry.php b/app/Mail/Members/Subscription/Entry.php deleted file mode 100644 index c078344..0000000 --- a/app/Mail/Members/Subscription/Entry.php +++ /dev/null @@ -1,70 +0,0 @@ -context(); - - $user = $context->getUser(); - $subscription = $context->getSeasonTicketContractSubscription(); - $parking = $context->getParking(); - - if ($user === null) { - throw new AppCommonException("コンテキスト不正 利用者情報"); - } - if ($subscription === null) { - throw new AppCommonException("コンテキスト不正 申込情報"); - } - if ($parking === null) { - throw new AppCommonException("コンテキスト不正 駐車場情報"); - } - - $this->email = $user->email; - $this->parkName = $parking->park_name; - $this->useStartRequestDate = $subscription->use_start_request_date; - $this->memo = $subscription->memo ?? ""; - } - - public function getTemplateName(): string - { - return 'mails.members.subscription.entry'; - } - - public function getSubject(): string - { - return '【スマートパーキングパス】定期申し込み内容'; - } - - public function getMemberParams(): array - { - return [ - 'email' => $this->email, - 'park_name' => $this->parkName, - 'use_start_request_date' => $this->getUseStartRequestDate(), - 'memo' => $this->memo - ]; - } - - public function getUseStartRequestDate() - { - if ($this->useStartRequestDate === null) return "-"; - return $this->useStartRequestDate->format("Y年m月d日"); - } -} diff --git a/app/Mail/Members/Subscription/Hold.php b/app/Mail/Members/Subscription/Hold.php deleted file mode 100644 index 747e1c6..0000000 --- a/app/Mail/Members/Subscription/Hold.php +++ /dev/null @@ -1,47 +0,0 @@ -context(); - $parking = $context->getParking(); - if ($parking === null) { - throw new AppCommonException("コンテキスト不正 駐車場情報"); - } - - $this->parkName = $parking->park_name; - $this->message = $message->message; - } - - public function getTemplateName(): string - { - return 'mails.members.subscription.hold'; - } - - public function getSubject(): string - { - return '【スマートパーキングパス】申込確認のお知らせ'; - } - - public function getMemberParams(): array - { - return [ - 'parkName' => $this->parkName, - 'memo' => $this->message, - ]; - } -} diff --git a/app/Mail/Members/Subscription/Reject.php b/app/Mail/Members/Subscription/Reject.php deleted file mode 100644 index 53e7e1d..0000000 --- a/app/Mail/Members/Subscription/Reject.php +++ /dev/null @@ -1,47 +0,0 @@ -context(); - $parking = $context->getParking(); - if ($parking === null) { - throw new AppCommonException("コンテキスト不正 駐車場情報"); - } - - $this->parkName = $parking->park_name; - $this->message = $message->message ?? ""; - } - - public function getTemplateName(): string - { - return 'mails.members.subscription.reject'; - } - - public function getSubject(): string - { - return '【スマートパーキングパス】申込却下のお知らせ'; - } - - public function getMemberParams(): array - { - return [ - 'parkName' => $this->parkName, - 'memo' => $this->message, - ]; - } -} diff --git a/app/Mail/Members/Subscription/Returned.php b/app/Mail/Members/Subscription/Returned.php deleted file mode 100644 index b0af117..0000000 --- a/app/Mail/Members/Subscription/Returned.php +++ /dev/null @@ -1,48 +0,0 @@ -context(); - $parking = $context->getParking(); - if ($parking === null) { - throw new AppCommonException("コンテキスト不正 駐車場情報"); - } - - $this->parkName = $parking->park_name; - $this->message = $message->message ?? ""; - } - - public function getTemplateName(): string - { - return 'mails.members.subscription.returned'; - } - - public function getSubject(): string - { - return '【スマートパーキングパス】申込差し戻しのお知らせ'; - } - - public function getMemberParams(): array - { - return [ - 'parkName' => $this->parkName, - 'memo' => $this->message, - ]; - } -} diff --git a/app/Mail/Members/UserRegisterComplete.php b/app/Mail/Members/UserRegisterComplete.php deleted file mode 100644 index fe53a28..0000000 --- a/app/Mail/Members/UserRegisterComplete.php +++ /dev/null @@ -1,76 +0,0 @@ -email = $model->email; - - if ($password !== null) { - $this->includePasswordReset = true; - $this->expiresAt = $password->expires_at; - $this->token = $password->token; - } - } - - public function getTemplateName(): string - { - return 'mails.members.user_register_complete'; - } - - public function getSubject(): string - { - return '【スマートパーキングパス】会員登録完了'; - } - - public function getMemberParams(): array - { - return [ - 'email' => $this->email, - 'includePasswordReset' => $this->includePasswordReset, - 'url' => $this->getUrl(), - 'expiresAt' => $this->getExpiresAt(), - ]; - } - - private function getUrl() - { - return implode( - "/", - [ - config("app.url"), - 'password-reset', - $this->token - ] - ); - } - - private function getExpiresAt() - { - if ($this->expiresAt === null) { - return ""; - } else { - return $this->expiresAt->format('Y/m/d H:i'); - } - } -} diff --git a/app/Models/AppModel.php b/app/Models/AppModel.php index 8ac7198..d40e4b6 100644 --- a/app/Models/AppModel.php +++ b/app/Models/AppModel.php @@ -23,6 +23,8 @@ abstract class AppModel extends BaseModel public function setId(?string $uuid = null) { + if ($this->id !== null) return; + if ($uuid) { $this->id = $uuid; } else { diff --git a/app/Models/ColumnName.php b/app/Models/ColumnName.php index a086e01..472f118 100644 --- a/app/Models/ColumnName.php +++ b/app/Models/ColumnName.php @@ -19,4 +19,5 @@ abstract class ColumnName const RECEIPT_ISSUING_ORDER_ID = "receipt_issuing_order_id"; const SMS_SEND_ORDER_ID = "sms_send_order_id"; const SMS_PROVIDER_ID = "sms_provider_id"; + const EMAIL_ID = "email_id"; } diff --git a/app/Models/Email.php b/app/Models/Email.php index 3de9689..8c7d0bb 100644 --- a/app/Models/Email.php +++ b/app/Models/Email.php @@ -2,11 +2,23 @@ namespace App\Models; +use Illuminate\Database\Eloquent\Relations\HasMany; class Email extends AppModel { + const COL_NAME_SEND_DATETIME = "send_datetime"; + public function getModelName(): string { return "Email"; } + + public function emailAttachments(): HasMany + { + return $this->hasMany(EmailAttachment::class); + } + + protected $casts = [ + self::COL_NAME_SEND_DATETIME => 'datetime', + ]; } diff --git a/app/Models/EmailAttachment.php b/app/Models/EmailAttachment.php new file mode 100644 index 0000000..2f7d3a8 --- /dev/null +++ b/app/Models/EmailAttachment.php @@ -0,0 +1,17 @@ + 'datetime', self::COL_NAME_STATUS_MAIL_POST_DATE => 'date', self::COL_NAME_STATUS_RECEIPT_DOWNLOAD_DATETIME => 'datetime', + self::COL_NAME_STATUS_RECEIPT_EMAIL_SEND_ORDER_DATETIME => 'datetime', self::COL_NAME_STATUS_RECEIPT_EMAIL_SEND_DATETIME => 'datetime', self::COL_NAME_RECEIPT_USE_DATE => 'date', self::COL_NAME_MAIL_PREF_CODE => PrefCode::class, diff --git a/app/Util/MigrationHelper.php b/app/Util/MigrationHelper.php index 9371373..5b56a57 100644 --- a/app/Util/MigrationHelper.php +++ b/app/Util/MigrationHelper.php @@ -78,6 +78,9 @@ class MigrationHelper $this->table->timestamp(ColumnName::UPDATED_AT)->nullable()->comment("更新日時"); $this->table->timestamp(ColumnName::DELETED_AT)->nullable()->comment("論理削除日時"); + $this->table->index([ColumnName::CREATED_AT], sprintf("%s_idx_CREATED_AT", $this->table->getTable())); + $this->table->index([ColumnName::UPDATED_AT], sprintf("%s_idx_UPDATED_AT", $this->table->getTable())); + return $this; } @@ -159,4 +162,10 @@ class MigrationHelper // $this->table->foreign(ColumnName::SMS_PROVIDER_ID)->references(ColumnName::ID)->on(SMSProvider::getTableName()); return $this; } + + public function emailId(bool $nullable = false) + { + $this->table->uuid(ColumnName::EMAIL_ID)->comment("EメールID")->nullable($nullable); + return $this; + } } diff --git a/config/mail.php b/config/mail.php index 542d98c..b3851fd 100644 --- a/config/mail.php +++ b/config/mail.php @@ -43,6 +43,8 @@ return [ 'password' => env('MAIL_PASSWORD'), 'timeout' => null, 'local_domain' => env('MAIL_EHLO_DOMAIN'), + 'auth_mode' => null, + 'verify_peer' => false, ], 'ses' => [ diff --git a/database/migrations/2023_07_11_134700_create_email_attachments_table.php b/database/migrations/2023_07_11_134700_create_email_attachments_table.php new file mode 100644 index 0000000..48060e6 --- /dev/null +++ b/database/migrations/2023_07_11_134700_create_email_attachments_table.php @@ -0,0 +1,46 @@ +schema()); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('email_attachments'); + } + + private function schema() + { + + return function (Blueprint $table, MigrationHelper $helper) { + $helper->baseColumn() + ->emailId(); + + $table->string('filepath')->comment("ファイルパス"); + $table->string('send_filename')->comment("送信ファイル名"); + $table->string('mime')->comment("MIMEタイプ"); + + $helper->index(1, [ColumnName::EMAIL_ID]); + $helper->index(2, [ColumnName::CREATED_AT]); + }; + } +}; diff --git a/database/migrations/2023_07_12_161800_add_column_receipt_issuing_orders_table_email_id.php b/database/migrations/2023_07_12_161800_add_column_receipt_issuing_orders_table_email_id.php new file mode 100644 index 0000000..0cd5b6d --- /dev/null +++ b/database/migrations/2023_07_12_161800_add_column_receipt_issuing_orders_table_email_id.php @@ -0,0 +1,40 @@ +uuid("receipt_pdf_email_id")->nullable()->comment("領収書PDF送付EmailID"); + }); + Schema::table('receipt_issuing_order_histories', function (Blueprint $table) { + $table->uuid("receipt_pdf_email_id")->nullable()->comment("領収書PDF送付EmailID"); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('receipt_issuing_orders', function (Blueprint $table) { + $table->dropColumn("receipt_pdf_email_id"); + }); + Schema::table('receipt_issuing_order_histories', function (Blueprint $table) { + $table->dropColumn("receipt_pdf_email_id"); + }); + } +}; diff --git a/deploy.sh b/deploy.sh index bc91294..86b9345 100644 --- a/deploy.sh +++ b/deploy.sh @@ -20,6 +20,7 @@ COMMANDS+=("${SAIL} php artisan config:cache") COMMANDS+=("${SAIL} php artisan route:cache") COMMANDS+=("${SAIL} php artisan view:cache") COMMANDS+=("${SAIL} php artisan event:cache") +COMMANDS+=("${SAIL} php artisan queue:restart") for COMMAND in "${COMMANDS[@]}"; do echo ${COMMAND} diff --git a/resources/views/mails/components/ask_confirmation.blade.php b/resources/views/mails/components/ask_confirmation.blade.php deleted file mode 100644 index eb2e4ab..0000000 --- a/resources/views/mails/components/ask_confirmation.blade.php +++ /dev/null @@ -1,14 +0,0 @@ -下記内容にてお問合せを受付ました。 -返信のメールがあるまでしばらくお待ちください。 - -件名: {{ $askSubject }} -@if($parkName) -駐車場名 : {{ $parkName }} -@endif - -■問い合わせ内容 -{{ $askContents }} - -■問い合わせ者情報 -氏名: {{ $userName }} -email: {{ $userEmail }} \ No newline at end of file diff --git a/resources/views/mails/components/season_ticket_contract/how_to_register_ic_card.blade.php b/resources/views/mails/components/season_ticket_contract/how_to_register_ic_card.blade.php deleted file mode 100644 index 08a14a3..0000000 --- a/resources/views/mails/components/season_ticket_contract/how_to_register_ic_card.blade.php +++ /dev/null @@ -1,7 +0,0 @@ - ①駐車場に設置された定期更新機で利用したい交通系ICカード(ICOCA,SUICAなど)をタッチします。 - ②画面が切り替わりますので、上記定期券番号と確認コードを入力して確定ボタンを押してください。 -  または、承認画面で認証用QRコードをかざしても定期券登録が完了します。 -@isset($my_qr_code_url) - 認証用QRコードは以下(初回アクセスの場合はパスワードを設定してログインしてください) - {{ $my_qr_code_url }} -@endisset \ No newline at end of file diff --git a/resources/views/mails/components/send_only.blade.php b/resources/views/mails/components/send_only.blade.php deleted file mode 100644 index 46c35fc..0000000 --- a/resources/views/mails/components/send_only.blade.php +++ /dev/null @@ -1 +0,0 @@ -※このメールをお送りしているアドレスは、送信専用となっており、返信いただいてもご回答いたしかねます。 \ No newline at end of file diff --git a/resources/views/mails/guests/receipt_a4.blade.php b/resources/views/mails/guests/receipt_a4.blade.php new file mode 100644 index 0000000..ff09c7c --- /dev/null +++ b/resources/views/mails/guests/receipt_a4.blade.php @@ -0,0 +1,15 @@ +@extends('mails.layouts.guest') + +@section('contents') +発行依頼された領収証を添付します。 +ご確認よろしくお願いいたします。 + +■店舗名 +{{ $shopName }} + +■利用日 +{{ $useDate }} + +■金額 +{{ $amount }}円 +@endsection \ No newline at end of file diff --git a/resources/views/mails/layouts/guest.blade.php b/resources/views/mails/layouts/guest.blade.php new file mode 100644 index 0000000..c610e35 --- /dev/null +++ b/resources/views/mails/layouts/guest.blade.php @@ -0,0 +1,11 @@ +ご利用ありがとうございます。 +EasyReceiptです。 + +@yield('contents') + + +※このメールをお送りしているアドレスは、送信専用となっており、返信いただいてもご回答いたしかねます。 +※このメールにお心当たりのない方は、お手数ですが削除いただきますようお願いいたします。 + +--------------------------------------------------------------------------------------- +EasyReceipt \ No newline at end of file diff --git a/routes/api.php b/routes/api.php index 0a92e0f..247e926 100644 --- a/routes/api.php +++ b/routes/api.php @@ -20,6 +20,7 @@ RouteHelper::post('/change-contract', App\Http\Controllers\Web\Auth\ChangeContra RouteHelper::get('/app-token-check', App\Http\Controllers\Web\ReceiptIssuingOrder\TokenCheckController::class); RouteHelper::post('/receipt-issuing-order/confirm', App\Http\Controllers\Web\ReceiptIssuingOrder\ConfirmController::class); +RouteHelper::post('/receipt-issuing-order/email-order', App\Http\Controllers\Web\ReceiptIssuingOrder\EmailOrderController::class); RouteHelper::post('/receipt-issuing-order/mail-order', App\Http\Controllers\Web\ReceiptIssuingOrder\MailOrderController::class); RouteHelper::post('/receipt-issuing-order/mail-complete', App\Http\Controllers\Web\ReceiptIssuingOrder\MailPostCompleteController::class); RouteHelper::post('/receipt-issuing-order/change-handler', App\Http\Controllers\Web\ReceiptIssuingOrder\ChangeHandlerController::class);