|
- <?php
-
- namespace App\Console\Commands;
-
- use App\Logic\SMS\SMSManager;
- use App\Models\Contract;
- use App\Models\ReceiptIssuingOrder;
- use App\Models\SMSSendOrder;
- use App\Models\UseByKeySummary;
- use App\Models\UseSummary;
- use App\Util\DateUtil;
- use App\Util\DBUtil;
- use Exception;
- use Illuminate\Support\Carbon;
- use Illuminate\Support\Collection;
- use Illuminate\Support\Facades\DB;
- use LogicException;
-
- class SummaryUse extends BaseCommand
- {
-
- const COMMAND = "summary:use {--contractId=} {--yyyymm=}";
-
- /**
- * 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;
- }
-
-
- private string $targetYYYYMM = "";
- private ?Carbon $targetDate = null;
-
-
- /**
- * Create a new command instance.
- *
- * @return void
- */
- public function __construct(private SMSManager $manager)
- {
- parent::__construct();
- }
-
- /**
- * Execute the console command.
- *
- * @return int
- */
- public function service(): int
- {
- $this->setTargetYYYYMM();
- $this->outputInfo(sprintf("対象集計年月: %s", $this->targetYYYYMM));
-
- $db = DBUtil::instance();
- try {
- $db->beginTransaction();
- foreach ($this->getTargetContractIds() as $contractId) {
- $this->handleTarget($contractId);
- }
-
- $db->commit();
- } catch (Exception $e) {
- $db->rollBack();
- throw $e;
- }
-
-
-
- return self::RESULTCODE_SUCCESS;
- }
-
- private function handleTarget(string $contractId)
- {
- // 集計対象のモデルを取得
- $model = $this->getModel($contractId);
-
- // 集計
- $summaryByKeys = $this->summary($model);
-
- // 保存
- $this->save($model, $summaryByKeys);
- }
-
- private function getTargetContractIds(): array
- {
- if ($this->option('contractId')) {
-
- return [$this->option('contractId')];
- }
- return Contract::pluck(Contract::COL_NAME_ID)->toArray();
- }
-
- private function setTargetYYYYMM()
- {
- $yyyyMM = $this->option('yyyymm');
-
- // デフォルト判定
- if ($yyyyMM === null) {
- // デフォルトは先月とする
- $this->targetDate = DateUtil::now()->addMonth(-1)->setDay(1)->setTime(0, 0);
- $this->targetYYYYMM = $this->targetDate->format('Ym');
- return;
- }
-
- // フォーマットチェック
- if (!preg_match("/^\d{6}$/", $yyyyMM)) {
- throw new Exception('YYYYMM不正');
- }
- // 日付チェック
- $tmpDate = Carbon::createFromFormat('Ym', $yyyyMM);
- if (!$tmpDate->isValid()) {
- throw new Exception('YYYYMM 日付不正');
- }
-
- $this->targetDate = $tmpDate->setDay(1)->setTime(0, 0);;
- $this->targetYYYYMM = $this->targetDate->format('Ym');;
- }
-
- private function getModel(string $contractId): UseSummary
- {
- $model = UseSummary::whereContractId($contractId)
- ->whereSummaryYyyymm($this->targetYYYYMM)
- ->firstOrNew([
- UseSummary::COL_NAME_CONTRACT_ID => $contractId,
- UseSummary::COL_NAME_SUMMARY_YYYYMM => $this->targetYYYYMM,
- ]);
-
- $currentYYYYMM = intval(DateUtil::now()->format('Ym'));
- $targetYYYYMM = intval($this->targetYYYYMM);
- if ($targetYYYYMM < $currentYYYYMM) {
- $model->is_fixed = true;
- }
-
- return $model;
- }
-
- /**
- * Undocumented function
- *
- * @param UseSummary $model
- * @return Collection<string,UseByKeySummary>
- */
- private function summary(UseSummary $model): Collection
- {
-
- $from = $this->targetDate->clone()->setTime(0, 0);
- $to = $this->targetDate->clone()->addMonth()->setTime(0, 0);
-
- /**
- * @var Collection<string,UseByKeySummary>
- */
- $summaryByKeys = collect();
-
- $makeKey = function (?string $key1, ?string $key2) {
- return sprintf("%s-%s", $key1 ?? "NULL", $key2 ?? "NULL");
- };
-
- $targetOrders = ReceiptIssuingOrder::getBuilder()
- ->where(ReceiptIssuingOrder::COL_NAME_CONTRACT_ID, $model->contract_id)
- ->where(ReceiptIssuingOrder::COL_NAME_ORDER_DATETIME, ">=", $from)
- ->where(ReceiptIssuingOrder::COL_NAME_ORDER_DATETIME, "<", $to);
-
- // 領収証発行依頼件数の取得
- $receiptIssuingOrders = DB::table($targetOrders, 'target_orders')
- ->groupBy(
- ReceiptIssuingOrder::COL_NAME_CONTRACT_ID,
- ReceiptIssuingOrder::COL_NAME_SUMMARY_KEY1,
- ReceiptIssuingOrder::COL_NAME_SUMMARY_KEY2,
- )
- ->select([
- ReceiptIssuingOrder::COL_NAME_CONTRACT_ID,
- ReceiptIssuingOrder::COL_NAME_SUMMARY_KEY1,
- ReceiptIssuingOrder::COL_NAME_SUMMARY_KEY2,
- DB::raw(sprintf("count(*) as count")),
- ])
- ->get();
- $model->receipt_order_count = 0;
- foreach ($receiptIssuingOrders as $ele) {
-
- $key1 = data_get($ele, ReceiptIssuingOrder::COL_NAME_SUMMARY_KEY1);
- $key2 = data_get($ele, ReceiptIssuingOrder::COL_NAME_SUMMARY_KEY2);
- $count = data_get($ele, 'count');
-
- $model->receipt_order_count += $count;
-
- $key = $makeKey($key1, $key2);
-
- $summaryByKey = $this->getUseByKeyModel($model, $key1, $key2);
-
- $summaryByKeys->put($key, $summaryByKey);
- }
-
- // SMS送信実績の取得
- $SMSs = SMSSendOrder::getBuilder()
- ->where(SMSSendOrder::COL_NAME_CONTRACT_ID, $model->contract_id)
- ->whereNotNull(SMSSendOrder::COL_NAME_SEND_DATETIME)
- ->where(SMSSendOrder::COL_NAME_SEND_DATETIME, ">=", $from)
- ->where(SMSSendOrder::COL_NAME_SEND_DATETIME, "<", $to)
- ->where(SMSSendOrder::COL_NAME_DONE, true)
- ->groupBy(
- ReceiptIssuingOrder::COL_NAME_CONTRACT_ID,
- ReceiptIssuingOrder::COL_NAME_SUMMARY_KEY1,
- ReceiptIssuingOrder::COL_NAME_SUMMARY_KEY2
- )
- ->select([
- ReceiptIssuingOrder::COL_NAME_CONTRACT_ID,
- ReceiptIssuingOrder::COL_NAME_SUMMARY_KEY1,
- ReceiptIssuingOrder::COL_NAME_SUMMARY_KEY2,
- DB::raw(sprintf("count(*) as count")),
- DB::raw(sprintf("sum(%s) as cost", SMSSendOrder::COL_NAME_COST)),
- ])
- ->get();
-
- $model->sms_send_count = 0;
- $model->sms_send_cost = 0;
- foreach ($SMSs as $ele) {
- $key1 = data_get($ele, SMSSendOrder::COL_NAME_SUMMARY_KEY1);
- $key2 = data_get($ele, SMSSendOrder::COL_NAME_SUMMARY_KEY2);
- $count = data_get($ele, 'count');
- $cost = data_get($ele, 'cost');
-
- $model->sms_send_count += $count;
- $model->sms_send_cost += $cost;
-
- $key = $makeKey($key1, $key2);
-
-
- $summaryByKey = $summaryByKeys->get($key);
- if (!$summaryByKey instanceof UseByKeySummary) {
- $summaryByKey = $this->getUseByKeyModel($model, $key1, $key2);
- $summaryByKeys->put($key, $summaryByKey);
- }
-
- $summaryByKey->fill([
- UseByKeySummary::COL_NAME_SMS_SEND_COUNT => $count,
- UseByKeySummary::COL_NAME_SMS_SEND_COST => $cost,
- ]);
- }
-
- return $summaryByKeys;
- }
-
-
- /**
- * @param UseSummary $model
- * @param Collection<UseByKeySummary> $summaryByKeys
- * @return void
- */
- private function save(UseSummary $model, Collection $summaryByKeys)
- {
-
-
- $contract = $model->contract;
-
- if (!$contract) {
- throw new Exception("契約不正");
- }
-
- $this->outputInfo(
- sprintf(
- "集計完了:%s 領収証発行依頼:%d件 SMS送信件数:%d件 SMSコスト:%d円",
- $contract->name,
- $model->receipt_order_count,
- $model->sms_send_count,
- $model->sms_send_cost,
- )
- );
-
-
- $model->save();
-
- $deleteTargets = UseByKeySummary::whereContractId($model->contract_id)
- ->whereSummaryYyyymm($this->targetYYYYMM)
- ->get();
-
-
- foreach ($summaryByKeys as $summary) {
-
- if (!($summary instanceof UseByKeySummary)) {
- throw new LogicException("モデル不正");
- }
-
- $summary->save();
-
- $deleteTargets = $deleteTargets->reject(function ($ele) use ($summary) {
- return $ele->summary_key1 === $summary->summary_key1 && $ele->summary_key2 === $summary->summary_key2;
- });
- }
-
- foreach ($deleteTargets as $ele) {
- $ele->delete();
- }
- }
-
- private function getUseByKeyModel(UseSummary $model, ?string $key1, ?string $key2): UseByKeySummary
- {
-
- $query = UseByKeySummary::whereContractId($model->contract_id)
- ->whereSummaryYyyymm($this->targetYYYYMM);
- if ($key1 === null) {
- $query->whereNull(UseByKeySummary::COL_NAME_SUMMARY_KEY1);
- } else {
- $query->whereSummaryKey1($key1);
- }
-
- if ($key2 === null) {
- $query->whereNull(UseByKeySummary::COL_NAME_SUMMARY_KEY2);
- } else {
- $query->whereSummaryKey2($key2);
- }
-
-
- $summary = $query->firstOrNew([
- UseByKeySummary::COL_NAME_CONTRACT_ID => $model->contract_id,
- UseByKeySummary::COL_NAME_SUMMARY_YYYYMM => $this->targetYYYYMM,
- UseByKeySummary::COL_NAME_SUMMARY_KEY1 => $key1,
- UseByKeySummary::COL_NAME_SUMMARY_KEY2 => $key2,
- ]);
-
- $currentYYYYMM = intval(DateUtil::now()->format('Ym'));
- $targetYYYYMM = intval($this->targetYYYYMM);
- if ($targetYYYYMM < $currentYYYYMM) {
- $summary->is_fixed = true;
- }
-
- return $summary;
- }
- }
|