Files
alrahma_sunday_school_api/app/Services/Reimbursements/ReimbursementExportService.php
T
2026-03-09 02:52:13 -04:00

234 lines
8.6 KiB
PHP

<?php
namespace App\Services\Reimbursements;
use App\Models\ReimbursementBatch;
use Illuminate\Support\Facades\DB;
use RuntimeException;
class ReimbursementExportService
{
public function __construct(private ReimbursementRecipientService $recipients)
{
}
public function buildUnderProcessingCsv(): array
{
$builder = DB::table('expenses')
->select('expenses.*', 'u.firstname as purchaser_firstname', 'u.lastname as purchaser_lastname')
->leftJoin('users as u', 'u.id', '=', 'expenses.purchased_by')
->where('expenses.status', 'approved')
->whereNull('expenses.reimbursement_id')
->where('expenses.category', '!=', 'Donation')
->orderByDesc('expenses.created_at');
$records = $builder->get();
$grouped = [];
foreach ($records as $row) {
$personId = (int) ($row->purchased_by ?? 0);
$name = trim(($row->purchaser_firstname ?? '') . ' ' . ($row->purchaser_lastname ?? ''));
if ($name === '') {
$name = $row->purchaser_firstname ?? $row->purchaser_lastname ?? 'Unknown';
}
$key = $personId > 0 ? 'id_' . $personId : 'name_' . strtolower($name);
if (!isset($grouped[$key])) {
$grouped[$key] = [
'name' => $name ?: 'Unknown',
'total' => 0.0,
'vendors' => [],
'descriptions' => [],
];
}
$amount = (float) ($row->amount ?? 0);
$grouped[$key]['total'] += $amount;
$vendor = trim((string) ($row->retailor ?? ''));
if ($vendor !== '' && !in_array($vendor, $grouped[$key]['vendors'], true)) {
$grouped[$key]['vendors'][] = $vendor;
}
$desc = trim((string) ($row->description ?? ''));
if ($desc !== '' && !in_array($desc, $grouped[$key]['descriptions'], true)) {
$grouped[$key]['descriptions'][] = $desc;
}
}
$rows = [];
$rows[] = ['Person', 'Total Amount', 'Vendors', 'Descriptions'];
foreach ($grouped as $entry) {
$rows[] = [
$entry['name'],
number_format($entry['total'], 2, '.', ''),
implode('; ', $entry['vendors']),
implode('; ', $entry['descriptions']),
];
}
return [
'filename' => 'under_processing_expenses.csv',
'rows' => $rows,
];
}
public function buildProcessedCsv(array $filters): array
{
$builder = DB::table('reimbursements')
->select('reimbursements.*', 'u.firstname as reimb_firstname', 'u.lastname as reimb_lastname')
->leftJoin('users as u', 'u.id', '=', 'reimbursements.reimbursed_to');
if (!empty($filters['semester'])) {
$builder->where('reimbursements.semester', $filters['semester']);
}
if (!empty($filters['status'])) {
$builder->where('reimbursements.status', $filters['status']);
}
if (!empty($filters['user_id'])) {
$builder->where('reimbursements.reimbursed_to', $filters['user_id']);
}
if (!empty($filters['school_year'])) {
$builder->where('reimbursements.school_year', $filters['school_year']);
}
$records = $builder->orderByDesc('reimbursements.created_at')->get();
$rows = [];
$rows[] = ['Amount', 'Reimbursed To', 'Status', 'Method', 'Check #', 'School Year', 'Semester', 'Date'];
foreach ($records as $row) {
$hasName = trim(($row->reimb_firstname ?? '') . ' ' . ($row->reimb_lastname ?? '')) !== '';
if (!$hasName) {
$label = $this->recipients->specialRecipientLabel($row->reimbursed_to ?? null);
if ($label !== null) {
$row->reimb_firstname = $label;
$row->reimb_lastname = '';
}
}
$rows[] = [
$row->amount,
trim(($row->reimb_firstname ?? '') . ' ' . ($row->reimb_lastname ?? '')),
$row->status,
$row->reimbursement_method ?? '-',
$row->check_number ?? '-',
$row->school_year ?? '-',
$row->semester ?? '-',
$row->created_at,
];
}
return [
'filename' => 'reimbursements_export.csv',
'rows' => $rows,
];
}
public function buildBatchCsv(int $batchId): array
{
$batch = ReimbursementBatch::query()->find($batchId);
if (!$batch) {
throw new RuntimeException('Batch not found.');
}
$batchLabel = trim((string) ($batch->title ?? '')) ?: ('Batch #' . $batchId);
$receiptRows = $this->fetchBatchReceiptRows($batchId);
$rows = [];
$this->writeBatchCsvMetadata($rows, $batchLabel, $batch->toArray());
$this->writeBatchCsvSummary($rows, $receiptRows, $this->formatCsvDate($batch->closed_at ?? null));
return [
'filename' => sprintf('batch_%d_items.csv', $batchId),
'rows' => $rows,
];
}
private function fetchBatchReceiptRows(int $batchId, array $receiptIds = []): array
{
$builder = DB::table('reimbursement_batch_items as bi')
->select('e.id as expense_id', 'e.retailor', 'e.amount', 'e.description', 'e.receipt_path as receipt_filename', 'e.date_of_purchase as purchase_date', 'u.firstname as purchaser_firstname', 'u.lastname as purchaser_lastname')
->join('expenses as e', 'e.id', '=', 'bi.expense_id')
->leftJoin('users as u', 'u.id', '=', 'e.purchased_by')
->where('bi.batch_id', $batchId);
if (!empty($receiptIds)) {
$builder->whereIn('e.id', $receiptIds);
}
$rows = $builder->get()->toArray();
return array_values(array_filter($rows, static function ($row) {
return !empty($row->receipt_filename);
}));
}
private function writeBatchCsvMetadata(array &$rows, string $batchLabel, array $batch): void
{
$closedAtRaw = $batch['closed_at'] ?? null;
$rows[] = ['Batch Title', $batchLabel];
$rows[] = ['School Year', $batch['school_year'] ?? '', 'Semester', $batch['semester'] ?? '', 'Closed At', $this->formatCsvDate($closedAtRaw)];
$rows[] = [];
$rows[] = ['Amount', 'Credit', 'Paid', 'Balance', 'Date', 'By Who', 'Vendor', 'Description'];
}
private function writeBatchCsvSummary(array &$rows, array $receiptRows, string $totalsDate = ''): void
{
$receiptTotalsByRecipient = [];
foreach ($receiptRows as $row) {
$recipientName = trim(($row->purchaser_firstname ?? '') . ' ' . ($row->purchaser_lastname ?? ''));
if ($recipientName === '') {
$recipientName = 'Unknown';
}
$vendor = trim((string) ($row->retailor ?? ''));
if ($vendor === '') {
$vendor = 'Vendor N/A';
}
$dateText = $this->formatCsvDate($row->purchase_date ?? null);
$descriptionValue = trim((string) ($row->description ?? ''));
$descriptionParts = $descriptionValue !== '' ? [$descriptionValue] : ['Receipt'];
$amountValue = (float) ($row->amount ?? 0);
$receiptTotalsByRecipient[$recipientName] = ($receiptTotalsByRecipient[$recipientName] ?? 0.0) + $amountValue;
$rows[] = [
number_format($amountValue, 2, '.', ''),
'',
number_format($amountValue, 2, '.', ''),
'0.00',
$dateText,
$recipientName,
$vendor,
implode(' | ', $descriptionParts),
];
}
if (!empty($receiptTotalsByRecipient)) {
$rows[] = [];
$rows[] = ['Totals by Recipient', '', '', '', '', '', '', ''];
foreach ($receiptTotalsByRecipient as $recipient => $total) {
$formatted = number_format($total, 2, '.', '');
$rows[] = [
$formatted,
'',
$formatted,
'0.00',
$totalsDate,
$recipient,
'',
'',
];
}
}
}
private function formatCsvDate(?string $value): string
{
if (!$value) {
return '';
}
$timestamp = strtotime($value);
if ($timestamp === false) {
return '';
}
return date('m-d-Y', $timestamp);
}
}