add controllers, servoices
This commit is contained in:
@@ -0,0 +1,233 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user