feat: 영업 실적(5% 오버라이딩 적용)과 매니저 수익(오버라이딩 제외) 분리 집계 로직 구현
This commit is contained in:
@@ -44,30 +44,64 @@ try {
|
||||
|
||||
if (!$member) return null;
|
||||
|
||||
// 이 멤버의 직접 실적 가져오기 (기존 sales_record + 신규 sales_tenant_products)
|
||||
// 이 멤버의 직접 실적 가져오기
|
||||
// 1) 영업 실적 (manager_id = 본인): 영업 수당 대상 (상위 오버라이딩 O)
|
||||
// 2) 매니저 수익 (sales_manager_id = 본인): 매니저 수당 대상 (상위 오버라이딩 X)
|
||||
$sql = "
|
||||
SELECT id, customer_name as customer, contract_date as contractDate, amount
|
||||
FROM sales_record
|
||||
WHERE member_id = ? AND status = 'completed' AND contract_date BETWEEN ? AND ?
|
||||
UNION ALL
|
||||
SELECT p.id, t.tenant_name as customer, p.contract_date as contractDate, p.contract_amount as amount
|
||||
/* [Type: sales] 본인이 영업한 건 (가입비/계약금) -> 영업 수당 20%, 상위 5% */
|
||||
SELECT 'sales' as type, p.id, t.tenant_name as customer, p.contract_date as contractDate, p.contract_amount as amount, 0 as fixed_commission
|
||||
FROM sales_tenant_products p
|
||||
JOIN sales_tenants t ON p.tenant_id = t.id
|
||||
WHERE (t.sales_manager_id = ? OR (t.sales_manager_id IS NULL AND t.manager_id = ?))
|
||||
WHERE t.manager_id = ?
|
||||
AND p.contract_date BETWEEN ? AND ?
|
||||
|
||||
UNION ALL
|
||||
|
||||
/* [Type: manager] 본인이 매니징한 건 (구독료 수당) -> 매니저 수당 100%, 상위 오버라이딩 없음 */
|
||||
SELECT 'manager' as type, p.id, t.tenant_name as customer, p.contract_date as contractDate, p.contract_amount as amount, p.commission_amount as fixed_commission
|
||||
FROM sales_tenant_products p
|
||||
JOIN sales_tenants t ON p.tenant_id = t.id
|
||||
WHERE t.sales_manager_id = ?
|
||||
AND p.contract_date BETWEEN ? AND ?
|
||||
|
||||
UNION ALL
|
||||
|
||||
/* [Type: sales] 기타 영업 기록 (기존 호환) */
|
||||
SELECT 'sales' as type, id, customer_name as customer, contract_date as contractDate, amount, 0 as fixed_commission
|
||||
FROM sales_record
|
||||
WHERE member_id = ? AND status = 'completed' AND contract_date BETWEEN ? AND ?
|
||||
";
|
||||
|
||||
// 파라미터 바인딩 순서 주의: manager_id, dates, sales_manager_id, dates, member_id, dates
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$parentId, $startDate, $endDate, $parentId, $parentId, $startDate, $endDate]);
|
||||
$stmt->execute([$parentId, $startDate, $endDate, $parentId, $startDate, $endDate, $parentId, $startDate, $endDate]);
|
||||
$directContracts = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$directSales = 0;
|
||||
$rate = 0;
|
||||
if ($parentId == $targetUserId) $rate = 0.20;
|
||||
else if ($depth == 1) $rate = 0.05;
|
||||
else if ($depth == 2) $rate = 0.03;
|
||||
$directSales = 0; // 매출 합계 (영업 매출만 집계할지, 전체 매출 집계할지? 보통 매출은 다 보여줌)
|
||||
|
||||
// 수당 계산 (건별 계산 후 합산)
|
||||
$myDirectCommission = 0; // targetUserId가 이 노드(parentId)를 통해 받는 수당
|
||||
|
||||
foreach ($directContracts as &$c) {
|
||||
$c['commission'] = $c['amount'] * $rate;
|
||||
$itemComm = 0;
|
||||
if ($c['type'] === 'manager') {
|
||||
// 매니저 수당: 본인(depth=0)인 경우에만 가져감 (오버라이딩 불가)
|
||||
if ($parentId == $targetUserId) {
|
||||
$itemComm = $c['fixed_commission'];
|
||||
} else {
|
||||
$itemComm = 0;
|
||||
}
|
||||
} else {
|
||||
// 영업 수당: 본인 20%, 상위 5%, 상위2 3%
|
||||
if ($parentId == $targetUserId) $itemComm = $c['amount'] * 0.20;
|
||||
else if ($depth == 1) $itemComm = $c['amount'] * 0.05;
|
||||
else if ($depth == 2) $itemComm = $c['amount'] * 0.03;
|
||||
}
|
||||
|
||||
$c['commission'] = $itemComm; // 화면 표시용 (이 건으로 targetUserId가 번 돈)
|
||||
$myDirectCommission += $itemComm;
|
||||
|
||||
// 매출 집계는 본인이 수행한 것만 (영업이든 매니징이든 매출액 자체는 표시)
|
||||
$directSales += $c['amount'];
|
||||
}
|
||||
unset($c);
|
||||
@@ -81,8 +115,7 @@ try {
|
||||
$totalSales = $directSales;
|
||||
$totalContractCount = count($directContracts);
|
||||
|
||||
$commission = $directSales * $rate;
|
||||
$subtreeCommission = $commission;
|
||||
$subtreeCommission = $myDirectCommission; // 내 직속 수당 + 하위로부터 올라온 오버라이딩 수당 합계
|
||||
|
||||
foreach ($childrenIds as $childId) {
|
||||
$childNode = buildOrgTree($pdo, $childId, $depth + 1, $startDate, $endDate, $targetUserId);
|
||||
@@ -90,24 +123,10 @@ try {
|
||||
$children[] = $childNode;
|
||||
$totalSales += $childNode['totalSales'];
|
||||
$totalContractCount += $childNode['contractCount'];
|
||||
$subtreeCommission += $childNode['commission']; // Aggregate commissions
|
||||
$subtreeCommission += $childNode['commission']; // 하위 재귀 호출 결과(오버라이딩 된 값들) 합산
|
||||
}
|
||||
}
|
||||
|
||||
// 수당 계산 (targetUserId 기준)
|
||||
// targetUserId == parentId 이면 본인의 직접 판매 (20%)
|
||||
// targetUserId 가 parentId의 부모이면 (depth=1) 관리자 수당 (5%)
|
||||
// targetUserId 가 parentId의 조부모이면 (depth=2) 교육자 수당 (3%)
|
||||
|
||||
$commission = 0;
|
||||
if ($parentId == $targetUserId) {
|
||||
$commission = $directSales * 0.20;
|
||||
} else if ($depth == 1) {
|
||||
$commission = $directSales * 0.05;
|
||||
} else if ($depth == 2) {
|
||||
$commission = $directSales * 0.03;
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => 'node_' . $member['id'],
|
||||
'real_id' => $member['id'],
|
||||
@@ -118,8 +137,8 @@ try {
|
||||
'directSales' => $directSales,
|
||||
'totalSales' => $totalSales,
|
||||
'contractCount' => $totalContractCount,
|
||||
'directCommission' => $commission,
|
||||
'commission' => $subtreeCommission,
|
||||
'directCommission' => $myDirectCommission, // 이 노드 자체에서 발생한 targetUser의 수입
|
||||
'commission' => $subtreeCommission, // 이 노드 및 하위 전체에서 발생한 targetUser의 총 수입
|
||||
'contracts' => $directContracts,
|
||||
'children' => $children
|
||||
];
|
||||
@@ -138,46 +157,51 @@ try {
|
||||
if ($rootNode) {
|
||||
$directNode = [
|
||||
'id' => 'root-direct',
|
||||
'name' => '내 직접 판매',
|
||||
'name' => '내 직접 실적 (영업+매니징)',
|
||||
'depth' => 0,
|
||||
'role' => '판매자',
|
||||
'role' => '본인',
|
||||
'isDirect' => true,
|
||||
'totalSales' => $rootNode['directSales'],
|
||||
'contractCount' => count($rootNode['contracts']),
|
||||
'commission' => $rootNode['directSales'] * 0.20,
|
||||
'commission' => $rootNode['directCommission'],
|
||||
'contracts' => $rootNode['contracts'],
|
||||
'children' => []
|
||||
];
|
||||
|
||||
// Root node's children should include this direct node + actual children
|
||||
$actualChildren = $rootNode['children'];
|
||||
$rootNode['children'] = array_merge([$directNode], $actualChildren);
|
||||
|
||||
// Root node should keep its aggregated commission as its primary commission value
|
||||
$rootNode['isDirect'] = false;
|
||||
}
|
||||
|
||||
// 전체 누적 실적 계산 (전체 기간)
|
||||
// 전체 누적 실적 계산 (재귀) - 로직 동일하게 수정
|
||||
function calculateTotalStats($pdo, $parentId, $targetUserId, $depth) {
|
||||
$sql = "
|
||||
SELECT amount FROM sales_record WHERE member_id = ? AND status = 'completed'
|
||||
SELECT 'sales' as type, p.contract_amount as amount, 0 as fixed_commission
|
||||
FROM sales_tenant_products p JOIN sales_tenants t ON p.tenant_id = t.id WHERE t.manager_id = ?
|
||||
UNION ALL
|
||||
SELECT p.contract_amount as amount
|
||||
FROM sales_tenant_products p
|
||||
JOIN sales_tenants t ON p.tenant_id = t.id
|
||||
WHERE (t.sales_manager_id = ? OR (t.sales_manager_id IS NULL AND t.manager_id = ?))
|
||||
SELECT 'manager' as type, p.contract_amount as amount, p.commission_amount as fixed_commission
|
||||
FROM sales_tenant_products p JOIN sales_tenants t ON p.tenant_id = t.id WHERE t.sales_manager_id = ?
|
||||
UNION ALL
|
||||
SELECT 'sales' as type, amount, 0 as fixed_commission FROM sales_record WHERE member_id = ? AND status = 'completed'
|
||||
";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$parentId, $parentId, $parentId]);
|
||||
$amounts = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||
|
||||
$directSales = array_sum($amounts);
|
||||
$count = count($amounts);
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$directSales = 0;
|
||||
$count = count($rows);
|
||||
$commission = 0;
|
||||
if ($parentId == $targetUserId) $commission = $directSales * 0.20;
|
||||
else if ($depth == 1) $commission = $directSales * 0.05;
|
||||
else if ($depth == 2) $commission = $directSales * 0.03;
|
||||
|
||||
foreach ($rows as $r) {
|
||||
$directSales += $r['amount'];
|
||||
if ($r['type'] === 'manager') {
|
||||
if ($parentId == $targetUserId) $commission += $r['fixed_commission'];
|
||||
} else {
|
||||
if ($parentId == $targetUserId) $commission += $r['amount'] * 0.20;
|
||||
else if ($depth == 1) $commission += $r['amount'] * 0.05;
|
||||
else if ($depth == 2) $commission += $r['amount'] * 0.03;
|
||||
}
|
||||
}
|
||||
|
||||
$stats = [
|
||||
'totalSales' => $directSales,
|
||||
@@ -190,13 +214,15 @@ try {
|
||||
$children = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||
|
||||
foreach ($children as $childId) {
|
||||
if ($depth < 2) { // 수당은 2단계 하위까지만
|
||||
if ($depth < 2) {
|
||||
// 수당 합산은 2단계까지만 (sales 기준)
|
||||
// manager 수당은 어차피 depth > 0 이면 0이므로 합산해도 상관없음
|
||||
$childStats = calculateTotalStats($pdo, $childId, $targetUserId, $depth + 1);
|
||||
$stats['totalSales'] += $childStats['totalSales'];
|
||||
$stats['totalCommission'] += $childStats['totalCommission'];
|
||||
$stats['totalCount'] += $childStats['totalCount'];
|
||||
} else {
|
||||
// 실적만 합산
|
||||
// 3단계 이하는 매출만 합산 (오버라이딩 X)
|
||||
$childStats = calculateTotalStats($pdo, $childId, $targetUserId, $depth + 1);
|
||||
$stats['totalSales'] += $childStats['totalSales'];
|
||||
$stats['totalCount'] += $childStats['totalCount'];
|
||||
|
||||
Reference in New Issue
Block a user