ultimatepos/Modules/Accounting/Services/DeferredDocumentsService.php

203 lines
7.5 KiB
PHP

<?php
namespace Modules\Accounting\Services;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Modules\Accounting\Entities\AccountingAccTransMapping;
use Modules\Accounting\Entities\AccountingCheque;
use Modules\Accounting\Entities\AccountingInstallmentSchedule;
class DeferredDocumentsService
{
public function summary(int $businessId): array
{
$cheques = $this->pendingChequeCount($businessId);
$installments = $this->overdueInstallmentCount($businessId);
$invoices = $this->overdueInvoiceCount($businessId);
$journals = $this->pendingJournalCount($businessId);
return [
'cheques' => $cheques,
'installments' => $installments,
'invoices' => $invoices,
'journals' => $journals,
'total' => $cheques + $installments + $invoices + $journals,
];
}
public function items(int $businessId): array
{
$items = [];
foreach ($this->pendingCheques($businessId) as $cheque) {
$items[] = [
'type' => 'cheque',
'type_label' => __('accounting::lang.cheques'),
'reference' => $cheque->cheque_number,
'party' => $cheque->bank_name ?: '-',
'amount' => (float) $cheque->amount,
'due_date' => optional($cheque->due_date)->format('Y-m-d'),
'status' => $cheque->status,
'url' => route('accounting.cheques'),
];
}
foreach ($this->overdueInstallments($businessId) as $row) {
$outstanding = max(0, (float) $row->amount + (float) ($row->penalty_amount ?? 0) - (float) $row->paid_amount);
$items[] = [
'type' => 'installment',
'type_label' => __('accounting::lang.installments'),
'reference' => '#'.$row->installment_number,
'party' => __('accounting::lang.installment_plan').' #'.$row->installment_plan_id,
'amount' => $outstanding,
'due_date' => $row->due_date,
'status' => $row->status,
'url' => route('accounting.installments'),
];
}
foreach ($this->overdueInvoices($businessId) as $invoice) {
$items[] = [
'type' => 'invoice',
'type_label' => __('sale.invoice'),
'reference' => $invoice->invoice_no,
'party' => $invoice->contact_name ?? '-',
'amount' => (float) $invoice->total_due,
'due_date' => $invoice->due_date,
'status' => $invoice->payment_status,
'url' => action([\App\Http\Controllers\SellController::class, 'index']),
];
}
foreach ($this->pendingJournals($businessId) as $journal) {
$items[] = [
'type' => 'journal',
'type_label' => __('accounting::lang.journal_entry'),
'reference' => $journal->ref_no ?? '#'.$journal->id,
'party' => $journal->note ?? '-',
'amount' => null,
'due_date' => optional($journal->operation_date)->format('Y-m-d'),
'status' => $journal->approval_status,
'url' => route('accounting.journalApprovals'),
];
}
return $items;
}
protected function pendingChequeCount(int $businessId): int
{
if (! Schema::hasTable('accounting_cheques')) {
return 0;
}
return (int) AccountingCheque::where('business_id', $businessId)
->whereIn('status', ['pending', 'deposited'])
->where(function ($q) {
$q->whereNull('due_date')
->orWhereDate('due_date', '<=', Carbon::today()->toDateString());
})
->count();
}
protected function overdueInstallmentCount(int $businessId): int
{
if (! Schema::hasTable('accounting_installment_schedule')) {
return 0;
}
return (int) DB::table('accounting_installment_schedule as s')
->join('accounting_installment_plans as p', 'p.id', '=', 's.installment_plan_id')
->where('p.business_id', $businessId)
->whereIn('s.status', ['overdue', 'pending'])
->whereDate('s.due_date', '<', Carbon::today()->toDateString())
->count();
}
protected function overdueInvoiceCount(int $businessId): int
{
if (! Schema::hasTable('transactions') || ! Schema::hasColumn('transactions', 'due_date')) {
return 0;
}
return (int) DB::table('transactions')
->where('business_id', $businessId)
->where('type', 'sell')
->where('status', 'final')
->whereIn('payment_status', ['due', 'partial'])
->whereNotNull('due_date')
->whereDate('due_date', '<', Carbon::today()->toDateString())
->count();
}
protected function pendingJournalCount(int $businessId): int
{
if (! Schema::hasTable('accounting_acc_trans_mappings') || ! Schema::hasColumn('accounting_acc_trans_mappings', 'approval_status')) {
return 0;
}
return (int) AccountingAccTransMapping::where('business_id', $businessId)
->where('approval_status', 'pending')
->count();
}
protected function pendingCheques(int $businessId)
{
return AccountingCheque::where('business_id', $businessId)
->whereIn('status', ['pending', 'deposited'])
->where(function ($q) {
$q->whereNull('due_date')
->orWhereDate('due_date', '<=', Carbon::today()->toDateString());
})
->orderBy('due_date')
->limit(100)
->get();
}
protected function overdueInstallments(int $businessId)
{
return DB::table('accounting_installment_schedule as s')
->join('accounting_installment_plans as p', 'p.id', '=', 's.installment_plan_id')
->where('p.business_id', $businessId)
->whereIn('s.status', ['overdue', 'pending'])
->whereDate('s.due_date', '<', Carbon::today()->toDateString())
->select('s.*')
->orderBy('s.due_date')
->limit(100)
->get();
}
protected function overdueInvoices(int $businessId)
{
return DB::table('transactions as t')
->leftJoin('contacts as c', 'c.id', '=', 't.contact_id')
->where('t.business_id', $businessId)
->where('t.type', 'sell')
->where('t.status', 'final')
->whereIn('t.payment_status', ['due', 'partial'])
->whereNotNull('t.due_date')
->whereDate('t.due_date', '<', Carbon::today()->toDateString())
->select(
't.invoice_no',
't.payment_status',
't.due_date',
'c.name as contact_name',
DB::raw('(t.final_total - COALESCE((SELECT SUM(IF(tp.is_return=1,-1*tp.amount,tp.amount)) FROM transaction_payments tp WHERE tp.transaction_id=t.id),0)) as total_due')
)
->orderBy('t.due_date')
->limit(100)
->get();
}
protected function pendingJournals(int $businessId)
{
return AccountingAccTransMapping::where('business_id', $businessId)
->where('approval_status', 'pending')
->orderByDesc('id')
->limit(50)
->get();
}
}