diff --git a/app/Codes/Email.php b/app/Codes/Email.php index c737d82..6c2ef9a 100644 --- a/app/Codes/Email.php +++ b/app/Codes/Email.php @@ -11,4 +11,5 @@ enum Email: string case ENTRY_PAYMENT_COMPLETE = '申込承認'; case CHANGE_PLAN_ORDER_APPROVE = 'プラン変更完了'; case COULD_NOT_PEY_NOTICE = '口座振替・未納者通知'; + case REGISTER_CREDITCARD = 'クレジットカード登録'; } diff --git a/app/Console/Commands/PoolTransfer/MoveToPool.php b/app/Console/Commands/PoolTransfer/MoveToPool.php index a4feb69..6d7484c 100644 --- a/app/Console/Commands/PoolTransfer/MoveToPool.php +++ b/app/Console/Commands/PoolTransfer/MoveToPool.php @@ -6,6 +6,7 @@ use App\Console\Commands\BaseCommand; use App\Exceptions\SkipException; use App\Kintone\KintoneRecordQueryOperator; use App\Kintone\Models\BankCheckResult; +use App\Kintone\Models\CreditcardAutoPaymentResult; use App\Kintone\Models\DropDown\SmbcPayment\SmbcPaymentStatus; use App\Kintone\Models\SmbcAccountTransferResult; use App\Kintone\Models\SmbcPayment; @@ -77,7 +78,7 @@ class MoveToPool extends BaseCommand return self::RESULTCODE_SUCCESS; } - public function handleData(YuchoPaymentResult|SmbcPayment|SmbcAccountTransferResult|BankCheckResult $payment) + public function handleData(YuchoPaymentResult|SmbcPayment|SmbcAccountTransferResult|BankCheckResult|CreditcardAutoPaymentResult $payment) { $manager = new PoolTransferManager(); @@ -85,12 +86,12 @@ class MoveToPool extends BaseCommand } /** - * @return Collection + * @return Collection */ public function getTargets() { /** - * @var Collection + * @var Collection */ $ret = collect(); @@ -129,6 +130,7 @@ class MoveToPool extends BaseCommand CollectionUtil::pushAll($ret, $targets); $this->outputInfo(sprintf("バンクチェック 支払完了:%d件", $targets->count())); + // バンクチェック 支払期限切れ $query = BankCheckResult::getQuery()->whereNotIn(BankCheckResult::FIELD_POOL_DONE, ["済"]) ->whereNotNull(BankCheckResult::FIELD_CUSTOMER_CODE) ->where(BankCheckResult::FIELD_REMAINING_AMOUNT, 0, KintoneRecordQueryOperator::NEQ) @@ -137,6 +139,15 @@ class MoveToPool extends BaseCommand CollectionUtil::pushAll($ret, $targets); $this->outputInfo(sprintf("バンクチェック 支払期限切れ:%d件", $targets->count())); + // クレジットカード + $query = CreditcardAutoPaymentResult::getQuery()->whereNotIn(CreditcardAutoPaymentResult::FIELD_POOL_DONE, ["済"]) + ->whereNotNull(CreditcardAutoPaymentResult::FIELD_CUSTOMER_CODE) + ->where(CreditcardAutoPaymentResult::FIELD_PAYMENT_AMOUNT, 0, KintoneRecordQueryOperator::GT); + $targets = CreditcardAutoPaymentResult::getAccess()->all($query); + CollectionUtil::pushAll($ret, $targets); + $this->outputInfo(sprintf("クレジットカード支払 :%d件", $targets->count())); + + return $ret; } } diff --git a/app/Email/Members/RegisterCreditcard.php b/app/Email/Members/RegisterCreditcard.php new file mode 100644 index 0000000..acbaad4 --- /dev/null +++ b/app/Email/Members/RegisterCreditcard.php @@ -0,0 +1,46 @@ +getCustomer(); + } + parent::__construct($customer); + } + + public function getTemplateName(): string + { + return 'emails.members.register_creditcard'; + } + + public function getSubject(): string + { + return "クレジットカード登録のご案内"; + } + + public function getMemberParams(): array + { + return [ + 'url' => $this->getAppUrl([ + 'dashboard', + 'robot-payment', + 'creditcard', + 'register', + $this->application->token + ]), + 'expires_at' => $this->application->tokenExpiresAt->format('Y/m/d H:i') + ]; + } +} diff --git a/app/Http/Controllers/Web/Auth/LoginCheckController.php b/app/Http/Controllers/Web/Auth/LoginCheckController.php index a2b1683..d5c5dd1 100644 --- a/app/Http/Controllers/Web/Auth/LoginCheckController.php +++ b/app/Http/Controllers/Web/Auth/LoginCheckController.php @@ -38,7 +38,6 @@ class LoginCheckController extends WebController $users = User::whereEmail($param->email) ->get(); foreach ($users as $user) { - info($user->toArray()); if (!Hash::check($param->password, $user->password)) { return $this->failedResponse(); } diff --git a/app/Http/Controllers/Web/Auth/LoginController.php b/app/Http/Controllers/Web/Auth/LoginController.php index 75f314e..7527107 100644 --- a/app/Http/Controllers/Web/Auth/LoginController.php +++ b/app/Http/Controllers/Web/Auth/LoginController.php @@ -65,5 +65,7 @@ class LoginController extends WebController Auth::login($user); return $this->successResponse($customer->toArray()); } + + return $this->failedResponse(); } } diff --git a/app/Http/Controllers/Web/Customer/ChangePaymentMethodCreditcardOrderController.php b/app/Http/Controllers/Web/Customer/ChangePaymentMethodCreditcardOrderController.php new file mode 100644 index 0000000..4ab9d90 --- /dev/null +++ b/app/Http/Controllers/Web/Customer/ChangePaymentMethodCreditcardOrderController.php @@ -0,0 +1,51 @@ +middleware('auth:sanctum'); + } + + protected function run(Request $request): JsonResponse + { + + $customer = Customer::getSelf(); + + if (!$customer->canPayByCreditcard()) { + return $this->failedResponse(); + } + + $application = new ChangePaymentMethodCreditcardOrderApplication(); + $manager = new GeneralApplicationManager($application); + $manager + ->setCustomer($customer) + ->makeApplication(); + + $application->save(); + + return $this->successResponse(); + } +} diff --git a/app/Http/Controllers/Web/Customer/ChangePaymentMethodCreditcardOrderParam.php b/app/Http/Controllers/Web/Customer/ChangePaymentMethodCreditcardOrderParam.php new file mode 100644 index 0000000..7d9e2e9 --- /dev/null +++ b/app/Http/Controllers/Web/Customer/ChangePaymentMethodCreditcardOrderParam.php @@ -0,0 +1,9 @@ +setEmail(new CouldNotPayNotice($seasonTicketContract, $paymentPlan)); return; } + if ($emailId === Email::REGISTER_CREDITCARD) { + $application = ChangePaymentMethodCreditcardOrderApplication::findByApplicationNo($this->param->applicationNo); + $this->setEmail(new RegisterCreditcard($application)); + return; + } if ($this->email === null || $this->emailManager === null) { diff --git a/app/Http/Controllers/Web/RobotPayment/BanckCheck/PaymentInfoController.php b/app/Http/Controllers/Web/RobotPayment/BanckCheck/PaymentInfoController.php index 6735951..06e138e 100644 --- a/app/Http/Controllers/Web/RobotPayment/BanckCheck/PaymentInfoController.php +++ b/app/Http/Controllers/Web/RobotPayment/BanckCheck/PaymentInfoController.php @@ -64,7 +64,10 @@ class PaymentInfoController extends WebController $requestArr = request()->toArray(); unset($requestArr["token"]); - $model->dataEntry = json_encode($requestArr); + $model->dataEntry = json_encode( + $requestArr, + JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT + ); $model->save(); } @@ -93,7 +96,10 @@ class PaymentInfoController extends WebController $requestArr = request()->toArray(); unset($requestArr["token"]); - $model->dataResult = json_encode($requestArr); + $model->dataResult = json_encode( + $requestArr, + JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT + ); $model->save(); } diff --git a/app/Http/Controllers/Web/RobotPayment/CreditCard/PaymentInfoController.php b/app/Http/Controllers/Web/RobotPayment/CreditCard/PaymentInfoController.php new file mode 100644 index 0000000..d96ebc4 --- /dev/null +++ b/app/Http/Controllers/Web/RobotPayment/CreditCard/PaymentInfoController.php @@ -0,0 +1,107 @@ +param; + logger("リクエスト受信 creditcard", ["param" => $request->all()]); + + // 認証チェック + // 初回の決済結果はトークン付で送信されるのでチェックする + if ($param->token !== config('custom.creditcard.token')) { + abort(403); + } + + $customer = Customer::findByCustomerCode($param->customerCode); + + $customer->paymentMethod = "クレジットカード"; + + $model = new CreditcardAutoPaymentInfo(); + + $model->customerCode = $param->customerCode; + $model->autoPaymentNo = $param->acid; + $model->shopOrderNo = $param->cod; + $model->paymentInterval = $this->getPaymentInterval(); + $model->paymentAmount = $this->getPaymentAmount(); + + // 機密な情報をリクエストデータから除外して登録する + $requestArr = request()->toArray(); + unset($requestArr["token"]); + unset($requestArr["id"]); + unset($requestArr["pa"]); + $model->dataResult = json_encode( + $requestArr, + JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT + ); + + $model->save(); + $customer->save(); + + return response()->view('robot-payment.creditcard.ok'); + } + + private function getPaymentAmount(): int + { + $param = $this->param; + return intval($param->acam) + intval($param->actx) + intval($param->acsf); + } + + private function getPaymentInterval(): string + { + $code = $this->param->actp; + if ($code === "2") { + return "毎週課金"; + } + if ($code === "3") { + return "隔週課金"; + } + if ($code === "4") { + return "毎月課金"; + } + if ($code === "5") { + return "隔月課金"; + } + if ($code === "6") { + return "3ヶ月課金"; + } + if ($code === "7") { + return "6ヶ月課金"; + } + if ($code === "8") { + return "1年課金"; + } + + return ""; + } +} diff --git a/app/Http/Controllers/Web/RobotPayment/CreditCard/PaymentInfoParam.php b/app/Http/Controllers/Web/RobotPayment/CreditCard/PaymentInfoParam.php new file mode 100644 index 0000000..4941865 --- /dev/null +++ b/app/Http/Controllers/Web/RobotPayment/CreditCard/PaymentInfoParam.php @@ -0,0 +1,50 @@ + $this->str(), + 'rst' => $this->str(), + 'ap' => $this->str(), + 'ec' => $this->str(true), + 'god' => $this->str(), + 'cod' => $this->str(), + 'am' => $this->numeric(), + 'tx' => $this->numeric(true), + 'sf' => $this->numeric(true), + 'ta' => $this->numeric(true), + 'acam' => $this->numeric(true), + 'actx' => $this->numeric(true), + 'acsf' => $this->numeric(true), + 'actp' => $this->str(true), + 'acid' => $this->str(), + 'customer_code' => $this->str(true), + 'token' => $this->str(true), + ]; + } +} diff --git a/app/Http/Controllers/Web/RobotPayment/CreditCard/PaymentResultController.php b/app/Http/Controllers/Web/RobotPayment/CreditCard/PaymentResultController.php new file mode 100644 index 0000000..3edf8ba --- /dev/null +++ b/app/Http/Controllers/Web/RobotPayment/CreditCard/PaymentResultController.php @@ -0,0 +1,107 @@ +param; + logger("リクエスト受信 creditcard result", ["param" => $request->all()]); + + try { + + $info = CreditcardAutoPaymentInfo::getAccess()->first( + CreditcardAutoPaymentInfo::getQuery() + ->where(CreditcardAutoPaymentInfo::FIELD_AUTO_PAYMENT_NO, $param->acid) + ->where(CreditcardAutoPaymentInfo::FIELD_SHOP_ORDER_NO, $param->cod) + ); + } catch (ModelNotFoundException $e) { + Log::error(sprintf( + "自動課金情報が存在しないため、クレジットカードの決済結果保存不可 自動課金番号<%s> 店舗側オーダー番号<%s>", + $param->acid, + $param->cod + )); + throw $e; + } + + $this->クレジット支払結果登録($info); + + return response()->view('robot-payment.creditcard.ok'); + } + + + private function クレジット支払結果登録(CreditcardAutoPaymentInfo $info) + { + $param = $this->param; + + $result = new CreditcardAutoPaymentResult(); + $result->creditcardAutoPaymentNo = $info->autoPaymentNo; + $result->paymentNo = $param->gid; + $result->paymentDate = DateUtil::now(); + $result->paymentResult = $this->get決済結果($param->rst); + $result->errorCode = $param->ec; + $result->paymentAmount = $info->paymentAmount; + + // 機密な情報をリクエストデータから除外して登録する + $requestArr = request()->toArray(); + unset($requestArr["token"]); + unset($requestArr["id"]); + unset($requestArr["pa"]); + $result->dataResult = json_encode( + $requestArr, + JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT + ); + + $result->save(); + } + + private function get決済結果(string $paymentResultCode): string + { + if ($paymentResultCode === "1") { + return "決済成功"; + } + if ($paymentResultCode === "2") { + return "決済失敗"; + } + if ($paymentResultCode === "3") { + return "リトライ課金失敗"; + } + if ($paymentResultCode === "4") { + return "ユーザー様による課金停止"; + } + if ($paymentResultCode === "5") { + return "お試し期間中にリトライ課金課金2回失敗"; + } + + throw new Exception("不正な決済結果コード " . $paymentResultCode); + } +} diff --git a/app/Http/Controllers/Web/RobotPayment/CreditCard/PaymentResultParam.php b/app/Http/Controllers/Web/RobotPayment/CreditCard/PaymentResultParam.php new file mode 100644 index 0000000..88460f7 --- /dev/null +++ b/app/Http/Controllers/Web/RobotPayment/CreditCard/PaymentResultParam.php @@ -0,0 +1,42 @@ + $this->str(), + 'rst' => $this->str(), + 'ap' => $this->str(), + 'ec' => $this->str(true), + 'god' => $this->str(), + 'cod' => $this->str(), + 'am' => $this->numeric(), + 'tx' => $this->numeric(true), + 'sf' => $this->numeric(true), + 'ta' => $this->numeric(true), + 'acid' => $this->str(), + 'customer_code' => $this->str(true), + 'token' => $this->str(true), + ]; + } +} diff --git a/app/Http/Controllers/Web/RobotPayment/CreditCard/RegisterTestController.php b/app/Http/Controllers/Web/RobotPayment/CreditCard/RegisterTestController.php new file mode 100644 index 0000000..fce61e6 --- /dev/null +++ b/app/Http/Controllers/Web/RobotPayment/CreditCard/RegisterTestController.php @@ -0,0 +1,34 @@ +view('robot-payment.creditcard.register'); + } +} diff --git a/app/Http/Controllers/Web/RobotPayment/CreditCard/RegisterTestParam.php b/app/Http/Controllers/Web/RobotPayment/CreditCard/RegisterTestParam.php new file mode 100644 index 0000000..c30c0be --- /dev/null +++ b/app/Http/Controllers/Web/RobotPayment/CreditCard/RegisterTestParam.php @@ -0,0 +1,13 @@ +middleware('auth:sanctum'); + } + + protected function run(Request $request): JsonResponse + { + $param = $this->param; + + $application = ChangePaymentMethodCreditcardOrderApplication::getAccess()->first( + ChangePaymentMethodCreditcardOrderApplication::getQuery() + ->where(ChangePaymentMethodCreditcardOrderApplication::FIELD_TOKEN, $param->token) + ); + + // トークン有効期限チェック + $now = DateUtil::now(); + if ($application->tokenExpiresAt !== null && $application->tokenExpiresAt->lt($now)) { + return $this->failedResponse(); + } + + $this->user = Auth::user(); + $this->customer = Customer::findByCustomerCode($this->user->kintone_customer_code); + + // 申請可能チェック + if ($this->customer->canApplyToChangePaymentMethodCreditcard() === false) { + return $this->failedResponse(); + } + + // 申請パラメーターの返却 + $ret = [ + "url" => "https://credit.j-payment.co.jp/link/creditcard", + "shop_code" => "128522", + 'customer_code' => $this->user->kintone_customer_code, + 'token' => config('custom.creditcard.token'), + 'payment_type' => "CREDITCARD", + 'job_type' => "CAPTURE", + 'tax' => "0", + 'send_fee' => "0", + 'amount' => "0", + "interval" => "4", // 毎月 + "payment_day" => "27", + "auto_amount" => $this->getAmount(), + "target_date" => $this->getTargetDate(), + "email" => $this->customer->email, + 'phone_number' => $this->customer->phoneNumber, + "order_no" => Str::uuid()->toString(), + ]; + + return $this->successResponse($ret); + } + + private function getAmount(): string + { + // 全契約を集計する + $targets = SeasonTicketContract::getAccess()->all( + SeasonTicketContract::getQuery() + ->where(SeasonTicketContract::FIELD_CUSTOMER_CODE, $this->user->kintone_customer_code) + ); + + $amount = 0; + foreach ($targets as $target) { + if ($target->isTerminated()) { + continue; + } + $plan = $target->getPlan(); + if (!$plan->canPayByCreditcard()) { + throw new AppCommonException("クレジット支払できない契約が存在"); + } + + $amount += intval($plan->amount ?? 0); + } + + return strval($amount); + } + + + private function getTargetDate(): string + { + /** + * 翌月の27日を指定する + */ + $target = DateUtil::now() + ->addMonth() + ->setDay(27); + + return $target->format("Y/m/d"); + } +} diff --git a/app/Http/Controllers/Web/RobotPayment/CreditCard/RegisterTokenCheckParam.php b/app/Http/Controllers/Web/RobotPayment/CreditCard/RegisterTokenCheckParam.php new file mode 100644 index 0000000..29f9852 --- /dev/null +++ b/app/Http/Controllers/Web/RobotPayment/CreditCard/RegisterTokenCheckParam.php @@ -0,0 +1,18 @@ + $this->str(), + ]; + } +} diff --git a/app/Http/Controllers/Web/RobotPayment/PaymentInfoIndexController.php b/app/Http/Controllers/Web/RobotPayment/PaymentInfoIndexController.php new file mode 100644 index 0000000..4921dcf --- /dev/null +++ b/app/Http/Controllers/Web/RobotPayment/PaymentInfoIndexController.php @@ -0,0 +1,34 @@ +getController($request)->entry($request); + } + + private function getController(Request $request): WebController + { + if ($request->get("payment_type") === "CREDITCARD") { + return app() + ->make(\App\Http\Controllers\Web\RobotPayment\CreditCard\PaymentInfoController::class); + } + if ($request->get('payment_type') === "BANK_CHECK") { + return app() + ->make(\App\Http\Controllers\Web\RobotPayment\BanckCheck\PaymentInfoController::class); + } + abort(403); + } +} diff --git a/app/Kintone/KintoneAccess.php b/app/Kintone/KintoneAccess.php index 40e8eab..b07d721 100644 --- a/app/Kintone/KintoneAccess.php +++ b/app/Kintone/KintoneAccess.php @@ -177,7 +177,7 @@ class KintoneAccess { $list = $this->some($query); if ($list->count() !== 1) { - throw new ModelNotFoundException(sprintf("モデル取得数エラー %s count:%d", $this->appName, $list->count())); + throw new ModelNotFoundException(sprintf("モデル取得数エラー %s count:%d queey:<%s>", $this->appName, $list->count(), $query->toQuery())); } return $list->first(); } diff --git a/app/Kintone/Models/ChangePaymentMethodCreditcardOrderApplication.php b/app/Kintone/Models/ChangePaymentMethodCreditcardOrderApplication.php new file mode 100644 index 0000000..8c32bc9 --- /dev/null +++ b/app/Kintone/Models/ChangePaymentMethodCreditcardOrderApplication.php @@ -0,0 +1,27 @@ + FieldType::SINGLE_LINE_TEXT, + self::FIELD_TOKEN_EXPIRES_AT => FieldType::DATETIME, + ]; + + protected const FIELD_NAMES = [ + ...parent::FIELD_NAMES, + ]; +} diff --git a/app/Kintone/Models/CreditcardAutoPaymentInfo.php b/app/Kintone/Models/CreditcardAutoPaymentInfo.php new file mode 100644 index 0000000..23817a3 --- /dev/null +++ b/app/Kintone/Models/CreditcardAutoPaymentInfo.php @@ -0,0 +1,48 @@ + FieldType::NUMBER, + self::FIELD_CUSTOMER_NAME => FieldType::SINGLE_LINE_TEXT, + self::FIELD_AUTO_PAYMENT_NO => FieldType::SINGLE_LINE_TEXT, + self::FIELD_SHOP_ORDER_NO => FieldType::SINGLE_LINE_TEXT, + self::FIELD_PAYMENT_INTERVAL => FieldType::DROP_DOWN, + self::FIELD_PAYMENT_AMOUNT => FieldType::NUMBER, + self::FIELD_DATA_RESULT => FieldType::MULTI_LINE_TEXT, + ]; + + protected const FIELD_NAMES = [ + ...parent::FIELD_NAMES, + ]; + + protected const RELATIONS = [ + Customer::class, + ]; +} diff --git a/app/Kintone/Models/CreditcardAutoPaymentResult.php b/app/Kintone/Models/CreditcardAutoPaymentResult.php new file mode 100644 index 0000000..f6b1489 --- /dev/null +++ b/app/Kintone/Models/CreditcardAutoPaymentResult.php @@ -0,0 +1,57 @@ + FieldType::SINGLE_LINE_TEXT, + self::FIELD_CUSTOMER_CODE => FieldType::NUMBER, + self::FIELD_CUSTOMER_NAME => FieldType::SINGLE_LINE_TEXT, + self::FIELD_PAYMENT_NO => FieldType::SINGLE_LINE_TEXT, + self::FIELD_PAYMENT_DATE => FieldType::DATE, + self::FIELD_PAYMENT_RESULT => FieldType::DROP_DOWN, + self::FIELD_ERROR_CODE => FieldType::SINGLE_LINE_TEXT, + self::FIELD_PAYMENT_AMOUNT => FieldType::NUMBER, + self::FIELD_POOL_DONE => FieldType::CHECK_BOX, + self::FIELD_DATA_RESULT => FieldType::MULTI_LINE_TEXT, + ]; + + protected const FIELD_NAMES = [ + ...parent::FIELD_NAMES, + ]; + + protected const RELATIONS = [ + CreditcardAutoPaymentInfo::class, + ]; +} diff --git a/app/Kintone/Models/Customer.php b/app/Kintone/Models/Customer.php index 0476f7c..e89ebb2 100644 --- a/app/Kintone/Models/Customer.php +++ b/app/Kintone/Models/Customer.php @@ -2,6 +2,7 @@ namespace App\Kintone\Models; +use App\Kintone\Repositories\SeasonTicketContractRepository; use Illuminate\Support\Facades\Auth; /** @@ -9,6 +10,7 @@ use Illuminate\Support\Facades\Auth; * @property int customerCode * @property string customerName * @property string customerNameKana + * @property string paymentMethod * @property string email * @property string phoneNumber * @property string zipCode @@ -24,6 +26,7 @@ class Customer extends KintoneModel const FIELD_CUSTOMER_CODE = "CustomerCode"; const FIELD_CUSTOMER_NAME = "CustomerName"; const FIELD_CUSTOMER_NAME_KANA = "顧客名カナ"; + const FIELD_PAYMENT_METHOD = "支払方法"; const FIELD_EMAIL = "メールアドレス"; const FIELD_PHONE_NUMBER = "電話番号"; const FIELD_ZIP_CODE = "契約者_郵便番号"; @@ -37,6 +40,7 @@ class Customer extends KintoneModel self::FIELD_CUSTOMER_CODE => FieldType::NUMBER, self::FIELD_CUSTOMER_NAME => FieldType::SINGLE_LINE_TEXT, self::FIELD_CUSTOMER_NAME_KANA => FieldType::SINGLE_LINE_TEXT, + self::FIELD_PAYMENT_METHOD => FieldType::SINGLE_LINE_TEXT, self::FIELD_EMAIL => FieldType::LINK, self::FIELD_PHONE_NUMBER => FieldType::LINK, self::FIELD_ZIP_CODE => FieldType::SINGLE_LINE_TEXT, @@ -57,6 +61,9 @@ class Customer extends KintoneModel self::FIELD_PHONE_NUMBER => 'phone_no', ]; + // キャッシュ + private bool|null $canPayByCreditcard = null; + public static function getSelf(): static { return static::getAccess()->find(Auth::user()->kintone_id); @@ -71,6 +78,8 @@ class Customer extends KintoneModel { return [ 'customer_name_kana_hankaku' => mb_convert_kana($this->customerNameKana, "sk"), + 'can_pay_by_creditcard' => $this->canPayByCreditcard(), + 'can_apply_to_change_payment_method_creditcard' => $this->canApplyToChangePaymentMethodCreditcard(), ]; } @@ -78,4 +87,28 @@ class Customer extends KintoneModel { return !!$this->icSeasonTicektUserId; } + + public function canPayByCreditcard(bool $refresh = false): bool + { + // キャッシュがあればそれを返却する + if (is_bool($this->canPayByCreditcard) && $refresh === false) { + return $this->canPayByCreditcard; + } + + $list = SeasonTicketContractRepository::get($this->customerCode); + foreach ($list as $ele) { + if (!$ele->plan->canPayByCreditcard()) { + $this->canPayByCreditcard = false; + return $this->canPayByCreditcard; + } + } + $this->canPayByCreditcard = true; + return $this->canPayByCreditcard; + } + + // クレジットカード登録申請可否 + public function canApplyToChangePaymentMethodCreditcard() + { + return $this->paymentMethod !== "クレジット" && $this->canPayByCreditcard(); + } } diff --git a/app/Kintone/Models/DropDown/PoolTransferHistory/TransferMethod.php b/app/Kintone/Models/DropDown/PoolTransferHistory/TransferMethod.php index 2cbd27a..e627136 100644 --- a/app/Kintone/Models/DropDown/PoolTransferHistory/TransferMethod.php +++ b/app/Kintone/Models/DropDown/PoolTransferHistory/TransferMethod.php @@ -8,4 +8,5 @@ abstract class TransferMethod const YUCHO = "ゆうちょ振込"; const CVS = "コンビニ支払"; const BANK_CHECK = "バンクチェック"; + const CREDITCARD = "クレジットカード"; } diff --git a/app/Kintone/Models/PoolTransferHistory.php b/app/Kintone/Models/PoolTransferHistory.php index 7026ddc..1a14ee6 100644 --- a/app/Kintone/Models/PoolTransferHistory.php +++ b/app/Kintone/Models/PoolTransferHistory.php @@ -20,6 +20,7 @@ use Illuminate\Support\Carbon; * @property ?int incomeYuchoTransferRecordNo * @property ?int incomeCvsPaymentRecordNo * @property ?int incomeBankCheckPaymentRecordNo + * @property ?int incomeCreditcardPaymentRecordNo * @property ?int paymentPlanRecordNo * @property ?int seasonContractRecordNo */ @@ -40,6 +41,7 @@ class PoolTransferHistory extends KintoneModel const FIELD_INCOME_YUCHO_TRANSFER_RECORD_NO = "ゆうちょ振込レコード番号"; const FIELD_INCOME_CVS_PAYMENT_RECORD_NO = "コンビニ支払レコード番号"; const FIELD_INCOME_BANK_CHECK_PAYMENT_RECORD_NO = "バンクチェック支払レコード番号"; + const FIELD_INCOME_CREDITCARD_PAYMENT_RECORD_NO = "クレジットカード支払レコード番号"; const FIELD_PAYMENT_PLAN_RECORD_NO = "入金予定結果レコード番号"; const FIELD_SEASON_CONTRACT_RECORD_NO = "車室情報管理レコード番号"; @@ -59,6 +61,7 @@ class PoolTransferHistory extends KintoneModel self::FIELD_INCOME_YUCHO_TRANSFER_RECORD_NO => FieldType::NUMBER, self::FIELD_INCOME_CVS_PAYMENT_RECORD_NO => FieldType::NUMBER, self::FIELD_INCOME_BANK_CHECK_PAYMENT_RECORD_NO => FieldType::NUMBER, + self::FIELD_INCOME_CREDITCARD_PAYMENT_RECORD_NO => FieldType::NUMBER, self::FIELD_PAYMENT_PLAN_RECORD_NO => FieldType::NUMBER, self::FIELD_SEASON_CONTRACT_RECORD_NO => FieldType::NUMBER, ]; @@ -75,5 +78,6 @@ class PoolTransferHistory extends KintoneModel Pool::class, PaymentPlan::class, BankCheckResult::class, + CreditcardAutoPaymentResult::class, ]; } diff --git a/app/Kintone/Models/SeasonTicketContractPlan.php b/app/Kintone/Models/SeasonTicketContractPlan.php index ce80819..198bf5c 100644 --- a/app/Kintone/Models/SeasonTicketContractPlan.php +++ b/app/Kintone/Models/SeasonTicketContractPlan.php @@ -12,6 +12,7 @@ use Illuminate\Support\Collection; * @property string parkingName * @property string[] sendItem * @property string vehicleType + * @property ?int amount * @property ?int taxAmount * @property ?int taxRate * @property Collection canChangePlanNameList @@ -19,6 +20,7 @@ use Illuminate\Support\Collection; * @property ?int chainGateDeposit * @property ?int cardDeposit * @property ?int totalDeposit + * @property string[] canPayByCreditcard */ class SeasonTicketContractPlan extends KintoneModel { @@ -29,12 +31,14 @@ class SeasonTicketContractPlan extends KintoneModel const FIELD_PARKING_NAME = "定期_駐車場名"; const FIELD_SEND_ITEM = "送付物"; const FIELD_VEHICLE_TYPE = "種別"; + const FIELD_AMOUNT = "契約金額"; const FIELD_TAX_AMOUNT = "内税"; const FIELD_TAX_RATE = "税率"; const FIELD_DEPOSIT = "保証金"; const FIELD_CHAIN_GATE_DEPOSIT = "チェーンゲート保証金"; const FIELD_CARD_DEPOSIT = "パスカード保証金"; const FIELD_TOTAL_DEPOSIT = "保証金合計額"; + const FIELD_CAN_PAY_BY_CREDITCARD = "クレジットカード支払許可"; const FIELD_CAN_CHANGE_PLAN_NAME_LIST = "プラン変更申請にて変更可能なプラン一覧"; const FIELD_CAN_CHANGE_PLAN_NAME_LIST_PLAN_NAME = "プラン変更申請にて変更可能なプラン一覧_定期_駐車場名_月額金額_駐車場備考_プラン_種別_支払パターン"; @@ -46,11 +50,13 @@ class SeasonTicketContractPlan extends KintoneModel self::FIELD_PARKING_NAME => FieldType::SINGLE_LINE_TEXT, self::FIELD_SEND_ITEM => FieldType::CHECK_BOX, self::FIELD_VEHICLE_TYPE => FieldType::SINGLE_LINE_TEXT, + self::FIELD_AMOUNT => FieldType::NUMBER, self::FIELD_TAX_AMOUNT => FieldType::NUMBER, self::FIELD_TAX_RATE => FieldType::NUMBER, self::FIELD_CAN_CHANGE_PLAN_NAME_LIST => FieldType::SUBTABLE, self::FIELD_DEPOSIT => FieldType::NUMBER, self::FIELD_CHAIN_GATE_DEPOSIT => FieldType::NUMBER, + self::FIELD_CAN_PAY_BY_CREDITCARD => FieldType::CHECK_BOX, self::FIELD_CARD_DEPOSIT => FieldType::NUMBER, self::FIELD_TOTAL_DEPOSIT => FieldType::NUMBER, ]; @@ -89,4 +95,8 @@ class SeasonTicketContractPlan extends KintoneModel { return $this->canChangePlanNameList->isNotEmpty(); } + public function canPayByCreditcard(): bool + { + return in_array("許可", $this->canPayByCreditcard, true); + } } diff --git a/app/Logic/GeneralApplicationManager.php b/app/Logic/GeneralApplicationManager.php index 0afb47c..f26080e 100644 --- a/app/Logic/GeneralApplicationManager.php +++ b/app/Logic/GeneralApplicationManager.php @@ -4,6 +4,7 @@ namespace App\Logic; use App\Exceptions\AppCommonException; use App\Kintone\Models\BankAccountUpdateApplication; +use App\Kintone\Models\ChangePaymentMethodCreditcardOrderApplication; use App\Kintone\Models\ChangePlanApplication; use App\Kintone\Models\Customer; use App\Kintone\Models\GeneralApplication; @@ -76,6 +77,14 @@ class GeneralApplicationManager $this->setType("プラン変更"); return; } + if ($model instanceof ParkingUseTypeChangeOrderApplication) { + $this->setType("IC定期_駐車場利用方法変更申請"); + return; + } + if ($model instanceof ChangePaymentMethodCreditcardOrderApplication) { + $this->setType("クレジット支払変更申請"); + return; + } } public function setCustomer(Customer $customer): static diff --git a/app/Logic/PoolTransferManager.php b/app/Logic/PoolTransferManager.php index 99c60f5..2d9a9a0 100644 --- a/app/Logic/PoolTransferManager.php +++ b/app/Logic/PoolTransferManager.php @@ -4,6 +4,7 @@ namespace App\Logic; use App\Exceptions\SkipException; use App\Kintone\Models\BankCheckResult; +use App\Kintone\Models\CreditcardAutoPaymentResult; use App\Kintone\Models\DropDown\PoolTransferHistory\TransferMethod; use App\Kintone\Models\DropDown\PoolTransferHistory\TransgerType; use App\Kintone\Models\Pool; @@ -19,12 +20,12 @@ use App\Util\DateUtil; class PoolTransferManager { - private SmbcPayment|SmbcAccountTransferResult|YuchoPaymentResult|BankCheckResult|null $payment = null; + private SmbcPayment|SmbcAccountTransferResult|YuchoPaymentResult|BankCheckResult|CreditcardAutoPaymentResult|null $payment = null; private Pool|null $pool = null; private PoolTransferHistory|null $history = null; - public function moveToPool(SmbcPayment|SmbcAccountTransferResult|YuchoPaymentResult|BankCheckResult $payment): Pool + public function moveToPool(SmbcPayment|SmbcAccountTransferResult|YuchoPaymentResult|BankCheckResult|CreditcardAutoPaymentResult $payment): Pool { $this->clear(); @@ -94,6 +95,10 @@ class PoolTransferManager $history->incomeMethod = TransferMethod::BANK_CHECK; $history->incomeBankCheckPaymentRecordNo = $this->payment->getRecordId(); } + if ($this->payment instanceof CreditcardAutoPaymentResult) { + $history->incomeMethod = TransferMethod::CREDITCARD; + $history->incomeCreditcardPaymentRecordNo = $this->payment->getRecordId(); + } $this->history = $history; } diff --git a/routes/api.php b/routes/api.php index d49a3bd..636f120 100644 --- a/routes/api.php +++ b/routes/api.php @@ -50,7 +50,10 @@ RouteHelper::post('/ask', App\Http\Controllers\Web\FAQ\AskController::class); RouteHelper::post('/email/change/start', App\Http\Controllers\Web\Customer\ChangeEmailStartController::class); RouteHelper::post('/email/change/verify', App\Http\Controllers\Web\Customer\ChangeEmailVerifyController::class); RouteHelper::post('/customer/update-info-order', App\Http\Controllers\Web\Customer\UpdateUserInfoOrderController::class); +RouteHelper::post('/customer/change-payment-method-creditcard-order', App\Http\Controllers\Web\Customer\ChangePaymentMethodCreditcardOrderController::class); RouteHelper::get('/customer/bank-account-register/start', App\Http\Controllers\Web\Customer\BankAccountRegisterStartController::class); RouteHelper::post('/password/setting/start', App\Http\Controllers\Web\Auth\PasswordSettingStartController::class); RouteHelper::post('/password/setting/verify', App\Http\Controllers\Web\Auth\PasswordSettingVerifyController::class); + +RouteHelper::post('/robot-payment/creditcard/token/check', App\Http\Controllers\Web\RobotPayment\CreditCard\RegisterTokenCheckController::class); diff --git a/routes/web.php b/routes/web.php index b1240b5..ccaf2a3 100644 --- a/routes/web.php +++ b/routes/web.php @@ -22,8 +22,11 @@ RouteHelper::get('/image/season-ticket-contract/{id}', App\Http\Controllers\Web\ // ロボットペイメント画面遷移 RouteHelper::get('/robot-payment/bank-check/register', App\Http\Controllers\Web\RobotPayment\BanckCheck\RegisterController::class); -// BANK CHECK WEBHOOK -RouteHelper::get('/robot-payment/bank-check/info', App\Http\Controllers\Web\RobotPayment\BanckCheck\PaymentInfoController::class); +RouteHelper::get('/robot-payment/creditcard/register/test', App\Http\Controllers\Web\RobotPayment\CreditCard\RegisterTestController::class); +// ロボットペイメント WEBHOOK 決済通知 +RouteHelper::get('/robot-payment/payment-info', App\Http\Controllers\Web\RobotPayment\PaymentInfoIndexController::class); +// ロボットペイメント WEBHOOK 自動課金通知 +RouteHelper::get('/robot-payment/creditcard/auto-payment-info', App\Http\Controllers\Web\RobotPayment\CreditCard\PaymentResultController::class); // ルーティングで適合しない場合はフロント側のRoutingにゆだねる