validate([ 'member_id' => 'nullable|integer', ]); return ApiResponse::handle(function () use ($data) { return [ 'subscriptions' => $this->billingService->getSubscriptions($data['member_id'] ?? null), ]; }, __('message.fetched')); } /** * 구독 등록/수정 */ public function saveSubscription(Request $request) { $data = $request->validate([ 'member_id' => 'required|integer|exists:barobill_members,id', 'service_type' => 'required|in:bank_account,card,hometax', 'monthly_fee' => 'nullable|integer|min:0', 'started_at' => 'nullable|date', 'ended_at' => 'nullable|date|after_or_equal:started_at', 'is_active' => 'nullable|boolean', 'memo' => 'nullable|string|max:500', ]); return ApiResponse::handle(function () use ($data) { return $this->billingService->saveSubscription( $data['member_id'], $data['service_type'], $data ); }, __('message.created')); } /** * 구독 해지 */ public function cancelSubscription(int $id) { return ApiResponse::handle(function () use ($id) { $this->billingService->cancelSubscription($id); return ['cancelled' => true]; }, __('message.deleted')); } /** * 월별 과금 현황 목록 */ public function billingList(Request $request) { $data = $request->validate([ 'billing_month' => 'nullable|string|date_format:Y-m', 'tenant_id' => 'nullable|integer', ]); return ApiResponse::handle(function () use ($data) { $billingMonth = $data['billing_month'] ?? Carbon::now()->format('Y-m'); $tenantId = $data['tenant_id'] ?? null; return [ 'list' => $this->billingService->getMonthlyBillingList($billingMonth, $tenantId), 'total' => $this->billingService->getMonthlyTotal($billingMonth, $tenantId), 'billing_month' => $billingMonth, ]; }, __('message.fetched')); } /** * 월별 과금 통계 */ public function billingStats(Request $request) { $data = $request->validate([ 'billing_month' => 'nullable|string|date_format:Y-m', 'tenant_id' => 'nullable|integer', ]); return ApiResponse::handle(function () use ($data) { $billingMonth = $data['billing_month'] ?? Carbon::now()->format('Y-m'); return $this->billingService->getMonthlyTotal($billingMonth, $data['tenant_id'] ?? null); }, __('message.fetched')); } /** * 월별 과금 배치 처리 */ public function processBilling(Request $request) { $data = $request->validate([ 'billing_month' => 'nullable|string|date_format:Y-m', ]); return ApiResponse::handle(function () use ($data) { return $this->billingService->processMonthlyBilling($data['billing_month'] ?? null); }, __('message.created')); } /** * 연간 과금 추이 */ public function yearlyTrend(Request $request) { $data = $request->validate([ 'year' => 'nullable|integer|min:2020|max:2030', 'tenant_id' => 'nullable|integer', ]); return ApiResponse::handle(function () use ($data) { $year = $data['year'] ?? Carbon::now()->year; return [ 'trend' => $this->billingService->getYearlyTrend($year, $data['tenant_id'] ?? null), 'year' => $year, ]; }, __('message.fetched')); } /** * 과금 정책 목록 */ public function pricingPolicies() { return ApiResponse::handle(function () { return ['policies' => $this->billingService->getPricingPolicies()]; }, __('message.fetched')); } /** * 과금 정책 수정 */ public function updatePricingPolicy(Request $request, int $id) { $data = $request->validate([ 'name' => 'nullable|string|max:100', 'description' => 'nullable|string|max:500', 'free_quota' => 'nullable|integer|min:0', 'free_quota_unit' => 'nullable|string|max:10', 'additional_unit' => 'nullable|integer|min:1', 'additional_unit_label' => 'nullable|string|max:10', 'additional_price' => 'nullable|integer|min:0', 'is_active' => 'nullable|boolean', ]); return ApiResponse::handle(function () use ($id, $data) { return $this->billingService->updatePricingPolicy($id, $data); }, __('message.updated')); } }