領収証発行サービス
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

262 lines
6.9KB

  1. <?php
  2. namespace App\Logic\ReceiptIssuingOrder;
  3. use App\Exceptions\AppCommonException;
  4. use App\Exceptions\ExclusiveException;
  5. use App\Features\InstanceAble;
  6. use App\Features\LoginUser;
  7. use App\Models\ReceiptIssuingOrder;
  8. use App\Models\User;
  9. use App\Util\DateUtil;
  10. use Illuminate\Support\Carbon;
  11. use Illuminate\Support\Str;
  12. use LogicException;
  13. abstract class ReceiptIssuingOrderManager
  14. {
  15. use LoginUser, InstanceAble;
  16. protected bool $initialized = false;
  17. public function __construct(
  18. protected ReceiptIssuingOrder $order,
  19. ) {
  20. }
  21. public function initByToken(string $token)
  22. {
  23. $ret = $this->checkToken($token);
  24. if (!$ret) {
  25. throw new AppCommonException("トークン不正");
  26. }
  27. $this->initialized = true;
  28. return $this;
  29. }
  30. public function initById(string $id)
  31. {
  32. $this->fetch($id);
  33. $this->initialized = true;
  34. return $this;
  35. }
  36. public function changeHandler(User $newHandler)
  37. {
  38. if (!$this->initialized) {
  39. throw new LogicException("初期化ミス");
  40. }
  41. if ($this->order->contract_id !== $newHandler->contract_id) {
  42. throw new AppCommonException('契約不正');
  43. }
  44. $this->order->handler_id = $newHandler->id;
  45. return $this;
  46. }
  47. public function getOrder(): array
  48. {
  49. if (!$this->initialized) {
  50. throw new LogicException("初期化ミス");
  51. }
  52. return $this->order->toArray();
  53. }
  54. public function isConfirmed(): bool
  55. {
  56. if (!$this->initialized) {
  57. throw new LogicException("初期化ミス");
  58. }
  59. return $this->order->status_receipt_confirm_datetime !== null;
  60. }
  61. public function checkTimestamp(Carbon $timestamp): static
  62. {
  63. if (!$this->initialized) {
  64. throw new LogicException("初期化ミス");
  65. }
  66. if ($this->order->updated_at->notEqualTo($timestamp)) {
  67. throw new ExclusiveException();
  68. }
  69. return $this;
  70. }
  71. protected function fetch(string $receiptIssuingOrderId)
  72. {
  73. $order = ReceiptIssuingOrder::findOrFail($receiptIssuingOrderId);
  74. if (!$this->loginUser()->checkAuthorization($order)) {
  75. throw new AppCommonException("認可不良");
  76. }
  77. $this->order = $order;
  78. }
  79. protected function refreshToken()
  80. {
  81. $order = $this->order;
  82. $order->access_token = base64_encode(Str::uuid());
  83. $order->access_token_expires_at = DateUtil::now()->adddays(7);
  84. return $this;
  85. }
  86. protected function checkToken(string $token): bool
  87. {
  88. $order = ReceiptIssuingOrder::whereAccessToken($token)
  89. ->first();
  90. if (!($order instanceof ReceiptIssuingOrder)) {
  91. return false;
  92. }
  93. if ($order->access_token_expires_at === null) {
  94. return false;
  95. }
  96. if ($order->access_token !== $token) {
  97. logger("TOKEN 期限切れ");
  98. return false;
  99. }
  100. $now = DateUtil::now();
  101. $ret = $now->lt($this->order->access_token_expires_at);
  102. if (!$ret) {
  103. logger("TOKEN 期限切れ");
  104. return false;
  105. }
  106. $this->order = $order;
  107. $this->initialized = true;
  108. return true;
  109. }
  110. protected function setStatus(): static
  111. {
  112. $order = $this->order;
  113. $order->status_done = false;
  114. // 郵送関連
  115. if ($order->status_mail_post_date !== null) {
  116. $order->status_name = "投函済み";
  117. $order->status_done = true;
  118. return $this;
  119. }
  120. if ($order->status_order_mail_datetime !== null) {
  121. $order->status_name = "郵送依頼中";
  122. return $this;
  123. }
  124. // メール配信
  125. if ($order->status_receipt_email_send_datetime !== null) {
  126. $order->status_name = "領収証メール配信済み";
  127. $order->status_done = true;
  128. return $this;
  129. }
  130. if ($order->status_mail_post_date !== null) {
  131. $order->status_name = "領収証メール配信依頼中";
  132. return $this;
  133. }
  134. // ダウンロード
  135. if ($order->status_receipt_download_datetime !== null) {
  136. $order->status_name = "ダウンロード済み";
  137. $order->status_done = true;
  138. return $this;
  139. }
  140. // 申請段階
  141. if ($order->status_receipt_confirm_datetime !== null) {
  142. $order->status_name = "確定済み";
  143. return $this;
  144. }
  145. if ($order->status_first_access_datetime !== null) {
  146. $order->status_name = "アクセス済み";
  147. return $this;
  148. }
  149. if ($order->status_sms_send_datetime !== null) {
  150. $order->status_name = "SMS配信済み";
  151. return $this;
  152. }
  153. if ($order->sms_send_success === false) {
  154. $order->status_name = "SMS送信失敗";
  155. return $this;
  156. }
  157. $order->status_name = "新規登録";
  158. return $this;
  159. }
  160. protected function save(): static
  161. {
  162. $this->setStatus()
  163. ->updateCheck();
  164. $this->order->save();
  165. return $this;
  166. }
  167. public function setConfirm(): static
  168. {
  169. if ($this->order->receipt_no !== null) {
  170. throw new LogicException("領収証確定済み変更検知");
  171. }
  172. $this->order->receipt_no = $this->generateReceiptnNo();
  173. $this->order->status_receipt_confirm_datetime = DateUtil::now();
  174. return $this;
  175. }
  176. private function generateReceiptnNo(): string
  177. {
  178. $count = 0;
  179. while (true) {
  180. $now = DateUtil::now();
  181. $receiptNo = sprintf("%04d%02d%02d-%06d", $now->year, $now->month, $now->day, random_int(0, 999999));
  182. if (!ReceiptIssuingOrder::whereReceiptNo($receiptNo)->exists()) {
  183. return $receiptNo;
  184. }
  185. $count++;
  186. if (1000 < $count) {
  187. throw new AppCommonException("領収証番号取得不正エラー");
  188. }
  189. }
  190. }
  191. private function updateCheck(): static
  192. {
  193. // 確定済みデータの変更確認
  194. if ($this->order->getOriginal(ReceiptIssuingOrder::COL_NAME_STATUS_RECEIPT_CONFIRM_DATETIME) !== null) {
  195. if ($this->order->isDirty([
  196. ReceiptIssuingOrder::COL_NAME_RECEIPT_USE_DATE,
  197. ReceiptIssuingOrder::COL_NAME_RECEIPT_SHOP_NAME,
  198. ReceiptIssuingOrder::COL_NAME_RECEIPT_ISSUER,
  199. ReceiptIssuingOrder::COL_NAME_RECEIPT_PURPOSE,
  200. ReceiptIssuingOrder::COL_NAME_RECEIPT_NAME,
  201. ReceiptIssuingOrder::COL_NAME_RECEIPT_INVOICE_NO,
  202. ReceiptIssuingOrder::COL_NAME_RECEIPT_AMOUNT,
  203. ])) {
  204. throw new LogicException("確定済みデータの変更を検知");
  205. }
  206. }
  207. return $this;
  208. }
  209. }