211 lines
8.0 KiB
PHP
Executable File
211 lines
8.0 KiB
PHP
Executable File
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\DailySale;
|
|
use App\Models\Expense;
|
|
use App\Models\Month;
|
|
use App\Models\User;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class CommissionCalculator
|
|
{
|
|
/**
|
|
* Calcular comisión para un usuario en un mes específico
|
|
*/
|
|
public static function calculateForMonth(User $user, Month $month): array
|
|
{
|
|
// Verificar que el mes pertenece al usuario
|
|
if ($month->user_id !== $user->id) {
|
|
throw new \InvalidArgumentException('El mes no pertenece al usuario');
|
|
}
|
|
|
|
// Total de ventas del usuario
|
|
$totalUserSales = $month->dailySales()->sum('user_sales');
|
|
|
|
// Total de ventas del sistema
|
|
$totalSystemSales = $month->dailySales()->sum('system_sales');
|
|
|
|
// Total de gastos
|
|
$totalExpenses = $month->expenses()->sum('amount');
|
|
|
|
// Salario base
|
|
$monthlySalary = $user->monthly_salary;
|
|
|
|
// Porcentaje de comisión
|
|
$commissionPercentage = $user->commission_percentage;
|
|
|
|
// Calcular comisión basada en ventas del sistema (ventas consolidadas)
|
|
$commission = ($totalSystemSales * $commissionPercentage) / 100;
|
|
|
|
// Calcular percepción total (salario + comisión - gastos)
|
|
$totalEarning = $monthlySalary + $commission - $totalExpenses;
|
|
|
|
return [
|
|
'user_id' => $user->id,
|
|
'month_id' => $month->id,
|
|
'month_name' => $month->name . ' ' . $month->year,
|
|
'total_user_sales' => round($totalUserSales, 2),
|
|
'total_system_sales' => round($totalSystemSales, 2),
|
|
'total_expenses' => round($totalExpenses, 2),
|
|
'monthly_salary' => round($monthlySalary, 2),
|
|
'commission_percentage' => round($commissionPercentage, 2),
|
|
'commission_amount' => round($commission, 2),
|
|
'total_earning' => round($totalEarning, 2),
|
|
'has_difference' => ($totalUserSales !== $totalSystemSales),
|
|
'sales_difference' => round($totalUserSales - $totalSystemSales, 2),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Calcular quincena (primera o segunda)
|
|
*
|
|
* QUINCENA 1 (ANTICIPO): mitad salary + comisiones del MES completo
|
|
* QUINCENA 2 (LIQUIDACIÓN): mitad salary - gastos de la segunda quincena
|
|
*/
|
|
public static function calculateBiweekly(User $user, Month $month, int $biweekly): array
|
|
{
|
|
if ($month->user_id !== $user->id) {
|
|
throw new \InvalidArgumentException('El mes no pertenece al usuario');
|
|
}
|
|
|
|
$monthlySalary = $user->monthly_salary;
|
|
$biweeklySalary = $monthlySalary / 2; // Mitad del sueldo
|
|
$commissionPercentage = $user->commission_percentage;
|
|
|
|
// Get month number
|
|
$monthNumber = self::getMonthNumber($month->name);
|
|
$year = $month->year;
|
|
$lastDay = self::getLastDayOfMonth($month->name, $year);
|
|
|
|
if ($biweekly === 1) {
|
|
// =====================
|
|
// QUINCENA 1 - ANTICIPO
|
|
// =====================
|
|
// Anticipo = mitad del sueldo + comisiones del MES completo
|
|
$totalSystemSales = $month->dailySales()->sum('system_sales');
|
|
$commission = ($totalSystemSales * $commissionPercentage) / 100;
|
|
|
|
// Gastos: q1 completo + mensual/2
|
|
$expensesQ1Amount = $month->expenses()
|
|
->where(function($q) {
|
|
$q->where('expense_type', 'q1')
|
|
->orWhere('expense_type', 'mensual');
|
|
})
|
|
->get()
|
|
->sum(function($e) {
|
|
return $e->expense_type === 'mensual' ? $e->amount / 2 : $e->amount;
|
|
});
|
|
|
|
$totalEarning = $biweeklySalary + $commission - $expensesQ1Amount;
|
|
|
|
return [
|
|
'user_id' => $user->id,
|
|
'month_id' => $month->id,
|
|
'month_name' => $month->name . ' ' . $year,
|
|
'biweekly' => $biweekly,
|
|
'period' => '1ra Quincena (1-15) - ANTICIPO',
|
|
'description' => 'Mitad del sueldo + comisiones del mes completo',
|
|
'biweekly_salary' => round($biweeklySalary, 2),
|
|
'total_system_sales' => round($totalSystemSales, 2),
|
|
'commission_percentage' => round($commissionPercentage, 2),
|
|
'commission_amount' => round($commission, 2),
|
|
'total_expenses_month' => 0,
|
|
'expenses_q1' => round($expensesQ1Amount, 2),
|
|
'expenses_q2' => 0,
|
|
'total_earning' => round($totalEarning, 2),
|
|
'type' => 'anticipo',
|
|
];
|
|
} else {
|
|
// =====================
|
|
// QUINCENA 2 - LIQUIDACIÓN
|
|
// =====================
|
|
// Liquidación = mitad del sueldo - gastos de Q2
|
|
|
|
// Gastos: q2 completo + mensual/2
|
|
$expensesQ2Amount = $month->expenses()
|
|
->where(function($q) {
|
|
$q->where('expense_type', 'q2')
|
|
->orWhere('expense_type', 'mensual');
|
|
})
|
|
->get()
|
|
->sum(function($e) {
|
|
return $e->expense_type === 'mensual' ? $e->amount / 2 : $e->amount;
|
|
});
|
|
|
|
// Total a pagar en liquidacion
|
|
$totalEarning = $biweeklySalary - $expensesQ2Amount;
|
|
|
|
return [
|
|
'user_id' => $user->id,
|
|
'month_id' => $month->id,
|
|
'month_name' => $month->name . ' ' . $year,
|
|
'biweekly' => $biweekly,
|
|
'period' => "2da Quincena (16-$lastDay) - LIQUIDACIÓN",
|
|
'description' => 'Mitad del sueldo - mitad de gastos del mes',
|
|
'biweekly_salary' => round($biweeklySalary, 2),
|
|
'total_system_sales' => 0,
|
|
'expenses_q2' => round($expensesQ2Amount, 2),
|
|
'total_earning' => round($totalEarning, 2),
|
|
'type' => 'liquidacion',
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Resumen anual del usuario
|
|
*/
|
|
public static function calculateYearly(User $user, int $year): array
|
|
{
|
|
$months = $user->months()->where('year', $year)->get();
|
|
|
|
$totalUserSales = 0;
|
|
$totalSystemSales = 0;
|
|
$totalExpenses = 0;
|
|
$totalSalary = 0;
|
|
$totalCommission = 0;
|
|
|
|
foreach ($months as $month) {
|
|
$totalUserSales += $month->dailySales()->sum('user_sales');
|
|
$totalSystemSales += $month->dailySales()->sum('system_sales');
|
|
$totalExpenses += $month->expenses()->sum('amount');
|
|
$totalSalary += $user->monthly_salary;
|
|
$totalCommission += ($month->dailySales()->sum('system_sales') * $user->commission_percentage) / 100;
|
|
}
|
|
|
|
return [
|
|
'user_id' => $user->id,
|
|
'year' => $year,
|
|
'months_count' => $months->count(),
|
|
'total_user_sales' => round($totalUserSales, 2),
|
|
'total_system_sales' => round($totalSystemSales, 2),
|
|
'total_expenses' => round($totalExpenses, 2),
|
|
'total_salary' => round($totalSalary, 2),
|
|
'total_commission' => round($totalCommission, 2),
|
|
'total_earning' => round($totalSalary + $totalCommission - $totalExpenses, 2),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Obtener número del mes por nombre
|
|
*/
|
|
private static function getMonthNumber(string $monthName): int
|
|
{
|
|
$months = [
|
|
'Enero' => 1, 'Febrero' => 2, 'Marzo' => 3, 'Abril' => 4,
|
|
'Mayo' => 5, 'Junio' => 6, 'Julio' => 7, 'Agosto' => 8,
|
|
'Septiembre' => 9, 'Octubre' => 10, 'Noviembre' => 11, 'Diciembre' => 12
|
|
];
|
|
|
|
return $months[$monthName] ?? 1;
|
|
}
|
|
|
|
/**
|
|
* Obtener último día del mes
|
|
*/
|
|
private static function getLastDayOfMonth(string $monthName, int $year): int
|
|
{
|
|
$monthNumber = self::getMonthNumber($monthName);
|
|
return (int) date('t', mktime(0, 0, 0, $monthNumber, 1, $year));
|
|
}
|
|
} |