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'],
];
}
}