'대기', self::STATUS_APPROVED => '승인', self::STATUS_PAID => '지급완료', self::STATUS_CANCELLED => '취소', ]; /** * 입금 구분 라벨 */ public static array $paymentTypeLabels = [ self::PAYMENT_DEPOSIT => '계약금', self::PAYMENT_BALANCE => '잔금', ]; protected $fillable = [ 'tenant_id', 'management_id', 'payment_type', 'payment_amount', 'payment_date', 'first_payment_at', 'first_partner_paid_at', 'second_payment_at', 'second_partner_paid_at', 'first_subscription_at', 'manager_paid_at', 'base_amount', 'partner_rate', 'manager_rate', 'partner_commission', 'manager_commission', 'scheduled_payment_date', 'status', 'actual_payment_date', 'partner_id', 'manager_user_id', 'notes', 'bank_reference', 'approved_by', 'approved_at', 'referrer_partner_id', 'referrer_rate', 'referrer_commission', 'first_referrer_paid_at', 'second_referrer_paid_at', ]; protected $casts = [ 'payment_amount' => 'decimal:2', 'base_amount' => 'decimal:2', 'partner_rate' => 'decimal:2', 'manager_rate' => 'decimal:2', 'partner_commission' => 'decimal:2', 'manager_commission' => 'decimal:2', 'payment_date' => 'date', 'first_payment_at' => 'date', 'first_partner_paid_at' => 'date', 'second_payment_at' => 'date', 'second_partner_paid_at' => 'date', 'first_subscription_at' => 'date', 'manager_paid_at' => 'date', 'scheduled_payment_date' => 'date', 'actual_payment_date' => 'date', 'approved_at' => 'datetime', 'referrer_rate' => 'decimal:2', 'referrer_commission' => 'decimal:2', 'first_referrer_paid_at' => 'date', 'second_referrer_paid_at' => 'date', ]; /** * 테넌트 관계 */ public function tenant(): BelongsTo { return $this->belongsTo(Tenant::class); } /** * 영업관리 관계 */ public function management(): BelongsTo { return $this->belongsTo(SalesTenantManagement::class, 'management_id'); } /** * 영업파트너 관계 */ public function partner(): BelongsTo { return $this->belongsTo(SalesPartner::class, 'partner_id'); } /** * 매니저(사용자) 관계 */ public function manager(): BelongsTo { return $this->belongsTo(User::class, 'manager_user_id'); } /** * 상세 내역 관계 */ public function details(): HasMany { return $this->hasMany(SalesCommissionDetail::class, 'commission_id'); } /** * 유치 영업파트너 관계 */ public function referrerPartner(): BelongsTo { return $this->belongsTo(SalesPartner::class, 'referrer_partner_id'); } /** * 승인자 관계 */ public function approver(): BelongsTo { return $this->belongsTo(User::class, 'approved_by'); } /** * 상태 라벨 Accessor */ public function getStatusLabelAttribute(): string { return self::$statusLabels[$this->status] ?? $this->status; } /** * 입금 구분 라벨 Accessor */ public function getPaymentTypeLabelAttribute(): string { return self::$paymentTypeLabels[$this->payment_type] ?? $this->payment_type; } /** * 총 수당액 Accessor */ public function getTotalCommissionAttribute(): float { return $this->partner_commission + $this->manager_commission + $this->referrer_commission; } /** * 지급예정일 계산 (입금일 익월 10일) */ public static function calculateScheduledPaymentDate(Carbon $paymentDate): Carbon { return $paymentDate->copy()->addMonth()->day(10); } /** * 승인 처리 */ public function approve(int $approverId): bool { if ($this->status !== self::STATUS_PENDING) { return false; } return $this->update([ 'status' => self::STATUS_APPROVED, 'approved_by' => $approverId, 'approved_at' => now(), ]); } /** * 지급완료 처리 */ public function markAsPaid(?string $bankReference = null): bool { if ($this->status !== self::STATUS_APPROVED) { return false; } return $this->update([ 'status' => self::STATUS_PAID, 'actual_payment_date' => now()->format('Y-m-d'), 'bank_reference' => $bankReference, ]); } /** * 승인취소 처리 (approved → pending) */ public function unapprove(): bool { if ($this->status !== self::STATUS_APPROVED) { return false; } return $this->update([ 'status' => self::STATUS_PENDING, 'approved_by' => null, 'approved_at' => null, ]); } /** * 취소 처리 */ public function cancel(): bool { if ($this->status === self::STATUS_PAID) { return false; } return $this->update([ 'status' => self::STATUS_CANCELLED, ]); } /** * 대기 상태 스코프 */ public function scopePending(Builder $query): Builder { return $query->where('status', self::STATUS_PENDING); } /** * 승인완료 스코프 */ public function scopeApproved(Builder $query): Builder { return $query->where('status', self::STATUS_APPROVED); } /** * 지급완료 스코프 */ public function scopePaid(Builder $query): Builder { return $query->where('status', self::STATUS_PAID); } /** * 특정 영업파트너 스코프 */ public function scopeForPartner(Builder $query, int $partnerId): Builder { return $query->where('partner_id', $partnerId); } /** * 특정 매니저 스코프 */ public function scopeForManager(Builder $query, int $managerUserId): Builder { return $query->where('manager_user_id', $managerUserId); } /** * 특정 월 지급예정 스코프 */ public function scopeForScheduledMonth(Builder $query, int $year, int $month): Builder { return $query->whereYear('scheduled_payment_date', $year) ->whereMonth('scheduled_payment_date', $month); } /** * 특정 기간 입금 스코프 */ public function scopePaymentDateBetween(Builder $query, string $startDate, string $endDate): Builder { return $query->whereBetween('payment_date', [$startDate, $endDate]); } // ======================================== // 2단계 수당 지급 관련 메서드 // ======================================== /** * 1차 납입완료 처리 */ public function recordFirstPayment(?Carbon $paymentDate = null): bool { return $this->update([ 'first_payment_at' => $paymentDate ?? now(), ]); } /** * 1차 파트너 수당 지급 처리 */ public function recordFirstPartnerPaid(?Carbon $paidDate = null): bool { if (!$this->first_payment_at) { return false; // 1차 납입이 먼저 완료되어야 함 } return $this->update([ 'first_partner_paid_at' => $paidDate ?? now(), ]); } /** * 2차 납입완료 처리 */ public function recordSecondPayment(?Carbon $paymentDate = null): bool { return $this->update([ 'second_payment_at' => $paymentDate ?? now(), ]); } /** * 2차 파트너 수당 지급 처리 */ public function recordSecondPartnerPaid(?Carbon $paidDate = null): bool { if (!$this->second_payment_at) { return false; // 2차 납입이 먼저 완료되어야 함 } return $this->update([ 'second_partner_paid_at' => $paidDate ?? now(), ]); } /** * 첫 구독료 입금 기록 (매니저 수당 기준) */ public function recordFirstSubscription(?Carbon $subscriptionDate = null): bool { return $this->update([ 'first_subscription_at' => $subscriptionDate ?? now(), ]); } /** * 매니저 수당 지급 처리 */ public function recordManagerPaid(?Carbon $paidDate = null): bool { if (!$this->first_subscription_at) { return false; // 첫 구독료 입금이 먼저 완료되어야 함 } return $this->update([ 'manager_paid_at' => $paidDate ?? now(), ]); } /** * 1차 파트너 수당 지급예정일 (1차 납입일 익월 10일) */ public function getFirstPartnerScheduledDateAttribute(): ?Carbon { if (!$this->first_payment_at) { return null; } return Carbon::parse($this->first_payment_at)->addMonth()->day(10); } /** * 2차 파트너 수당 지급예정일 (2차 납입일 익월 10일) */ public function getSecondPartnerScheduledDateAttribute(): ?Carbon { if (!$this->second_payment_at) { return null; } return Carbon::parse($this->second_payment_at)->addMonth()->day(10); } /** * 매니저 수당 지급예정일 (첫 구독료 입금일 익월 10일) */ public function getManagerScheduledDateAttribute(): ?Carbon { if (!$this->first_subscription_at) { return null; } return Carbon::parse($this->first_subscription_at)->addMonth()->day(10); } /** * 파트너 수당 1차 지급 완료 여부 */ public function isFirstPartnerPaid(): bool { return $this->first_partner_paid_at !== null; } /** * 파트너 수당 2차 지급 완료 여부 */ public function isSecondPartnerPaid(): bool { return $this->second_partner_paid_at !== null; } /** * 매니저 수당 지급 완료 여부 */ public function isManagerPaid(): bool { return $this->manager_paid_at !== null; } /** * 1차 유치수당 지급 처리 */ public function recordFirstReferrerPaid(?Carbon $paidDate = null): bool { if (!$this->referrer_partner_id) { return false; } return $this->update([ 'first_referrer_paid_at' => $paidDate ?? now(), ]); } /** * 2차 유치수당 지급 처리 */ public function recordSecondReferrerPaid(?Carbon $paidDate = null): bool { if (!$this->referrer_partner_id) { return false; } return $this->update([ 'second_referrer_paid_at' => $paidDate ?? now(), ]); } /** * 1차 유치수당 지급 완료 여부 */ public function isFirstReferrerPaid(): bool { return $this->first_referrer_paid_at !== null; } /** * 2차 유치수당 지급 완료 여부 */ public function isSecondReferrerPaid(): bool { return $this->second_referrer_paid_at !== null; } /** * 전체 수당 지급 완료 여부 (파트너 1차/2차 + 매니저 + 유치수당) */ public function isFullyPaid(): bool { $basePaid = $this->isFirstPartnerPaid() && $this->isSecondPartnerPaid() && $this->isManagerPaid(); if ($this->referrer_partner_id) { return $basePaid && $this->isFirstReferrerPaid() && $this->isSecondReferrerPaid(); } return $basePaid; } }