| @@ -74,6 +74,7 @@ class FillPaymentPlan extends BaseCommand | |||
| // プランの取得 | |||
| $plans = $this->getPlans(); | |||
| foreach ($plans as $plan) { | |||
| // 契約の取得 | |||
| @@ -0,0 +1,129 @@ | |||
| <?php | |||
| namespace App\Console\Commands\PoolTransfer; | |||
| use App\Console\Commands\BaseCommand; | |||
| use App\Email\Members\EntryPaymentComplete; | |||
| use App\Exceptions\SkipException; | |||
| use App\Kintone\KintoneRecordQueryOperator; | |||
| use App\Kintone\Models\PaymentPlan; | |||
| use App\Kintone\Models\Pool; | |||
| use App\Kintone\Models\SeasonTicketContractEntry; | |||
| use App\Logic\EmailManager; | |||
| use App\Logic\PoolAttachManager; | |||
| class AttachToPaymentPlan extends BaseCommand | |||
| { | |||
| const COMMAND = "pool-transfer:attach-to-payment-plan"; | |||
| /** | |||
| * The name and signature of the console command. | |||
| * | |||
| * @var string | |||
| */ | |||
| protected $signature = self::COMMAND; | |||
| /** | |||
| * The console command description. | |||
| * | |||
| * @var string | |||
| */ | |||
| protected $description = '入金予定実績へ充当する'; | |||
| static public function getCommand() | |||
| { | |||
| return self::COMMAND; | |||
| } | |||
| /** | |||
| * Create a new command instance. | |||
| * | |||
| * @return void | |||
| */ | |||
| public function __construct() | |||
| { | |||
| parent::__construct(); | |||
| } | |||
| /** | |||
| * Execute the console command. | |||
| * | |||
| * @return int | |||
| */ | |||
| public function service(): int | |||
| { | |||
| $targets = $this->getTargets(); | |||
| $this->outputInfo(sprintf("総件数:%d件", $targets->count())); | |||
| foreach ($targets as $index => $target) { | |||
| // 100件ごとに経過を出力 | |||
| if ($index % 100 === 0) { | |||
| $this->outputInfo(sprintf("処理中:%d件目", $index + 1)); | |||
| } | |||
| try { | |||
| $this->handleData($target); | |||
| } catch (SkipException $e) { | |||
| $this->outputWarn($e->getMessage()); | |||
| } | |||
| } | |||
| return self::RESULTCODE_SUCCESS; | |||
| } | |||
| public function handleData(Pool $pool) | |||
| { | |||
| $manager = new PoolAttachManager(); | |||
| $manager->attach($pool) | |||
| ->save(); | |||
| // 初回振り込み完了処理 | |||
| if ($manager->getFirstPaymnetEntryRecordIds()->isNotEmpty()) { | |||
| foreach ($manager->getFirstPaymnetEntryRecordIds() as $entryRecordId) { | |||
| $this->handleFirstPaymentDone($entryRecordId); | |||
| } | |||
| } | |||
| } | |||
| public function handleFirstPaymentDone(int $entryRecordNo) | |||
| { | |||
| // 未払いチェック | |||
| $query = PaymentPlan::getQuery()->where(PaymentPlan::FIELD_FIRST_PAYMENT_ENTRY_RECORD_NO, $entryRecordNo); | |||
| $plans = PaymentPlan::getAccess()->all($query); | |||
| if ($plans->isEmpty()) { | |||
| return; | |||
| } | |||
| // 未払い検索 | |||
| $未払い = $plans->first((function (PaymentPlan $plan) { | |||
| return !$plan->appropriationDate || $plan->appropriationAmount !== $plan->paymentPlanAmount; | |||
| })); | |||
| if ($未払い) { | |||
| return; | |||
| } | |||
| // 承認メール送信 | |||
| $entry = SeasonTicketContractEntry::find($entryRecordNo); | |||
| $parking = $entry->getParking(); | |||
| $plan = $entry->getPlan(); | |||
| $email = new EntryPaymentComplete($parking, $entry, $plan); | |||
| (new EmailManager($email))->confirm(); | |||
| } | |||
| public function getTargets() | |||
| { | |||
| $query = Pool::getQuery()->where(Pool::FIELD_POOL_AMOUNT, 0, KintoneRecordQueryOperator::GT); | |||
| $ret = Pool::getAccess()->all($query); | |||
| return $ret; | |||
| } | |||
| } | |||
| @@ -0,0 +1,124 @@ | |||
| <?php | |||
| namespace App\Console\Commands\PoolTransfer; | |||
| use App\Console\Commands\BaseCommand; | |||
| use App\Exceptions\SkipException; | |||
| use App\Kintone\KintoneRecordQueryOperator; | |||
| use App\Kintone\Models\DropDown\SmbcPayment\SmbcPaymentStatus; | |||
| use App\Kintone\Models\SmbcAccountTransferResult; | |||
| use App\Kintone\Models\SmbcPayment; | |||
| use App\Kintone\Models\YuchoPaymentResult; | |||
| use App\Logic\PoolTransferManager; | |||
| use App\Util\CollectionUtil; | |||
| use Illuminate\Support\Collection; | |||
| class MoveToPool extends BaseCommand | |||
| { | |||
| const COMMAND = "pool-transfer:move-to-pool"; | |||
| /** | |||
| * The name and signature of the console command. | |||
| * | |||
| * @var string | |||
| */ | |||
| protected $signature = self::COMMAND; | |||
| /** | |||
| * The console command description. | |||
| * | |||
| * @var string | |||
| */ | |||
| protected $description = '入金プールへ異動する'; | |||
| static public function getCommand() | |||
| { | |||
| return self::COMMAND; | |||
| } | |||
| /** | |||
| * Create a new command instance. | |||
| * | |||
| * @return void | |||
| */ | |||
| public function __construct() | |||
| { | |||
| parent::__construct(); | |||
| } | |||
| /** | |||
| * Execute the console command. | |||
| * | |||
| * @return int | |||
| */ | |||
| public function service(): int | |||
| { | |||
| $targets = $this->getTargets(); | |||
| $this->outputInfo(sprintf("総件数:%d件", $targets->count())); | |||
| foreach ($targets as $target) { | |||
| try { | |||
| $this->handleData($target); | |||
| } catch (SkipException $e) { | |||
| $this->outputWarn($e->getMessage()); | |||
| } | |||
| } | |||
| return self::RESULTCODE_SUCCESS; | |||
| } | |||
| public function handleData(YuchoPaymentResult|SmbcPayment|SmbcAccountTransferResult $payment) | |||
| { | |||
| $manager = new PoolTransferManager(); | |||
| $manager->moveToPool($payment); | |||
| } | |||
| /** | |||
| * @return Collection<int ,YuchoPaymentResult|SmbcPayment|SmbcAccountTransferResult> | |||
| */ | |||
| public function getTargets() | |||
| { | |||
| /** | |||
| * @var Collection<int ,YuchoPaymentResult|SmbcPayment|SmbcAccountTransferResult> | |||
| */ | |||
| $ret = collect(); | |||
| // ゆうちょ振込 | |||
| $query = YuchoPaymentResult::getQuery()->whereNotIn(YuchoPaymentResult::FIELD_POOL_DONE, ["済"]) | |||
| ->whereNotNull(YuchoPaymentResult::FIELD_CUSTOMER_CODE) | |||
| ->where(YuchoPaymentResult::FIELD_PAYMENT_AMOUNT, 0, KintoneRecordQueryOperator::GT); | |||
| $targets = YuchoPaymentResult::getAccess()->all($query); | |||
| $ret->concat($targets); | |||
| CollectionUtil::pushAll($ret, $targets); | |||
| $this->outputInfo(sprintf("ゆうちょ件数:%d件", $targets->count())); | |||
| // コンビニ支払 | |||
| $query = SmbcPayment::getQuery()->whereNotIn(SmbcPayment::FIELD_POOL_DONE, ["済"]) | |||
| ->whereNotNull(SmbcPayment::FIELD_CUSTOMER_CODE) | |||
| ->where(SmbcPayment::FIELD_PAYMENT_AMOUNT, 0, KintoneRecordQueryOperator::GT) | |||
| ->whereIn(SmbcPayment::FIELD_STATUS, [SmbcPaymentStatus::S002_決済結果待ち]); | |||
| $targets = SmbcPayment::getAccess()->all($query); | |||
| CollectionUtil::pushAll($ret, $targets); | |||
| $this->outputInfo(sprintf("コンビニ支払:%d件", $targets->count())); | |||
| // 口座振替 | |||
| $query = SmbcAccountTransferResult::getQuery()->whereNotIn(SmbcAccountTransferResult::FIELD_POOL_DONE, ["済"]) | |||
| ->whereNotNull(SmbcAccountTransferResult::FIELD_CUSTOMER_CODE) | |||
| ->where(SmbcAccountTransferResult::FIELD_PAYMENT_AMOUNT, 0, KintoneRecordQueryOperator::GT); | |||
| $targets = SmbcAccountTransferResult::getAccess()->all($query); | |||
| CollectionUtil::pushAll($ret, $targets); | |||
| $this->outputInfo(sprintf("口座振替:%d件", $targets->count())); | |||
| return $ret; | |||
| } | |||
| } | |||
| @@ -18,6 +18,7 @@ class Kernel extends ConsoleKernel | |||
| Schedules\BankAccountRegisterRemaind::register($schedule); | |||
| Schedules\SeasonTikcetContractSelectionSetResult::register($schedule); | |||
| Schedules\SeasonTicketContractTerminateComplete::register($schedule); | |||
| Schedules\PoolTransfer::register($schedule); | |||
| } | |||
| /** | |||
| @@ -0,0 +1,22 @@ | |||
| <?php | |||
| namespace App\Console\Schedules; | |||
| use App\Console\Commands\PoolTransfer\MoveToPool; | |||
| use App\Console\Commands\PoolTransfer\AttachToPaymentPlan; | |||
| use Illuminate\Console\Scheduling\Schedule; | |||
| use Illuminate\Support\Facades\Artisan; | |||
| class PoolTransfer extends BaseSchedule | |||
| { | |||
| static public function register(Schedule $schedule) | |||
| { | |||
| $schedule->command(MoveToPool::class) | |||
| ->twiceDaily(10, 16) | |||
| ->description("プール金異動") | |||
| ->onSuccess(function () { | |||
| Artisan::call(AttachToPaymentPlan::class); | |||
| }); | |||
| } | |||
| } | |||
| @@ -11,7 +11,7 @@ class SMBCBankAccountRegisterPoll extends BaseSchedule | |||
| static public function register(Schedule $schedule) | |||
| { | |||
| $schedule->command(Command::class) | |||
| ->everyThreeMinutes() | |||
| ->everyOddHour() | |||
| ->unlessBetween('1:00', '6:00') | |||
| ->description("SMBC口座振替申請結果取得"); | |||
| } | |||
| @@ -11,8 +11,8 @@ class SMBCPaymentPoll extends BaseSchedule | |||
| static public function register(Schedule $schedule) | |||
| { | |||
| $schedule->command(Command::class) | |||
| ->everyTwoHours() | |||
| ->twiceDailyAt(9, 15, 30) | |||
| ->unlessBetween('1:00', '6:00') | |||
| ->description("SMBC支払結果取得"); | |||
| ->description("SMBC支払結果取得(コンビニ)"); | |||
| } | |||
| } | |||
| @@ -43,7 +43,6 @@ class EntryPaymentComplete extends Members | |||
| 'use_start_date' => $entry->useStartDate ? $entry->useStartDate->format('Y/m/d') : "-", | |||
| 'payment_method' => $entry->paymentMethod ?? "-", | |||
| 'amount' => number_format($entry->amount ?? 0), | |||
| 'paymentExplain' => EntryMessageBuilder::getPaymentExplainStr($this->entry), | |||
| 'taxExplain' => EntryMessageBuilder::getTaxExplain($this->plan), | |||
| 'can_terminate_15' => in_array(Parking::ELEMENT_CAN_TERMINATE_DATE_15, $this->parking->canTerminateDate), | |||
| 'can_terminate_end_of_month' => in_array(Parking::ELEMENT_CAN_TERMINATE_DATE_END_OF_MONTH, $this->parking->canTerminateDate), | |||
| @@ -0,0 +1,9 @@ | |||
| <?php | |||
| namespace App\Exceptions; | |||
| use Exception; | |||
| class SkipException extends Exception | |||
| { | |||
| } | |||
| @@ -0,0 +1,10 @@ | |||
| <?php | |||
| namespace App\Kintone\Models\DropDown\PoolTransferHistory; | |||
| abstract class TransferMethod | |||
| { | |||
| const ACCOUNT_TRANSFER = "口座振替"; | |||
| const YUCHO = "ゆうちょ振込"; | |||
| const CVS = "コンビニ支払"; | |||
| } | |||
| @@ -0,0 +1,9 @@ | |||
| <?php | |||
| namespace App\Kintone\Models\DropDown\PoolTransferHistory; | |||
| abstract class TransgerType | |||
| { | |||
| const INCOME = "入金"; | |||
| const ATTACH = "充当"; | |||
| } | |||
| @@ -453,6 +453,10 @@ abstract class KintoneModel | |||
| public function save() | |||
| { | |||
| if (count($this->changed) === 0) { | |||
| return; | |||
| } | |||
| $access = static::getAccess(); | |||
| if ($this->recordId === null) { | |||
| $access->create($this); | |||
| @@ -23,7 +23,9 @@ use Illuminate\Support\Collection; | |||
| * @property Carbon appropriationDate | |||
| * @property int appropriationAmount | |||
| * @property int remainingAmount | |||
| * @property int firstPaymentEntryRecordNo | |||
| * @property Collection<int ,Deposit> depositList | |||
| * @property string[] partialFee | |||
| */ | |||
| class PaymentPlan extends KintoneModel | |||
| { | |||
| @@ -42,9 +44,11 @@ class PaymentPlan extends KintoneModel | |||
| const FIELD_APPROPRIATION_DATE = "appropriation_date"; | |||
| const FIELD_APPROPRIATION_AMOUNT = "appropriation_amount"; | |||
| const FIELD_REMAINING_AMOUNT = "remaining_amount"; | |||
| const FIELD_FIRST_PAYMENT_ENTRY_RECORD_NO = "first_payment_entry_record_no"; | |||
| const FIELD_DEPOSIT_LIST = "保証金明細"; | |||
| const FIELD_DEPOSIT_LIST_NAME = "保証金明細_名称"; | |||
| const FIELD_DEPOSIT_LIST_AMOUNT = "保証金明細_金額"; | |||
| const FIELD_PARTIAL_FEE = "定期料金日割り分"; | |||
| protected const FIELDS = [ | |||
| ...parent::FIELDS, | |||
| @@ -61,7 +65,9 @@ class PaymentPlan extends KintoneModel | |||
| self::FIELD_APPROPRIATION_DATE => FieldType::DATE, | |||
| self::FIELD_APPROPRIATION_AMOUNT => FieldType::NUMBER, | |||
| self::FIELD_REMAINING_AMOUNT => FieldType::NUMBER, | |||
| self::FIELD_FIRST_PAYMENT_ENTRY_RECORD_NO => FieldType::NUMBER, | |||
| self::FIELD_DEPOSIT_LIST => FieldType::SUBTABLE, | |||
| self::FIELD_PARTIAL_FEE => FieldType::CHECK_BOX, | |||
| ]; | |||
| protected const SUB_TABLES = [ | |||
| @@ -87,14 +93,37 @@ class PaymentPlan extends KintoneModel | |||
| ]; | |||
| } | |||
| /** | |||
| * 支払い済みか判定 | |||
| * | |||
| * @return boolean | |||
| */ | |||
| public function donePayment(): bool | |||
| { | |||
| $paymentDate = $this->getDate(self::FIELD_APPROPRIATION_DATE); | |||
| $remainingAmount = $this->getNumber(self::FIELD_REMAINING_AMOUNT); | |||
| $paymentPlanAmount = $this->getNumber(self::FIELD_PAYMENT_PLAN_AMOUNT); | |||
| $paymentAmount = $this->getNumber(self::FIELD_APPROPRIATION_AMOUNT); | |||
| return !!$paymentDate && $remainingAmount === 0; | |||
| return !!$paymentDate && $remainingAmount === 0 && $paymentPlanAmount === $paymentAmount; | |||
| } | |||
| /** | |||
| * 日割り分の請求データか判定 | |||
| * | |||
| * @return boolean | |||
| */ | |||
| public function isPartialFee(): bool | |||
| { | |||
| $target = $this->partialFee; | |||
| if (is_array($target) && !!count($target)) { | |||
| return true; | |||
| } | |||
| return false; | |||
| } | |||
| private function getViewName(): string | |||
| { | |||
| @@ -0,0 +1,36 @@ | |||
| <?php | |||
| namespace App\Kintone\Models; | |||
| use Illuminate\Support\Carbon; | |||
| /** | |||
| * アプリ名 入金プール | |||
| * | |||
| * @property int customerCode | |||
| * @property string customerName | |||
| * @property int poolAmount | |||
| */ | |||
| class Pool extends KintoneModel | |||
| { | |||
| const CONFIG_KEY = "KINTONE_APP_POOL"; | |||
| const FIELD_CUSTOMER_CODE = "顧客コード"; | |||
| const FIELD_CUSTOMER_NAME = "顧客名"; | |||
| const FIELD_POOL_AMOUNT = "プール金"; | |||
| protected const FIELDS = [ | |||
| ...parent::FIELDS, | |||
| self::FIELD_CUSTOMER_CODE => FieldType::NUMBER, | |||
| self::FIELD_CUSTOMER_NAME => FieldType::SINGLE_LINE_TEXT, | |||
| self::FIELD_POOL_AMOUNT => FieldType::NUMBER, | |||
| ]; | |||
| protected const FIELD_NAMES = [ | |||
| ...parent::FIELD_NAMES, | |||
| ]; | |||
| protected const RELATIONS = [ | |||
| Customer::class, | |||
| ]; | |||
| } | |||
| @@ -0,0 +1,75 @@ | |||
| <?php | |||
| namespace App\Kintone\Models; | |||
| use Illuminate\Support\Carbon; | |||
| /** | |||
| * アプリ名 プール金・異動履歴 | |||
| * | |||
| * @property int poolRecordNo | |||
| * @property int customerCode | |||
| * @property string customerName | |||
| * @property Carbon transferDatetime | |||
| * @property string transferType | |||
| * @property int transferAmount | |||
| * @property int poolAmountBefore | |||
| * @property int poolAmountAfter | |||
| * @property ?string incomeMethod | |||
| * @property ?int incomeAccountTransferResultRecordNo | |||
| * @property ?int incomeYuchoTransferRecordNo | |||
| * @property ?int incomeCvsPaymentRecordNo | |||
| * @property ?int paymentPlanRecordNo | |||
| * @property ?int seasonContractRecordNo | |||
| */ | |||
| class PoolTransferHistory extends KintoneModel | |||
| { | |||
| const CONFIG_KEY = "KINTONE_APP_POOL_TRANSFER_HISTORY"; | |||
| const FIELD_POOL_RECORD_NO = "入金プールレコード番号"; | |||
| const FIELD_CUSTOMER_CODE = "顧客コード"; | |||
| const FIELD_CUSTOMER_NAME = "顧客名"; | |||
| const FIELD_TRANSFER_DATETIME = "異動日時"; | |||
| const FIELD_TRANSFER_TYPE = "種別"; | |||
| const FIELD_TRANSFER_AMOUNT = "異動金額"; | |||
| const FIELD_POOL_AMOUNT_BEFORE = "異動前残高"; | |||
| const FIELD_POOL_AMOUNT_AFTER = "異動後残高"; | |||
| const FIELD_INCOME_METHOD = "入金手段"; | |||
| const FIELD_INCOME_ACCOUNT_TRANSFER_RESULT_RECORD_NO = "口座振替結果レコード番号"; | |||
| const FIELD_INCOME_YUCHO_TRANSFER_RECORD_NO = "ゆうちょ振込レコード番号"; | |||
| const FIELD_INCOME_CVS_PAYMENT_RECORD_NO = "コンビニ支払レコード番号"; | |||
| const FIELD_PAYMENT_PLAN_RECORD_NO = "入金予定結果レコード番号"; | |||
| const FIELD_SEASON_CONTRACT_RECORD_NO = "車室情報管理レコード番号"; | |||
| protected const FIELDS = [ | |||
| ...parent::FIELDS, | |||
| self::FIELD_POOL_RECORD_NO => FieldType::NUMBER, | |||
| self::FIELD_CUSTOMER_CODE => FieldType::NUMBER, | |||
| self::FIELD_CUSTOMER_NAME => FieldType::SINGLE_LINE_TEXT, | |||
| self::FIELD_TRANSFER_DATETIME => FieldType::DATETIME, | |||
| self::FIELD_TRANSFER_TYPE => FieldType::DROP_DOWN, | |||
| self::FIELD_TRANSFER_AMOUNT => FieldType::NUMBER, | |||
| self::FIELD_POOL_AMOUNT_BEFORE => FieldType::NUMBER, | |||
| self::FIELD_POOL_AMOUNT_AFTER => FieldType::NUMBER, | |||
| self::FIELD_INCOME_METHOD => FieldType::SINGLE_LINE_TEXT, | |||
| self::FIELD_INCOME_ACCOUNT_TRANSFER_RESULT_RECORD_NO => FieldType::NUMBER, | |||
| self::FIELD_INCOME_YUCHO_TRANSFER_RECORD_NO => FieldType::NUMBER, | |||
| self::FIELD_INCOME_CVS_PAYMENT_RECORD_NO => FieldType::NUMBER, | |||
| self::FIELD_PAYMENT_PLAN_RECORD_NO => FieldType::NUMBER, | |||
| self::FIELD_SEASON_CONTRACT_RECORD_NO => FieldType::NUMBER, | |||
| ]; | |||
| protected const FIELD_NAMES = [ | |||
| ...parent::FIELD_NAMES, | |||
| ]; | |||
| protected const RELATIONS = [ | |||
| Customer::class, | |||
| YuchoPaymentResult::class, | |||
| SmbcPayment::class, | |||
| SmbcAccountTransferResult::class, | |||
| Pool::class, | |||
| PaymentPlan::class, | |||
| ]; | |||
| } | |||
| @@ -0,0 +1,40 @@ | |||
| <?php | |||
| namespace App\Kintone\Models; | |||
| use Illuminate\Support\Carbon; | |||
| /** | |||
| * アプリ名 SMBC口座振替結果 | |||
| * | |||
| * @property int customerCode | |||
| * @property string customerName | |||
| * @property Carbon paymentDate | |||
| * @property int paymentAmount | |||
| * @property string[] poolDone | |||
| */ | |||
| class SmbcAccountTransferResult extends KintoneModel | |||
| { | |||
| const CONFIG_KEY = "KINTONE_APP_SMBC_ACCOUNT_TRANSFER_RESULT"; | |||
| const FIELD_CUSTOMER_CODE = "顧客コード"; | |||
| const FIELD_CUSTOMER_NAME = "顧客名"; | |||
| const FIELD_PAYMENT_DATE = "引落日"; | |||
| const FIELD_PAYMENT_AMOUNT = "引落金額"; | |||
| const FIELD_POOL_DONE = "プール済み"; | |||
| const FIELD_RESULT_CODE = "結果コード"; | |||
| protected const FIELDS = [ | |||
| ...parent::FIELDS, | |||
| self::FIELD_CUSTOMER_CODE => FieldType::NUMBER, | |||
| self::FIELD_CUSTOMER_NAME => FieldType::SINGLE_LINE_TEXT, | |||
| self::FIELD_PAYMENT_DATE => FieldType::DATE, | |||
| self::FIELD_PAYMENT_AMOUNT => FieldType::NUMBER, | |||
| self::FIELD_POOL_DONE => FieldType::CHECK_BOX, | |||
| self::FIELD_RESULT_CODE => FieldType::SINGLE_LINE_TEXT, | |||
| ]; | |||
| protected const FIELD_NAMES = [ | |||
| ...parent::FIELD_NAMES, | |||
| ]; | |||
| } | |||
| @@ -12,6 +12,7 @@ use Illuminate\Support\Carbon; | |||
| * @property string orderNo | |||
| * @property int customerCode | |||
| * @property int claimAmount | |||
| * @property string[] poolDone | |||
| * @property string acceptNo | |||
| * @property string paymentStatus | |||
| * @property ?Carbon paymentStatusUpdateDatetime | |||
| @@ -30,6 +31,8 @@ class SmbcPayment extends KintoneModel | |||
| const FIELD_ORDER_NO = "請求_補助_番号"; | |||
| const FIELD_CUSTOMER_CODE = "顧客コード"; | |||
| const FIELD_CLAIM_AMOUNT = "請求金額"; | |||
| const FIELD_POOL_DONE = "プール済み"; | |||
| const FIELD_ACCEPT_NO = "決済受付番号"; | |||
| const FIELD_PAYMENT_STATUS = "決済ステータス"; | |||
| @@ -0,0 +1,38 @@ | |||
| <?php | |||
| namespace App\Kintone\Models; | |||
| use Illuminate\Support\Carbon; | |||
| /** | |||
| * アプリ名 ゆうちょ振込情報 | |||
| * | |||
| * @property int customerCode | |||
| * @property string customerName | |||
| * @property Carbon paymentDate | |||
| * @property int paymentAmount | |||
| * @property string[] poolDone | |||
| */ | |||
| class YuchoPaymentResult extends KintoneModel | |||
| { | |||
| const CONFIG_KEY = "KINTONE_APP_YUCHO_PAYMENT_RESULT"; | |||
| const FIELD_CUSTOMER_CODE = "顧客コード"; | |||
| const FIELD_CUSTOMER_NAME = "顧客名"; | |||
| const FIELD_PAYMENT_DATE = "取引日"; | |||
| const FIELD_PAYMENT_AMOUNT = "受入金額"; | |||
| const FIELD_POOL_DONE = "プール済み"; | |||
| protected const FIELDS = [ | |||
| ...parent::FIELDS, | |||
| self::FIELD_CUSTOMER_CODE => FieldType::NUMBER, | |||
| self::FIELD_CUSTOMER_NAME => FieldType::SINGLE_LINE_TEXT, | |||
| self::FIELD_PAYMENT_DATE => FieldType::DATE, | |||
| self::FIELD_PAYMENT_AMOUNT => FieldType::NUMBER, | |||
| self::FIELD_POOL_DONE => FieldType::CHECK_BOX, | |||
| ]; | |||
| protected const FIELD_NAMES = [ | |||
| ...parent::FIELD_NAMES, | |||
| ]; | |||
| } | |||
| @@ -0,0 +1,192 @@ | |||
| <?php | |||
| namespace App\Logic; | |||
| use App\Exceptions\SkipException; | |||
| use App\Kintone\KintoneRecordQuery; | |||
| use App\Kintone\Models\DropDown\PaymentPlan\PaymentType; | |||
| use App\Kintone\Models\DropDown\PoolTransferHistory\TransgerType; | |||
| use App\Kintone\Models\PaymentPlan; | |||
| use App\Kintone\Models\Pool; | |||
| use App\Kintone\Models\PoolTransferHistory; | |||
| use App\Util\DateUtil; | |||
| use Exception; | |||
| use Illuminate\Support\Collection; | |||
| /** | |||
| * 入金プールから入金予定結果へ異動する | |||
| */ | |||
| class PoolAttachManager | |||
| { | |||
| private Pool|null $pool = null; | |||
| /** | |||
| * @var Collection<int, PoolTransferHistory> | |||
| */ | |||
| private Collection $histories; | |||
| /** | |||
| * @var Collection<int, PaymentPlan> | |||
| */ | |||
| private Collection $plans; | |||
| /** | |||
| * @var Collection<int, PaymentPlan> | |||
| */ | |||
| private Collection $completePlans; | |||
| /** | |||
| * @var Collection<int, bool> | |||
| */ | |||
| private Collection $firstPaymnetEntryRecordIds; | |||
| public function attach(Pool $pool) | |||
| { | |||
| $this->clear(); | |||
| if ($pool->poolAmount === 0) { | |||
| throw new SkipException(sprintf("プール金なし 顧客コード:%d", $pool->customerCode)); | |||
| } | |||
| $this->pool = $pool; | |||
| $this->plans = $this->getPaymentPlans(); | |||
| foreach ($this->plans as $plan) { | |||
| try { | |||
| if (!$this->canAttach($plan)) { | |||
| throw new AttachStop(sprintf("残高不足のため充当途中停止 顧客コード:%d", $this->pool->customerCode)); | |||
| } | |||
| $this->makeHistory($plan); | |||
| $this->setPoolAmount($plan); | |||
| $this->setPaymentPlanDone($plan); | |||
| } catch (AttachStop $e) { | |||
| logs()->warning($e->getMessage()); | |||
| break; | |||
| } | |||
| } | |||
| return $this; | |||
| } | |||
| public function getFirstPaymnetEntryRecordIds() | |||
| { | |||
| return $this->firstPaymnetEntryRecordIds->keys(); | |||
| } | |||
| private function getPaymentPlans() | |||
| { | |||
| $query = PaymentPlan::getQuery() | |||
| ->where(PaymentPlan::FIELD_CUSTOMER_CODE, $this->pool->customerCode) | |||
| ->whereNull(PaymentPlan::FIELD_APPROPRIATION_DATE) | |||
| ->where(function (KintoneRecordQuery $q) { | |||
| $q->whereNull(PaymentPlan::FIELD_APPROPRIATION_AMOUNT) | |||
| ->orWhere(PaymentPlan::FIELD_APPROPRIATION_AMOUNT, 0); | |||
| }) | |||
| ->orderByAsc(PaymentPlan::FIELD_PAYMENT_PLAN_DATE); | |||
| $plans = PaymentPlan::getAccess()->all($query); | |||
| return $plans; | |||
| } | |||
| private function canAttach(PaymentPlan $plan) | |||
| { | |||
| $afterPool = $this->pool->poolAmount - $plan->paymentPlanAmount; | |||
| return 0 <= $afterPool; | |||
| } | |||
| private function makeHistory(PaymentPlan $plan) | |||
| { | |||
| $history = new PoolTransferHistory(); | |||
| $history->poolRecordNo = $this->pool->getRecordId(); | |||
| $history->customerCode = $this->pool->customerCode; | |||
| $history->transferDatetime = DateUtil::now(); | |||
| $history->transferType = TransgerType::ATTACH; | |||
| $history->transferAmount = $plan->paymentPlanAmount; | |||
| $history->poolAmountBefore = $this->pool->poolAmount; | |||
| $history->poolAmountAfter = $this->pool->poolAmount - $plan->paymentPlanAmount; | |||
| $history->paymentPlanRecordNo = $plan->getRecordId(); | |||
| $this->histories->push($history); | |||
| } | |||
| private function setPoolAmount(PaymentPlan $plan) | |||
| { | |||
| $afterPool = $this->pool->poolAmount - $plan->paymentPlanAmount; | |||
| $this->pool->poolAmount = $afterPool; | |||
| } | |||
| private function setPaymentPlanDone(PaymentPlan $plan) | |||
| { | |||
| $plan->appropriationDate = DateUtil::now(); | |||
| $plan->appropriationAmount = $plan->paymentPlanAmount; | |||
| $plan->remainingAmount = 0; | |||
| if (!!$plan->firstPaymentEntryRecordNo) { | |||
| $this->firstPaymnetEntryRecordIds->put($plan->firstPaymentEntryRecordNo, true); | |||
| } | |||
| $this->completePlans->push($plan); | |||
| } | |||
| public function save() | |||
| { | |||
| foreach ($this->histories as $history) { | |||
| $history->save(); | |||
| } | |||
| foreach ($this->completePlans as $plan) { | |||
| $plan->save(); | |||
| } | |||
| $this->pool->save(); | |||
| $this->makeReceipt(); | |||
| return $this; | |||
| } | |||
| private function makeReceipt() | |||
| { | |||
| if ($this->completePlans->isEmpty()) { | |||
| return; | |||
| } | |||
| // 支払い種別ごとにグルーピング | |||
| $ids = []; | |||
| foreach ($this->completePlans as $plan) { | |||
| // 保証金は領収証を発行しない | |||
| if ($plan->paymentType === PaymentType::A保証金) { | |||
| continue; | |||
| } | |||
| $ids[$plan->paymentType][] = $plan; | |||
| } | |||
| // 領収証作成 | |||
| foreach ($ids as $targets) { | |||
| $manager = new ReceiptManager(); | |||
| $manager->setPaymentPlans(collect($targets)) | |||
| ->create($targets); | |||
| } | |||
| return $this; | |||
| } | |||
| private function clear() | |||
| { | |||
| $this->pool = null; | |||
| $this->histories = collect(); | |||
| $this->firstPaymnetEntryRecordIds = collect(); | |||
| $this->plans = collect(); | |||
| $this->completePlans = collect(); | |||
| } | |||
| } | |||
| class AttachStop extends Exception | |||
| { | |||
| } | |||
| @@ -0,0 +1,119 @@ | |||
| <?php | |||
| namespace App\Logic; | |||
| use App\Exceptions\SkipException; | |||
| use App\Kintone\Models\DropDown\PoolTransferHistory\TransferMethod; | |||
| use App\Kintone\Models\DropDown\PoolTransferHistory\TransgerType; | |||
| use App\Kintone\Models\Pool; | |||
| use App\Kintone\Models\PoolTransferHistory; | |||
| use App\Kintone\Models\SmbcAccountTransferResult; | |||
| use App\Kintone\Models\SmbcPayment; | |||
| use App\Kintone\Models\YuchoPaymentResult; | |||
| use App\Util\DateUtil; | |||
| /** | |||
| * 各種支払いデータから入金プールへ異動する | |||
| */ | |||
| class PoolTransferManager | |||
| { | |||
| private SmbcPayment|SmbcAccountTransferResult|YuchoPaymentResult|null $payment = null; | |||
| private Pool|null $pool = null; | |||
| private PoolTransferHistory|null $history = null; | |||
| public function moveToPool(SmbcPayment|SmbcAccountTransferResult|YuchoPaymentResult $payment): Pool | |||
| { | |||
| $this->clear(); | |||
| if (!$payment->customerCode) { | |||
| throw new SkipException(sprintf("顧客コード未割当 レコード番号:%d", $payment->getRecordId())); | |||
| } | |||
| $this->payment = $payment; | |||
| $this->getPool(); | |||
| $this->setPoolDone(); | |||
| $this->makeHistory(); | |||
| $this->setPoolAmount(); | |||
| $this->save(); | |||
| return $this->pool; | |||
| } | |||
| private function getPool() | |||
| { | |||
| $access = Pool::getAccess(); | |||
| $query = Pool::getQuery()->where(Pool::FIELD_CUSTOMER_CODE, $this->payment->customerCode); | |||
| $list = $access->some($query); | |||
| if ($list->isNotEmpty()) { | |||
| if ($list->count() !== 1) { | |||
| throw new SkipException(sprintf("データ不正 入金プール一意制約違反 顧客コード%d", $this->payment->customerCode)); | |||
| } | |||
| $this->pool = $list->first(); | |||
| return; | |||
| } | |||
| $pool = new Pool(); | |||
| $pool->customerCode = $this->payment->customerCode; | |||
| $pool->poolAmount = 0; | |||
| $pool->save(); | |||
| $this->pool = $pool; | |||
| } | |||
| private function makeHistory() | |||
| { | |||
| $history = new PoolTransferHistory(); | |||
| $history->poolRecordNo = $this->pool->getRecordId(); | |||
| $history->customerCode = $this->payment->customerCode; | |||
| $history->transferDatetime = DateUtil::now(); | |||
| $history->transferType = TransgerType::INCOME; | |||
| $history->transferAmount = $this->payment->paymentAmount; | |||
| $history->poolAmountBefore = $this->pool->poolAmount; | |||
| $history->poolAmountAfter = $this->pool->poolAmount + $this->payment->paymentAmount; | |||
| if ($this->payment instanceof SmbcPayment) { | |||
| $history->incomeMethod = TransferMethod::CVS; | |||
| $history->incomeCvsPaymentRecordNo = $this->payment->getRecordId(); | |||
| } | |||
| if ($this->payment instanceof SmbcAccountTransferResult) { | |||
| $history->incomeMethod = TransferMethod::ACCOUNT_TRANSFER; | |||
| $history->incomeAccountTransferResultRecordNo = $this->payment->getRecordId(); | |||
| } | |||
| if ($this->payment instanceof YuchoPaymentResult) { | |||
| $history->incomeMethod = TransferMethod::YUCHO; | |||
| $history->incomeYuchoTransferRecordNo = $this->payment->getRecordId(); | |||
| } | |||
| $this->history = $history; | |||
| } | |||
| private function setPoolDone() | |||
| { | |||
| $this->payment->poolDone = ["済"]; | |||
| } | |||
| private function setPoolAmount() | |||
| { | |||
| $this->pool->poolAmount += $this->payment->paymentAmount; | |||
| } | |||
| private function save() | |||
| { | |||
| $this->history->save(); | |||
| $this->pool->save(); | |||
| $this->payment->save(); | |||
| } | |||
| private function clear() | |||
| { | |||
| $this->payment = null; | |||
| $this->pool = null; | |||
| $this->history = null; | |||
| } | |||
| } | |||
| @@ -22,6 +22,8 @@ class ReceiptManager | |||
| { | |||
| private ?Receipt $receipt = null; | |||
| private $paymentPlans = null; | |||
| public function __construct(?int $recordNo = null) | |||
| { | |||
| if ($recordNo) { | |||
| @@ -36,6 +38,12 @@ class ReceiptManager | |||
| return $this->receipt; | |||
| } | |||
| public function setPaymentPlans(Collection $paymentPlans) | |||
| { | |||
| $this->paymentPlans = $paymentPlans; | |||
| return $this; | |||
| } | |||
| public function create(array $paymentPlanRecordNoList) | |||
| { | |||
| @@ -67,7 +75,7 @@ class ReceiptManager | |||
| $detail->amount = $detail->unitPrice * $detail->quantity; | |||
| $detail->targetMonth = $payment->targetMonth ? sprintf("%d月分", $payment->targetMonth) : ""; | |||
| $detail->taxRate = config("business.taxRate.normal", 0); | |||
| $detail->memo = "memo"; | |||
| $detail->memo = $this->getMemoContents($payment); | |||
| $receipt->receiptDetail->push($detail); | |||
| $receipt->receiptTotalAmount += $payment->appropriationAmount; | |||
| } | |||
| @@ -112,6 +120,9 @@ class ReceiptManager | |||
| private function getPayments(array $paymentPlanRecordNoList) | |||
| { | |||
| if (!!$this->paymentPlans) { | |||
| return $this->paymentPlans; | |||
| } | |||
| $query = PaymentPlan::getQuery()->whereIn(PaymentPlan::FIELD_RECORD_NO, $paymentPlanRecordNoList); | |||
| $ret = PaymentPlan::getAccess()->all($query); | |||
| @@ -286,4 +297,13 @@ class ReceiptManager | |||
| } | |||
| throw new AppCommonException('申請番号取得失敗'); | |||
| } | |||
| private function getMemoContents(PaymentPlan $plan): string | |||
| { | |||
| if ($plan->isPartialFee()) { | |||
| return "日割り分"; | |||
| } | |||
| return ""; | |||
| } | |||
| } | |||
| @@ -0,0 +1,15 @@ | |||
| <?php | |||
| namespace App\Util; | |||
| use Illuminate\Support\Collection; | |||
| class CollectionUtil | |||
| { | |||
| public static function pushAll($base, $append) | |||
| { | |||
| foreach ($append as $ele) { | |||
| $base->push($ele); | |||
| } | |||
| } | |||
| } | |||
| @@ -50,6 +50,10 @@ return [ | |||
| ...App\Kintone\Models\Ask::setConfig(), | |||
| ...App\Kintone\Models\Receipt::setConfig(), | |||
| ...App\Kintone\Models\SmbcPayment::setConfig(), | |||
| ...App\Kintone\Models\SmbcAccountTransferResult::setConfig(), | |||
| ...App\Kintone\Models\YuchoPaymentResult::setConfig(), | |||
| ...App\Kintone\Models\Pool::setConfig(), | |||
| ...App\Kintone\Models\PoolTransferHistory::setConfig(), | |||
| ], | |||
| ]; | |||