131 lines
4.0 KiB
PHP
131 lines
4.0 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\LedgerEntry;
|
|
use App\Models\ChartOfAccount;
|
|
use App\Models\Payment;
|
|
use App\Models\Wage;
|
|
use Carbon\Carbon;
|
|
|
|
class LedgerService
|
|
{
|
|
/**
|
|
* Create a ledger entry from a payment (income)
|
|
*/
|
|
public function recordPayment(Payment $payment): LedgerEntry
|
|
{
|
|
$incomeAccount = ChartOfAccount::where('type', 'income')
|
|
->where('category', 'revenue')
|
|
->first();
|
|
|
|
return LedgerEntry::create([
|
|
'entry_date' => $payment->payment_date,
|
|
'chart_of_account_id' => $incomeAccount?->id,
|
|
'currency_id' => $payment->invoice->currency_id,
|
|
'amount' => $payment->amount,
|
|
'description' => "Payment received - {$payment->payment_number}",
|
|
'source_type' => 'payment',
|
|
'source_id' => $payment->id,
|
|
'created_by' => $payment->received_by,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Create a ledger entry for a wage (expense)
|
|
*/
|
|
public function recordWage(Wage $wage): LedgerEntry
|
|
{
|
|
$expenseAccount = ChartOfAccount::where('type', 'expense')
|
|
->where('category', 'operating_expense')
|
|
->first();
|
|
|
|
return LedgerEntry::create([
|
|
'entry_date' => $wage->period_end,
|
|
'chart_of_account_id' => $expenseAccount?->id,
|
|
'currency_id' => $wage->currency_id,
|
|
'amount' => -$wage->total_amount, // negative for expense
|
|
'description' => "Wage payment - {$wage->user->name} ({$wage->period_start} to {$wage->period_end})",
|
|
'source_type' => 'wage',
|
|
'source_id' => $wage->id,
|
|
'created_by' => $wage->created_by,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Get income summary for a period
|
|
*/
|
|
public function getIncomeSummary(string $startDate, string $endDate): array
|
|
{
|
|
$entries = LedgerEntry::income()
|
|
->whereBetween('entry_date', [$startDate, $endDate])
|
|
->with('chartOfAccount')
|
|
->get();
|
|
|
|
$byAccount = $entries->groupBy('chart_of_account_id')
|
|
->map(fn($group) => [
|
|
'account_name' => $group->first()->chartOfAccount->name,
|
|
'total' => $group->sum('amount'),
|
|
])
|
|
->values();
|
|
|
|
return [
|
|
'total_income' => $entries->sum('amount'),
|
|
'by_account' => $byAccount,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Get expense summary for a period
|
|
*/
|
|
public function getExpenseSummary(string $startDate, string $endDate): array
|
|
{
|
|
$entries = LedgerEntry::expense()
|
|
->whereBetween('entry_date', [$startDate, $endDate])
|
|
->with('chartOfAccount')
|
|
->get();
|
|
|
|
$byAccount = $entries->groupBy('chart_of_account_id')
|
|
->map(fn($group) => [
|
|
'account_name' => $group->first()->chartOfAccount->name,
|
|
'total' => abs($group->sum('amount')),
|
|
])
|
|
->values();
|
|
|
|
return [
|
|
'total_expenses' => abs($entries->sum('amount')),
|
|
'by_account' => $byAccount,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Get net profit for a period
|
|
*/
|
|
public function getNetProfit(string $startDate, string $endDate): float
|
|
{
|
|
$income = $this->getIncomeSummary($startDate, $endDate)['total_income'];
|
|
$expenses = $this->getExpenseSummary($startDate, $endDate)['total_expenses'];
|
|
|
|
return $income - $expenses;
|
|
}
|
|
|
|
/**
|
|
* Get full P&L report
|
|
*/
|
|
public function getProfitLossReport(string $startDate, string $endDate): array
|
|
{
|
|
$income = $this->getIncomeSummary($startDate, $endDate);
|
|
$expenses = $this->getExpenseSummary($startDate, $endDate);
|
|
|
|
return [
|
|
'period' => [
|
|
'start' => $startDate,
|
|
'end' => $endDate,
|
|
],
|
|
'income' => $income,
|
|
'expenses' => $expenses,
|
|
'net_profit' => $income['total_income'] - $expenses['total_expenses'],
|
|
];
|
|
}
|
|
}
|