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 */ private function summary(UseSummary $model): Collection { $from = $this->targetDate->clone()->setTime(0, 0); $to = $this->targetDate->clone()->addMonth()->setTime(0, 0); /** * @var Collection */ $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); $summaryByKey->receipt_order_count += $count; $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 $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; } }