715 lines
28 KiB
PHP
715 lines
28 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\Sales\SalesCommission;
|
|
use App\Models\Sales\SalesCommissionDetail;
|
|
use App\Models\Sales\SalesPartner;
|
|
use App\Models\Sales\SalesTenantManagement;
|
|
use Carbon\Carbon;
|
|
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
|
use Illuminate\Support\Collection;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class SalesCommissionService
|
|
{
|
|
/**
|
|
* 기본 수당률
|
|
*/
|
|
const DEFAULT_PARTNER_RATE = 20.00;
|
|
|
|
const DEFAULT_GROUP_RATE = 30.00; // 단체 파트너 수당률
|
|
|
|
const DEFAULT_INDIVIDUAL_REFERRER_RATE = 5.00; // 개인 유치수당률
|
|
|
|
const DEFAULT_GROUP_REFERRER_RATE = 3.00; // 단체 유치수당률
|
|
|
|
// =========================================================================
|
|
// 정산 목록 조회
|
|
// =========================================================================
|
|
|
|
/**
|
|
* 정산 목록 조회 (페이지네이션)
|
|
*/
|
|
public function getCommissions(array $filters = [], int $perPage = 20): LengthAwarePaginator
|
|
{
|
|
$query = SalesCommission::query()
|
|
->with([
|
|
'tenant', 'partner.user.parent', 'manager', 'referrerPartner.user',
|
|
'management.tenant',
|
|
'management.tenantProspect.registeredBy.parent',
|
|
'management.tenantProspect.registeredBy.salesPartner',
|
|
'management.salesPartner.user.parent', 'management.manager',
|
|
'management.contractProducts',
|
|
]);
|
|
|
|
// 상태 필터
|
|
if (! empty($filters['status'])) {
|
|
$query->where('status', $filters['status']);
|
|
}
|
|
|
|
// 입금구분 필터
|
|
if (! empty($filters['payment_type'])) {
|
|
$query->where('payment_type', $filters['payment_type']);
|
|
}
|
|
|
|
// 영업파트너 필터
|
|
if (! empty($filters['partner_id'])) {
|
|
$query->where('partner_id', $filters['partner_id']);
|
|
}
|
|
|
|
// 매니저 필터
|
|
if (! empty($filters['manager_user_id'])) {
|
|
$query->where('manager_user_id', $filters['manager_user_id']);
|
|
}
|
|
|
|
// 지급예정 기간 범위 필터
|
|
if (! empty($filters['scheduled_start_year']) && ! empty($filters['scheduled_start_month'])
|
|
&& ! empty($filters['scheduled_end_year']) && ! empty($filters['scheduled_end_month'])) {
|
|
$startDate = \Carbon\Carbon::create($filters['scheduled_start_year'], $filters['scheduled_start_month'], 1)->startOfMonth();
|
|
$endDate = \Carbon\Carbon::create($filters['scheduled_end_year'], $filters['scheduled_end_month'], 1)->endOfMonth();
|
|
$query->whereBetween('scheduled_payment_date', [$startDate, $endDate]);
|
|
}
|
|
// 지급예정 년/월 필터 (단일)
|
|
elseif (! empty($filters['scheduled_year']) && ! empty($filters['scheduled_month'])) {
|
|
$query->forScheduledMonth((int) $filters['scheduled_year'], (int) $filters['scheduled_month']);
|
|
}
|
|
|
|
// 입금일 기간 필터
|
|
if (! empty($filters['payment_start_date']) && ! empty($filters['payment_end_date'])) {
|
|
$query->paymentDateBetween($filters['payment_start_date'], $filters['payment_end_date']);
|
|
}
|
|
|
|
// 수당유형 필터
|
|
if (! empty($filters['commission_type'])) {
|
|
$commissionType = $filters['commission_type'];
|
|
if ($commissionType === 'partner') {
|
|
$query->where('partner_commission', '>', 0);
|
|
} elseif ($commissionType === 'manager') {
|
|
$query->where('manager_commission', '>', 0);
|
|
} elseif ($commissionType === 'referrer') {
|
|
$query->whereNotNull('referrer_partner_id')
|
|
->where('referrer_commission', '>', 0);
|
|
}
|
|
}
|
|
|
|
// 고객사 검색 (management → tenant 또는 tenantProspect)
|
|
if (! empty($filters['search'])) {
|
|
$search = $filters['search'];
|
|
$query->whereHas('management', function ($q) use ($search) {
|
|
$q->where(function ($sub) use ($search) {
|
|
$sub->whereHas('tenant', function ($tq) use ($search) {
|
|
$tq->where('company_name', 'like', "%{$search}%");
|
|
})->orWhereHas('tenantProspect', function ($tpq) use ($search) {
|
|
$tpq->where('company_name', 'like', "%{$search}%");
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
return $query
|
|
->orderBy('scheduled_payment_date', 'desc')
|
|
->orderBy('created_at', 'desc')
|
|
->paginate($perPage);
|
|
}
|
|
|
|
/**
|
|
* 정산 상세 조회
|
|
*/
|
|
public function getCommissionById(int $id): ?SalesCommission
|
|
{
|
|
return SalesCommission::with([
|
|
'tenant',
|
|
'partner.user',
|
|
'manager',
|
|
'management',
|
|
'details.contractProduct.product',
|
|
'approver',
|
|
])->find($id);
|
|
}
|
|
|
|
// =========================================================================
|
|
// 수당 생성 (입금 시)
|
|
// =========================================================================
|
|
|
|
/**
|
|
* 입금 등록 및 수당 생성
|
|
*/
|
|
public function createCommission(int $managementId, string $paymentType, float $paymentAmount, string $paymentDate): SalesCommission
|
|
{
|
|
return DB::transaction(function () use ($managementId, $paymentType, $paymentAmount, $paymentDate) {
|
|
$management = SalesTenantManagement::with([
|
|
'salesPartner.user.parent',
|
|
'contractProducts.product',
|
|
'tenantProspect.registeredBy.salesPartner',
|
|
])->findOrFail($managementId);
|
|
|
|
// 영업파트너 resolve (fallback: tenantProspect → registeredBy → salesPartner)
|
|
$partner = $management->salesPartner;
|
|
if (! $partner) {
|
|
$partner = $management->tenantProspect?->registeredBy?->salesPartner;
|
|
}
|
|
if (! $partner) {
|
|
throw new \Exception('영업파트너가 지정되지 않았습니다.');
|
|
}
|
|
|
|
$paymentDateCarbon = Carbon::parse($paymentDate);
|
|
|
|
// 계약 상품이 없으면 기본 계산
|
|
$contractProducts = $management->contractProducts;
|
|
$totalRegistrationFee = $contractProducts->sum('registration_fee') ?: $paymentAmount * 2;
|
|
$baseAmount = $totalRegistrationFee / 2; // 개발비의 50%
|
|
|
|
// 수당률 (단체/개인 분기 처리)
|
|
$isGroup = $partner->isGroup();
|
|
if ($isGroup) {
|
|
// 단체: 단체 30%, 유치자 3%, 매니저 0%
|
|
$partnerRate = $partner->commission_rate ?? self::DEFAULT_GROUP_RATE;
|
|
$referrerId = $partner->referrer_partner_id;
|
|
$referrerRate = $referrerId ? self::DEFAULT_GROUP_REFERRER_RATE : 0;
|
|
} else {
|
|
// 개인: 파트너 20%, 유치자(상위파트너) 5%
|
|
$partnerRate = $partner->commission_rate ?? self::DEFAULT_PARTNER_RATE;
|
|
// 협업지원금: 유치자(parent)의 SalesPartner에게 5%
|
|
$parentUser = $partner->user?->parent;
|
|
$referrerPartner = $parentUser
|
|
? SalesPartner::where('user_id', $parentUser->id)->first()
|
|
: null;
|
|
$referrerId = $referrerPartner?->id;
|
|
$referrerRate = $referrerId ? self::DEFAULT_INDIVIDUAL_REFERRER_RATE : 0;
|
|
}
|
|
|
|
// 수당 계산
|
|
$partnerCommission = $baseAmount * ($partnerRate / 100);
|
|
|
|
// 매니저 수당 = 구독료 1개월 (비율 아님)
|
|
$subscriptionFee = $contractProducts->sum('subscription_fee') ?? 0;
|
|
$managerCommission = $management->manager_user_id ? $subscriptionFee : 0;
|
|
$managerRate = 0; // 매니저는 비율 기반이 아님
|
|
|
|
$referrerCommission = ($referrerId && $referrerRate > 0)
|
|
? $baseAmount * ($referrerRate / 100)
|
|
: 0;
|
|
|
|
// 지급예정일 (익월 10일)
|
|
$scheduledPaymentDate = SalesCommission::calculateScheduledPaymentDate($paymentDateCarbon);
|
|
|
|
// 정산 생성
|
|
$commission = SalesCommission::create([
|
|
'tenant_id' => $management->tenant_id,
|
|
'management_id' => $managementId,
|
|
'payment_type' => $paymentType,
|
|
'payment_amount' => $paymentAmount,
|
|
'payment_date' => $paymentDate,
|
|
'base_amount' => $baseAmount,
|
|
'partner_rate' => $partnerRate,
|
|
'manager_rate' => $managerRate,
|
|
'partner_commission' => $partnerCommission,
|
|
'manager_commission' => $managerCommission,
|
|
'scheduled_payment_date' => $scheduledPaymentDate,
|
|
'status' => SalesCommission::STATUS_PENDING,
|
|
'partner_id' => $partner->id,
|
|
'manager_user_id' => $management->manager_user_id,
|
|
'referrer_partner_id' => $referrerId,
|
|
'referrer_rate' => $referrerRate,
|
|
'referrer_commission' => $referrerCommission,
|
|
]);
|
|
|
|
// 상품별 상세 내역 생성
|
|
foreach ($contractProducts as $contractProduct) {
|
|
$productBaseAmount = ($contractProduct->registration_fee ?? 0) / 2;
|
|
$productPartnerRate = $contractProduct->product->partner_commission ?? $partnerRate;
|
|
$productManagerRate = $contractProduct->product->manager_commission ?? $managerRate;
|
|
|
|
SalesCommissionDetail::create([
|
|
'commission_id' => $commission->id,
|
|
'contract_product_id' => $contractProduct->id,
|
|
'registration_fee' => $contractProduct->registration_fee ?? 0,
|
|
'base_amount' => $productBaseAmount,
|
|
'partner_rate' => $productPartnerRate,
|
|
'manager_rate' => $productManagerRate,
|
|
'partner_commission' => $productBaseAmount * ($productPartnerRate / 100),
|
|
'manager_commission' => $productBaseAmount * ($productManagerRate / 100),
|
|
]);
|
|
}
|
|
|
|
// management 입금 정보 업데이트
|
|
$updateData = [];
|
|
if ($paymentType === SalesCommission::PAYMENT_DEPOSIT) {
|
|
$updateData = [
|
|
'deposit_amount' => $paymentAmount,
|
|
'deposit_paid_date' => $paymentDate,
|
|
'deposit_status' => 'paid',
|
|
];
|
|
} else {
|
|
$updateData = [
|
|
'balance_amount' => $paymentAmount,
|
|
'balance_paid_date' => $paymentDate,
|
|
'balance_status' => 'paid',
|
|
];
|
|
}
|
|
|
|
// 총 개발비 업데이트
|
|
$updateData['total_registration_fee'] = $totalRegistrationFee;
|
|
$management->update($updateData);
|
|
|
|
return $commission->load(['tenant', 'partner.user', 'manager', 'details']);
|
|
});
|
|
}
|
|
|
|
// =========================================================================
|
|
// 승인/지급 처리
|
|
// =========================================================================
|
|
|
|
/**
|
|
* 승인 처리
|
|
*/
|
|
public function approve(int $commissionId, int $approverId): SalesCommission
|
|
{
|
|
$commission = SalesCommission::findOrFail($commissionId);
|
|
|
|
// 금액이 0이면 재계산하여 DB 업데이트
|
|
if ($commission->partner_commission <= 0) {
|
|
$this->recalculateCommission($commission);
|
|
}
|
|
|
|
if (! $commission->approve($approverId)) {
|
|
throw new \Exception('승인할 수 없는 상태입니다.');
|
|
}
|
|
|
|
return $commission->fresh(['tenant', 'partner.user', 'manager', 'referrerPartner.user']);
|
|
}
|
|
|
|
/**
|
|
* 일괄 승인
|
|
*/
|
|
public function bulkApprove(array $ids, int $approverId): int
|
|
{
|
|
$count = 0;
|
|
|
|
DB::transaction(function () use ($ids, $approverId, &$count) {
|
|
$commissions = SalesCommission::whereIn('id', $ids)
|
|
->where('status', SalesCommission::STATUS_PENDING)
|
|
->get();
|
|
|
|
foreach ($commissions as $commission) {
|
|
// 금액이 0이면 재계산
|
|
if ($commission->partner_commission <= 0) {
|
|
$this->recalculateCommission($commission);
|
|
}
|
|
if ($commission->approve($approverId)) {
|
|
$count++;
|
|
}
|
|
}
|
|
});
|
|
|
|
return $count;
|
|
}
|
|
|
|
/**
|
|
* 지급완료 처리
|
|
*/
|
|
public function markAsPaid(int $commissionId, ?string $bankReference = null): SalesCommission
|
|
{
|
|
$commission = SalesCommission::findOrFail($commissionId);
|
|
|
|
if (! $commission->markAsPaid($bankReference)) {
|
|
throw new \Exception('지급완료 처리할 수 없는 상태입니다.');
|
|
}
|
|
|
|
// 영업파트너 누적 수당 업데이트
|
|
$this->updatePartnerTotalCommission($commission->partner_id);
|
|
|
|
return $commission->fresh(['tenant', 'partner.user', 'manager']);
|
|
}
|
|
|
|
/**
|
|
* 일괄 지급완료
|
|
*/
|
|
public function bulkMarkAsPaid(array $ids, ?string $bankReference = null): int
|
|
{
|
|
$count = 0;
|
|
$partnerIds = [];
|
|
|
|
DB::transaction(function () use ($ids, $bankReference, &$count, &$partnerIds) {
|
|
$commissions = SalesCommission::whereIn('id', $ids)
|
|
->where('status', SalesCommission::STATUS_APPROVED)
|
|
->get();
|
|
|
|
foreach ($commissions as $commission) {
|
|
if ($commission->markAsPaid($bankReference)) {
|
|
$count++;
|
|
$partnerIds[] = $commission->partner_id;
|
|
}
|
|
}
|
|
});
|
|
|
|
// 영업파트너 누적 수당 일괄 업데이트
|
|
foreach (array_unique($partnerIds) as $partnerId) {
|
|
$this->updatePartnerTotalCommission($partnerId);
|
|
}
|
|
|
|
return $count;
|
|
}
|
|
|
|
/**
|
|
* 승인취소 처리
|
|
*/
|
|
public function unapprove(int $commissionId): SalesCommission
|
|
{
|
|
$commission = SalesCommission::findOrFail($commissionId);
|
|
|
|
if (! $commission->unapprove()) {
|
|
throw new \Exception('승인취소할 수 없는 상태입니다.');
|
|
}
|
|
|
|
return $commission->fresh(['tenant', 'partner.user', 'manager']);
|
|
}
|
|
|
|
/**
|
|
* 취소 처리
|
|
*/
|
|
public function cancel(int $commissionId): SalesCommission
|
|
{
|
|
$commission = SalesCommission::findOrFail($commissionId);
|
|
|
|
if (! $commission->cancel()) {
|
|
throw new \Exception('취소할 수 없는 상태입니다.');
|
|
}
|
|
|
|
return $commission->fresh(['tenant', 'partner.user', 'manager']);
|
|
}
|
|
|
|
// =========================================================================
|
|
// 영업파트너/매니저 대시보드용
|
|
// =========================================================================
|
|
|
|
/**
|
|
* 영업파트너 수당 요약
|
|
*/
|
|
public function getPartnerCommissionSummary(int $partnerId): array
|
|
{
|
|
$commissions = SalesCommission::forPartner($partnerId)->get();
|
|
|
|
$thisMonth = now()->format('Y-m');
|
|
$thisMonthStart = now()->startOfMonth()->format('Y-m-d');
|
|
$thisMonthEnd = now()->endOfMonth()->format('Y-m-d');
|
|
|
|
// 1차/2차 수당 상세 계산
|
|
$firstCommissionDetails = $this->calculateStageCommission($commissions, 'first');
|
|
$secondCommissionDetails = $this->calculateStageCommission($commissions, 'second');
|
|
|
|
return [
|
|
// 이번 달 지급예정 (승인 완료된 건)
|
|
'scheduled_this_month' => $commissions
|
|
->where('status', SalesCommission::STATUS_APPROVED)
|
|
->filter(fn ($c) => $c->scheduled_payment_date->format('Y-m') === $thisMonth)
|
|
->sum('partner_commission'),
|
|
|
|
// 누적 수령 수당
|
|
'total_received' => $commissions
|
|
->where('status', SalesCommission::STATUS_PAID)
|
|
->sum('partner_commission'),
|
|
|
|
// 대기중 수당
|
|
'pending_amount' => $commissions
|
|
->where('status', SalesCommission::STATUS_PENDING)
|
|
->sum('partner_commission'),
|
|
|
|
// 이번 달 신규 계약 건수
|
|
'contracts_this_month' => $commissions
|
|
->filter(fn ($c) => $c->payment_date >= $thisMonthStart && $c->payment_date <= $thisMonthEnd)
|
|
->count(),
|
|
|
|
// 1차 수당 상세
|
|
'first_commission' => $firstCommissionDetails,
|
|
|
|
// 2차 수당 상세
|
|
'second_commission' => $secondCommissionDetails,
|
|
|
|
// 총 수당 금액 (1차 + 2차)
|
|
'total_commission' => $commissions->sum('partner_commission'),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 단계별 수당 계산 (1차/2차)
|
|
* 파트너 수당의 50%씩 1차/2차로 분할
|
|
*/
|
|
private function calculateStageCommission($commissions, string $stage): array
|
|
{
|
|
$paymentAtField = $stage === 'first' ? 'first_payment_at' : 'second_payment_at';
|
|
$paidAtField = $stage === 'first' ? 'first_partner_paid_at' : 'second_partner_paid_at';
|
|
|
|
$total = 0;
|
|
$pending = 0; // 납입 대기 (입금 전)
|
|
$scheduled = 0; // 지급예정 (입금 완료, 수당 미지급)
|
|
$paid = 0; // 지급완료
|
|
|
|
foreach ($commissions as $commission) {
|
|
// 파트너 수당의 50%가 각 단계별 금액
|
|
$stageAmount = $commission->partner_commission / 2;
|
|
$total += $stageAmount;
|
|
|
|
$paymentAt = $commission->{$paymentAtField};
|
|
$paidAt = $commission->{$paidAtField};
|
|
|
|
if ($paidAt) {
|
|
// 지급완료
|
|
$paid += $stageAmount;
|
|
} elseif ($paymentAt) {
|
|
// 납입완료, 수당 지급예정
|
|
$scheduled += $stageAmount;
|
|
} else {
|
|
// 납입 대기
|
|
$pending += $stageAmount;
|
|
}
|
|
}
|
|
|
|
return [
|
|
'total' => $total,
|
|
'pending' => $pending, // 납입 대기
|
|
'scheduled' => $scheduled, // 지급예정
|
|
'paid' => $paid, // 지급완료
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 매니저 수당 요약
|
|
*/
|
|
public function getManagerCommissionSummary(int $managerUserId): array
|
|
{
|
|
$commissions = SalesCommission::forManager($managerUserId)->get();
|
|
|
|
$thisMonth = now()->format('Y-m');
|
|
|
|
return [
|
|
// 이번 달 지급예정 (승인 완료된 건)
|
|
'scheduled_this_month' => $commissions
|
|
->where('status', SalesCommission::STATUS_APPROVED)
|
|
->filter(fn ($c) => $c->scheduled_payment_date->format('Y-m') === $thisMonth)
|
|
->sum('manager_commission'),
|
|
|
|
// 누적 수령 수당
|
|
'total_received' => $commissions
|
|
->where('status', SalesCommission::STATUS_PAID)
|
|
->sum('manager_commission'),
|
|
|
|
// 대기중 수당
|
|
'pending_amount' => $commissions
|
|
->where('status', SalesCommission::STATUS_PENDING)
|
|
->sum('manager_commission'),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 최근 수당 내역 (대시보드용)
|
|
*/
|
|
public function getRecentCommissions(int $partnerId, int $limit = 5): Collection
|
|
{
|
|
return SalesCommission::forPartner($partnerId)
|
|
->with(['tenant', 'management'])
|
|
->orderBy('created_at', 'desc')
|
|
->limit($limit)
|
|
->get();
|
|
}
|
|
|
|
// =========================================================================
|
|
// 통계
|
|
// =========================================================================
|
|
|
|
/**
|
|
* 정산 통계 (본사 대시보드용)
|
|
*/
|
|
public function getSettlementStats(int $year, int $month): array
|
|
{
|
|
$commissions = SalesCommission::forScheduledMonth($year, $month)->get();
|
|
|
|
return [
|
|
// 상태별 건수 및 금액
|
|
'pending' => [
|
|
'count' => $commissions->where('status', SalesCommission::STATUS_PENDING)->count(),
|
|
'partner_total' => $commissions->where('status', SalesCommission::STATUS_PENDING)->sum('partner_commission'),
|
|
'manager_total' => $commissions->where('status', SalesCommission::STATUS_PENDING)->sum('manager_commission'),
|
|
],
|
|
'approved' => [
|
|
'count' => $commissions->where('status', SalesCommission::STATUS_APPROVED)->count(),
|
|
'partner_total' => $commissions->where('status', SalesCommission::STATUS_APPROVED)->sum('partner_commission'),
|
|
'manager_total' => $commissions->where('status', SalesCommission::STATUS_APPROVED)->sum('manager_commission'),
|
|
],
|
|
'paid' => [
|
|
'count' => $commissions->where('status', SalesCommission::STATUS_PAID)->count(),
|
|
'partner_total' => $commissions->where('status', SalesCommission::STATUS_PAID)->sum('partner_commission'),
|
|
'manager_total' => $commissions->where('status', SalesCommission::STATUS_PAID)->sum('manager_commission'),
|
|
],
|
|
|
|
// 전체 합계
|
|
'total' => [
|
|
'count' => $commissions->count(),
|
|
'base_amount' => $commissions->sum('base_amount'),
|
|
'partner_commission' => $commissions->sum('partner_commission'),
|
|
'manager_commission' => $commissions->sum('manager_commission'),
|
|
],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 정산 통계 (기간 범위)
|
|
*/
|
|
public function getSettlementStatsForRange(int $startYear, int $startMonth, int $endYear, int $endMonth): array
|
|
{
|
|
$startDate = \Carbon\Carbon::create($startYear, $startMonth, 1)->startOfMonth();
|
|
$endDate = \Carbon\Carbon::create($endYear, $endMonth, 1)->endOfMonth();
|
|
|
|
$commissions = SalesCommission::whereBetween('scheduled_payment_date', [$startDate, $endDate])->get();
|
|
|
|
return [
|
|
'pending' => [
|
|
'count' => $commissions->where('status', SalesCommission::STATUS_PENDING)->count(),
|
|
'partner_total' => $commissions->where('status', SalesCommission::STATUS_PENDING)->sum('partner_commission'),
|
|
'manager_total' => $commissions->where('status', SalesCommission::STATUS_PENDING)->sum('manager_commission'),
|
|
],
|
|
'approved' => [
|
|
'count' => $commissions->where('status', SalesCommission::STATUS_APPROVED)->count(),
|
|
'partner_total' => $commissions->where('status', SalesCommission::STATUS_APPROVED)->sum('partner_commission'),
|
|
'manager_total' => $commissions->where('status', SalesCommission::STATUS_APPROVED)->sum('manager_commission'),
|
|
],
|
|
'paid' => [
|
|
'count' => $commissions->where('status', SalesCommission::STATUS_PAID)->count(),
|
|
'partner_total' => $commissions->where('status', SalesCommission::STATUS_PAID)->sum('partner_commission'),
|
|
'manager_total' => $commissions->where('status', SalesCommission::STATUS_PAID)->sum('manager_commission'),
|
|
],
|
|
'total' => [
|
|
'count' => $commissions->count(),
|
|
'base_amount' => $commissions->sum('base_amount'),
|
|
'partner_commission' => $commissions->sum('partner_commission'),
|
|
'manager_commission' => $commissions->sum('manager_commission'),
|
|
],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 입금 대기 중인 테넌트 목록
|
|
*/
|
|
public function getPendingPaymentTenants(): Collection
|
|
{
|
|
return SalesTenantManagement::with(['tenant', 'salesPartner.user', 'manager'])
|
|
->contracted()
|
|
->where(function ($query) {
|
|
$query->where('deposit_status', 'pending')
|
|
->orWhere('balance_status', 'pending');
|
|
})
|
|
->orderBy('contracted_at', 'desc')
|
|
->get();
|
|
}
|
|
|
|
// =========================================================================
|
|
// 내부 메서드
|
|
// =========================================================================
|
|
|
|
/**
|
|
* 수당 재계산 (기존 0원 레코드 정상화)
|
|
*/
|
|
private function recalculateCommission(SalesCommission $commission): void
|
|
{
|
|
$management = SalesTenantManagement::with([
|
|
'salesPartner.user.parent',
|
|
'contractProducts.product',
|
|
'tenantProspect.registeredBy.salesPartner',
|
|
])->find($commission->management_id);
|
|
|
|
if (! $management) {
|
|
return;
|
|
}
|
|
|
|
// 파트너 resolve (fallback: tenantProspect → registeredBy → salesPartner)
|
|
$partner = $management->salesPartner;
|
|
if (! $partner) {
|
|
$partner = $management->tenantProspect?->registeredBy?->salesPartner;
|
|
}
|
|
if (! $partner) {
|
|
return;
|
|
}
|
|
|
|
$contractProducts = $management->contractProducts;
|
|
$totalRegistrationFee = $contractProducts->sum('registration_fee') ?: ($commission->payment_amount * 2);
|
|
$baseAmount = $totalRegistrationFee / 2;
|
|
|
|
$isGroup = $partner->isGroup();
|
|
|
|
// 파트너 수당
|
|
if ($isGroup) {
|
|
$partnerRate = $partner->commission_rate ?? self::DEFAULT_GROUP_RATE;
|
|
$referrerId = $partner->referrer_partner_id;
|
|
$referrerRate = $referrerId ? self::DEFAULT_GROUP_REFERRER_RATE : 0;
|
|
} else {
|
|
$partnerRate = $partner->commission_rate ?? self::DEFAULT_PARTNER_RATE;
|
|
$parentUser = $partner->user?->parent;
|
|
$referrerPartner = $parentUser
|
|
? SalesPartner::where('user_id', $parentUser->id)->first()
|
|
: null;
|
|
$referrerId = $referrerPartner?->id;
|
|
$referrerRate = $referrerId ? self::DEFAULT_INDIVIDUAL_REFERRER_RATE : 0;
|
|
}
|
|
|
|
$partnerCommission = $baseAmount * ($partnerRate / 100);
|
|
|
|
// 매니저 수당 = 구독료 1개월
|
|
$subscriptionFee = $contractProducts->sum('subscription_fee') ?? 0;
|
|
$managerCommission = $management->manager_user_id ? $subscriptionFee : 0;
|
|
|
|
// 유치수당
|
|
$referrerCommission = ($referrerId && $referrerRate > 0)
|
|
? $baseAmount * ($referrerRate / 100)
|
|
: 0;
|
|
|
|
// DB 업데이트
|
|
$updateData = [
|
|
'base_amount' => $baseAmount,
|
|
'partner_rate' => $partnerRate,
|
|
'manager_rate' => 0,
|
|
'partner_commission' => $partnerCommission,
|
|
'manager_commission' => $managerCommission,
|
|
'referrer_rate' => $referrerRate,
|
|
'referrer_commission' => $referrerCommission,
|
|
];
|
|
|
|
// partner_id가 0이면 정상 값으로 교체
|
|
if ($commission->partner_id <= 0) {
|
|
$updateData['partner_id'] = $partner->id;
|
|
}
|
|
|
|
// referrer_partner_id 설정
|
|
if ($referrerId) {
|
|
$updateData['referrer_partner_id'] = $referrerId;
|
|
}
|
|
|
|
// payment_amount가 0이면 totalRegistrationFee/2로 설정
|
|
if ($commission->payment_amount <= 0) {
|
|
$updateData['payment_amount'] = $baseAmount;
|
|
}
|
|
|
|
$commission->update($updateData);
|
|
$commission->refresh();
|
|
}
|
|
|
|
/**
|
|
* 영업파트너 누적 수당 업데이트
|
|
*/
|
|
private function updatePartnerTotalCommission(int $partnerId): void
|
|
{
|
|
$totalPaid = SalesCommission::forPartner($partnerId)
|
|
->paid()
|
|
->sum('partner_commission');
|
|
|
|
$contractCount = SalesCommission::forPartner($partnerId)
|
|
->paid()
|
|
->count();
|
|
|
|
SalesPartner::where('id', $partnerId)->update([
|
|
'total_commission' => $totalPaid,
|
|
'total_contracts' => $contractCount,
|
|
]);
|
|
}
|
|
}
|