add controllers, servoices
This commit is contained in:
@@ -0,0 +1,498 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Reimbursements;
|
||||
|
||||
use App\Models\Expense;
|
||||
use App\Models\ReimbursementBatchAdminFile;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class ReimbursementQueryService
|
||||
{
|
||||
public function __construct(
|
||||
private ReimbursementRecipientService $recipients,
|
||||
private ReimbursementFileService $files
|
||||
) {
|
||||
}
|
||||
|
||||
public function underProcessing(): array
|
||||
{
|
||||
$pendingQuery = DB::table('expenses as e')
|
||||
->selectRaw('e.id as expense_id, e.amount as expense_amount, e.description, e.receipt_path as expense_receipt, e.retailor, e.purchased_by, u.firstname as purchaser_firstname, u.lastname as purchaser_lastname')
|
||||
->leftJoin('users as u', 'u.id', '=', 'e.purchased_by')
|
||||
->leftJoin('reimbursement_batch_items as bi', function ($join) {
|
||||
$join->on('bi.expense_id', '=', 'e.id');
|
||||
$join->whereNull('bi.unassigned_at');
|
||||
})
|
||||
->whereNull('e.reimbursement_id')
|
||||
->where('e.category', '!=', 'Donation')
|
||||
->where(function ($q) {
|
||||
$q->where('e.status', 'approved')
|
||||
->orWhere('e.status', 'Approved')
|
||||
->orWhere('e.status', 'APPROVED');
|
||||
})
|
||||
->whereNull('bi.id')
|
||||
->orderByDesc('e.created_at');
|
||||
|
||||
$pendingRows = $pendingQuery->get();
|
||||
|
||||
$pendingItems = [];
|
||||
$itemsMap = [];
|
||||
|
||||
foreach ($pendingRows as $row) {
|
||||
$expenseId = (int) ($row->expense_id ?? 0);
|
||||
if ($expenseId <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$receiptUrl = $this->files->expenseReceiptUrl($row->expense_receipt ?? null);
|
||||
$fullName = trim(($row->purchaser_firstname ?? '') . ' ' . ($row->purchaser_lastname ?? '')) ?: 'Unknown';
|
||||
|
||||
$item = [
|
||||
'id' => $expenseId,
|
||||
'expense_id' => $expenseId,
|
||||
'reimbursement_id' => null,
|
||||
'expense_amount' => (float) ($row->expense_amount ?? 0),
|
||||
'vendor' => (string) ($row->retailor ?? ''),
|
||||
'description' => trim((string) ($row->description ?? '')),
|
||||
'purchased_by' => $fullName,
|
||||
'receipt_url' => $receiptUrl,
|
||||
'batch_id' => null,
|
||||
'batch_label' => null,
|
||||
'admin_id' => null,
|
||||
'admin_name' => null,
|
||||
'batch_number' => 0,
|
||||
];
|
||||
|
||||
$pendingItems[] = $item;
|
||||
$itemsMap[$expenseId] = $item;
|
||||
}
|
||||
|
||||
$assignedQuery = DB::table('reimbursement_batch_items as bi')
|
||||
->selectRaw('bi.id as batch_item_id, bi.batch_id, bi.admin_id, bi.reimbursement_id, bi.expense_id, b.title as batch_title, b.status as batch_status, b.yearly_batch_number as batch_year_number, e.amount as expense_amount, e.description, e.receipt_path as expense_receipt, e.retailor, purchaser.firstname as purchaser_firstname, purchaser.lastname as purchaser_lastname, admin.firstname as admin_firstname, admin.lastname as admin_lastname')
|
||||
->join('reimbursement_batches as b', 'b.id', '=', 'bi.batch_id')
|
||||
->join('expenses as e', 'e.id', '=', 'bi.expense_id')
|
||||
->leftJoin('users as purchaser', 'purchaser.id', '=', 'e.purchased_by')
|
||||
->leftJoin('users as admin', 'admin.id', '=', 'bi.admin_id')
|
||||
->where('b.status', 'open')
|
||||
->whereNull('bi.unassigned_at')
|
||||
->whereNull('e.reimbursement_id')
|
||||
->where('e.category', '!=', 'Donation')
|
||||
->where(function ($q) {
|
||||
$q->where('e.status', 'approved')
|
||||
->orWhere('e.status', 'Approved')
|
||||
->orWhere('e.status', 'APPROVED');
|
||||
})
|
||||
->orderBy('b.opened_at', 'ASC')
|
||||
->orderBy('bi.assigned_at', 'ASC');
|
||||
|
||||
$assignedRows = $assignedQuery->get();
|
||||
$batchStructures = [];
|
||||
|
||||
foreach ($assignedRows as $row) {
|
||||
$expenseId = (int) ($row->expense_id ?? 0);
|
||||
$batchId = (int) ($row->batch_id ?? 0);
|
||||
if ($expenseId <= 0 || $batchId <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$receiptUrl = $this->files->expenseReceiptUrl($row->expense_receipt ?? null);
|
||||
$purchaser = trim(($row->purchaser_firstname ?? '') . ' ' . ($row->purchaser_lastname ?? '')) ?: 'Unknown';
|
||||
$yearlyNumber = (int) ($row->batch_year_number ?? 0);
|
||||
$batchLabel = trim((string) ($row->batch_title ?? ''));
|
||||
if ($batchLabel === '') {
|
||||
$fallbackNumber = $yearlyNumber > 0 ? $yearlyNumber : $batchId;
|
||||
$batchLabel = 'Batch #' . $fallbackNumber;
|
||||
}
|
||||
$adminId = $row->admin_id ? (int) $row->admin_id : 0;
|
||||
$adminName = $adminId > 0
|
||||
? (trim(($row->admin_firstname ?? '') . ' ' . ($row->admin_lastname ?? '')) ?: 'Admin')
|
||||
: 'Unassigned';
|
||||
$batchStatus = strtolower(trim((string) ($row->batch_status ?? ''))) ?: 'open';
|
||||
|
||||
$item = [
|
||||
'id' => $expenseId,
|
||||
'expense_id' => $expenseId,
|
||||
'reimbursement_id' => $row->reimbursement_id ? (int) $row->reimbursement_id : null,
|
||||
'expense_amount' => (float) ($row->expense_amount ?? 0),
|
||||
'vendor' => (string) ($row->retailor ?? ''),
|
||||
'description' => trim((string) ($row->description ?? '')),
|
||||
'purchased_by' => $purchaser,
|
||||
'receipt_url' => $receiptUrl,
|
||||
'batch_id' => $batchId,
|
||||
'batch_label' => $batchLabel,
|
||||
'admin_id' => $adminId ?: null,
|
||||
'admin_name' => $adminId > 0 ? $adminName : null,
|
||||
'batch_number' => $batchId,
|
||||
];
|
||||
|
||||
$itemsMap[$expenseId] = $item;
|
||||
|
||||
if (!isset($batchStructures[$batchId])) {
|
||||
$batchStructures[$batchId] = [
|
||||
'batchId' => $batchId,
|
||||
'label' => $batchLabel,
|
||||
'slots' => [],
|
||||
'status' => $batchStatus,
|
||||
'yearly_batch_number' => $yearlyNumber,
|
||||
];
|
||||
} else {
|
||||
$batchStructures[$batchId]['status'] = $batchStatus;
|
||||
if ($yearlyNumber > 0) {
|
||||
$batchStructures[$batchId]['yearly_batch_number'] = $yearlyNumber;
|
||||
}
|
||||
}
|
||||
|
||||
$slotKey = $adminId ?: 0;
|
||||
if (!isset($batchStructures[$batchId]['slots'][$slotKey])) {
|
||||
$batchStructures[$batchId]['slots'][$slotKey] = [
|
||||
'admin_id' => $adminId ?: 0,
|
||||
'admin_name' => $adminId > 0 ? $adminName : 'Unassigned',
|
||||
'items' => [],
|
||||
'check_file' => null,
|
||||
];
|
||||
}
|
||||
$batchStructures[$batchId]['slots'][$slotKey]['items'][] = $expenseId;
|
||||
}
|
||||
|
||||
$adminFileMap = [];
|
||||
if (!empty($batchStructures)) {
|
||||
$batchIds = array_keys($batchStructures);
|
||||
$files = ReimbursementBatchAdminFile::query()
|
||||
->select('batch_id', 'admin_id', 'filename', 'original_filename')
|
||||
->whereIn('batch_id', $batchIds)
|
||||
->get();
|
||||
|
||||
foreach ($files as $file) {
|
||||
$batchId = (int) ($file->batch_id ?? 0);
|
||||
$adminId = (int) ($file->admin_id ?? 0);
|
||||
if ($batchId <= 0) {
|
||||
continue;
|
||||
}
|
||||
$adminFileMap[$batchId][$adminId] = [
|
||||
'filename' => $file->filename,
|
||||
'original_filename' => $file->original_filename ?? null,
|
||||
'url' => $this->files->adminFileUrl($file->filename ?? '', 'inline'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($batchStructures as $batchId => &$batch) {
|
||||
foreach ($batch['slots'] as $slotKey => &$slot) {
|
||||
$adminId = $slot['admin_id'] ?? 0;
|
||||
$slot['check_file'] = $adminFileMap[$batchId][$adminId] ?? null;
|
||||
}
|
||||
unset($slot);
|
||||
}
|
||||
unset($batch);
|
||||
|
||||
$existingBatches = array_map(static function (array $batch) {
|
||||
$normalizedSlots = array_map(static function (array $slot) {
|
||||
$slot['items'] = array_values(array_map('intval', $slot['items']));
|
||||
return $slot;
|
||||
}, array_values($batch['slots']));
|
||||
|
||||
$itemIds = [];
|
||||
foreach ($normalizedSlots as $slot) {
|
||||
$itemIds = array_merge($itemIds, $slot['items']);
|
||||
}
|
||||
|
||||
return [
|
||||
'batchId' => $batch['batchId'],
|
||||
'batchNumber' => $batch['batchId'],
|
||||
'label' => $batch['label'],
|
||||
'sequence' => $batch['yearly_batch_number'] ?? 0,
|
||||
'yearly_batch_number' => $batch['yearly_batch_number'] ?? 0,
|
||||
'slots' => $normalizedSlots,
|
||||
'itemIds' => array_values(array_unique($itemIds)),
|
||||
'status' => $batch['status'] ?? 'open',
|
||||
];
|
||||
}, array_values($batchStructures));
|
||||
|
||||
$admins = $this->recipients->adminRoster();
|
||||
|
||||
return [
|
||||
'pendingItems' => $pendingItems,
|
||||
'existingBatches' => $existingBatches,
|
||||
'adminUsers' => $admins,
|
||||
'itemsPayload' => array_values($itemsMap),
|
||||
];
|
||||
}
|
||||
|
||||
public function index(array $filters): array
|
||||
{
|
||||
$expenses = Expense::getReimbursedExpensesWithDetails($filters)
|
||||
->get()
|
||||
->map(static fn ($row) => (array) $row)
|
||||
->all();
|
||||
|
||||
$batchSummaries = [];
|
||||
$batchDetails = [];
|
||||
$batchAttachments = [];
|
||||
|
||||
$batchQuery = DB::table('reimbursement_batches as b')
|
||||
->selectRaw('b.id as batch_id, b.title as batch_title, b.yearly_batch_number, b.closed_at, b.school_year as batch_school_year, e.id as expense_id, e.amount as expense_amount, e.description, e.retailor, e.receipt_path as expense_receipt, e.date_of_purchase as expense_date_of_purchase, e.purchased_by, u.firstname as purchaser_firstname, u.lastname as purchaser_lastname, r.amount as reimb_amount')
|
||||
->join('reimbursement_batch_items as bi', 'bi.batch_id', '=', 'b.id')
|
||||
->join('expenses as e', 'e.id', '=', 'bi.expense_id')
|
||||
->leftJoin('users as u', 'u.id', '=', 'e.purchased_by')
|
||||
->leftJoin('reimbursements as r', 'r.expense_id', '=', 'e.id')
|
||||
->where('b.status', 'closed')
|
||||
->whereNull('bi.unassigned_at');
|
||||
|
||||
if (!empty($filters['school_year'])) {
|
||||
$batchQuery->where(function ($q) use ($filters) {
|
||||
$q->where('b.school_year', $filters['school_year'])
|
||||
->orWhere('e.school_year', $filters['school_year']);
|
||||
});
|
||||
}
|
||||
if (!empty($filters['user_id'])) {
|
||||
$batchQuery->where('e.purchased_by', $filters['user_id']);
|
||||
}
|
||||
|
||||
$batchRows = $batchQuery->get();
|
||||
foreach ($batchRows as $row) {
|
||||
$bid = (int) ($row->batch_id ?? 0);
|
||||
if ($bid <= 0) {
|
||||
continue;
|
||||
}
|
||||
$labelNumber = (int) ($row->yearly_batch_number ?? $bid);
|
||||
if (!isset($batchSummaries[$bid])) {
|
||||
$batchSummaries[$bid] = [
|
||||
'batch_id' => $bid,
|
||||
'title' => trim((string) ($row->batch_title ?? '')) ?: ('Batch #' . $labelNumber),
|
||||
'sequence' => $labelNumber,
|
||||
'closed_at' => $row->closed_at ?? null,
|
||||
'amount' => 0.0,
|
||||
'items' => 0,
|
||||
];
|
||||
}
|
||||
$amount = $row->reimb_amount ?? $row->expense_amount ?? 0;
|
||||
$batchSummaries[$bid]['amount'] += (float) $amount;
|
||||
$batchSummaries[$bid]['items'] += 1;
|
||||
|
||||
if (!isset($batchDetails[$bid])) {
|
||||
$batchDetails[$bid] = [
|
||||
'title' => $batchSummaries[$bid]['title'],
|
||||
'sequence' => $labelNumber,
|
||||
'closed_at' => $batchSummaries[$bid]['closed_at'],
|
||||
'items' => [],
|
||||
'checks' => [],
|
||||
];
|
||||
}
|
||||
if (!isset($batchAttachments[$bid])) {
|
||||
$batchAttachments[$bid] = [
|
||||
'receipts' => [],
|
||||
'checks' => [],
|
||||
];
|
||||
}
|
||||
|
||||
$batchDetails[$bid]['items'][] = [
|
||||
'amount' => (float) $amount,
|
||||
'description' => $row->description ?? '',
|
||||
'vendor' => $row->retailor ?? '',
|
||||
'purchased_by' => trim(($row->purchaser_firstname ?? '') . ' ' . ($row->purchaser_lastname ?? '')),
|
||||
'receipt_url' => $this->files->expenseReceiptUrl($row->expense_receipt ?? null),
|
||||
];
|
||||
|
||||
$receiptFilename = trim((string) ($row->expense_receipt ?? ''));
|
||||
if ($receiptFilename !== '') {
|
||||
$batchAttachments[$bid]['receipts'][] = [
|
||||
'expense_id' => (int) ($row->expense_id ?? 0),
|
||||
'receipt_filename' => $receiptFilename,
|
||||
'receipt_url' => $this->files->expenseReceiptUrl($receiptFilename),
|
||||
'purchaser_firstname' => $row->purchaser_firstname ?? '',
|
||||
'purchaser_lastname' => $row->purchaser_lastname ?? '',
|
||||
'vendor' => $row->retailor ?? '',
|
||||
'description' => $row->description ?? '',
|
||||
'amount' => (float) ($row->expense_amount ?? 0),
|
||||
'date_of_purchase' => $row->expense_date_of_purchase ?? '',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($batchSummaries)) {
|
||||
$batchIds = array_keys($batchSummaries);
|
||||
$files = ReimbursementBatchAdminFile::query()
|
||||
->select('id as file_id', 'batch_id', 'admin_id', 'filename', 'original_filename', 'uploaded_at')
|
||||
->whereIn('batch_id', $batchIds)
|
||||
->get();
|
||||
|
||||
$adminNames = $this->recipients->adminRoster();
|
||||
$adminNameMap = [];
|
||||
foreach ($adminNames as $admin) {
|
||||
$adminNameMap[(int) $admin['id']] = trim(($admin['firstname'] ?? '') . ' ' . ($admin['lastname'] ?? ''));
|
||||
}
|
||||
|
||||
foreach ($files as $file) {
|
||||
$bid = (int) ($file->batch_id ?? 0);
|
||||
if ($bid <= 0 || !isset($batchDetails[$bid])) {
|
||||
continue;
|
||||
}
|
||||
$aid = (int) ($file->admin_id ?? 0);
|
||||
$batchDetails[$bid]['checks'][] = [
|
||||
'admin' => $adminNameMap[$aid] ?? ($aid > 0 ? 'Admin #' . $aid : 'Unassigned'),
|
||||
'filename' => $file->filename,
|
||||
'original' => $file->original_filename ?? $file->filename,
|
||||
'url' => $this->files->adminFileUrl($file->filename ?? '', 'inline'),
|
||||
];
|
||||
if (!isset($batchAttachments[$bid])) {
|
||||
$batchAttachments[$bid] = [
|
||||
'receipts' => [],
|
||||
'checks' => [],
|
||||
];
|
||||
}
|
||||
$batchAttachments[$bid]['checks'][] = [
|
||||
'file_id' => (int) ($file->file_id ?? 0),
|
||||
'filename' => $file->filename,
|
||||
'original_filename' => $file->original_filename ?? $file->filename,
|
||||
'admin' => $adminNameMap[$aid] ?? ($aid > 0 ? 'Admin #' . $aid : 'Unassigned'),
|
||||
'url' => $this->files->adminFileUrl($file->filename ?? '', 'inline'),
|
||||
'uploaded_at' => $file->uploaded_at ?? null,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($batchSummaries)) {
|
||||
$batchSummaries = array_values($batchSummaries);
|
||||
usort($batchSummaries, static function ($a, $b) {
|
||||
$aSeq = (int) ($a['sequence'] ?? 0);
|
||||
$bSeq = (int) ($b['sequence'] ?? 0);
|
||||
return $bSeq <=> $aSeq;
|
||||
});
|
||||
}
|
||||
|
||||
$donationBatch = null;
|
||||
$donationDetails = [
|
||||
'items' => [],
|
||||
'checks' => [],
|
||||
];
|
||||
|
||||
$donationQuery = DB::table('expenses as e')
|
||||
->selectRaw('e.id as expense_id, e.amount as expense_amount, e.description, e.retailor, e.receipt_path as expense_receipt, e.purchased_by, e.school_year, e.semester, e.status, u.firstname as purchaser_firstname, u.lastname as purchaser_lastname')
|
||||
->leftJoin('users as u', 'u.id', '=', 'e.purchased_by')
|
||||
->where('e.category', 'Donation');
|
||||
|
||||
if (!empty($filters['school_year'])) {
|
||||
$donationQuery->where('e.school_year', $filters['school_year']);
|
||||
}
|
||||
if (!empty($filters['semester'])) {
|
||||
$donationQuery->where('e.semester', $filters['semester']);
|
||||
}
|
||||
if (!empty($filters['user_id'])) {
|
||||
$donationQuery->where('e.purchased_by', $filters['user_id']);
|
||||
}
|
||||
if (!empty($filters['status'])) {
|
||||
$donationQuery->where(function ($q) use ($filters) {
|
||||
$q->where('e.status', $filters['status'])
|
||||
->orWhere('e.status', strtolower((string) $filters['status']))
|
||||
->orWhere('e.status', strtoupper((string) $filters['status']));
|
||||
});
|
||||
}
|
||||
|
||||
$donationRows = $donationQuery->orderByDesc('e.created_at')->get();
|
||||
if ($donationRows->isNotEmpty()) {
|
||||
$donationTotal = 0.0;
|
||||
foreach ($donationRows as $row) {
|
||||
$amount = (float) ($row->expense_amount ?? 0);
|
||||
$donationTotal += $amount;
|
||||
$purchaser = trim(($row->purchaser_firstname ?? '') . ' ' . ($row->purchaser_lastname ?? ''));
|
||||
if ($purchaser === '') {
|
||||
$purchaser = 'Unknown';
|
||||
}
|
||||
$donationDetails['items'][] = [
|
||||
'amount' => $amount,
|
||||
'description' => $row->description ?? '',
|
||||
'vendor' => $row->retailor ?? '',
|
||||
'purchased_by' => $purchaser,
|
||||
'receipt_url' => $this->files->expenseReceiptUrl($row->expense_receipt ?? null),
|
||||
];
|
||||
}
|
||||
|
||||
$donationBatch = [
|
||||
'title' => 'Donations',
|
||||
'items' => count($donationDetails['items']),
|
||||
'amount' => $donationTotal,
|
||||
];
|
||||
}
|
||||
|
||||
foreach ($expenses as &$e) {
|
||||
if (array_key_exists('expense_receipt', $e)) {
|
||||
$e['expense_receipt_url'] = $this->files->expenseReceiptUrl($e['expense_receipt']);
|
||||
} elseif (array_key_exists('receipt_path', $e)) {
|
||||
$e['expense_receipt_url'] = $this->files->expenseReceiptUrl($e['receipt_path']);
|
||||
}
|
||||
|
||||
if (array_key_exists('reimb_receipt', $e)) {
|
||||
$e['reimb_receipt_url'] = $this->files->receiptUrl($e['reimb_receipt']);
|
||||
} elseif (array_key_exists('receipt_path_reimb', $e)) {
|
||||
$e['reimb_receipt_url'] = $this->files->receiptUrl($e['receipt_path_reimb']);
|
||||
}
|
||||
|
||||
$recipientId = $e['reimb_recipient_id'] ?? ($e['reimbursed_to'] ?? null);
|
||||
$hasName = trim(($e['reimb_firstname'] ?? '') . ' ' . ($e['reimb_lastname'] ?? '')) !== '';
|
||||
if (!$hasName) {
|
||||
$label = $this->recipients->specialRecipientLabel($recipientId);
|
||||
if ($label !== null) {
|
||||
$e['reimb_firstname'] = $label;
|
||||
$e['reimb_lastname'] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($e);
|
||||
|
||||
$users = $this->recipients->recipientOptions();
|
||||
|
||||
$years = DB::table('reimbursements')
|
||||
->select('school_year')
|
||||
->distinct()
|
||||
->orderByDesc('school_year')
|
||||
->get();
|
||||
$schoolYears = array_values(array_filter(array_map(static fn ($row) => $row->school_year ?? null, $years->all())));
|
||||
|
||||
return [
|
||||
'expenses' => $expenses,
|
||||
'users' => $users,
|
||||
'schoolYears' => $schoolYears,
|
||||
'batchSummaries' => $batchSummaries,
|
||||
'batchDetails' => $batchDetails,
|
||||
'batchAttachments' => $batchAttachments,
|
||||
'donationBatch' => $donationBatch,
|
||||
'donationDetails' => $donationDetails,
|
||||
];
|
||||
}
|
||||
|
||||
public function reimbursedExpenses(): array
|
||||
{
|
||||
$rows = DB::table('reimbursements as r')
|
||||
->selectRaw('e.amount as expense_amount, e.category, e.description, e.receipt_path as expense_receipt, e.purchased_by, r.amount as reimb_amount, r.reimbursement_method, r.check_number, r.receipt_path as reimb_receipt, r.status as reimb_status, r.created_at, u.firstname as purchaser_firstname, u.lastname as purchaser_lastname, a.firstname as approver_firstname, a.lastname as approver_lastname')
|
||||
->join('expenses as e', 'e.id', '=', 'r.expense_id')
|
||||
->leftJoin('users as u', 'u.id', '=', 'e.purchased_by')
|
||||
->leftJoin('users as a', 'a.id', '=', 'r.approved_by')
|
||||
->orderByDesc('r.created_at')
|
||||
->get();
|
||||
|
||||
$expenses = [];
|
||||
foreach ($rows as $row) {
|
||||
$expenses[] = [
|
||||
'expense_amount' => (float) ($row->expense_amount ?? 0),
|
||||
'category' => $row->category ?? null,
|
||||
'description' => $row->description ?? null,
|
||||
'expense_receipt' => $row->expense_receipt ?? null,
|
||||
'purchased_by' => $row->purchased_by ?? null,
|
||||
'reimb_amount' => (float) ($row->reimb_amount ?? 0),
|
||||
'reimbursement_method' => $row->reimbursement_method ?? null,
|
||||
'check_number' => $row->check_number ?? null,
|
||||
'reimb_receipt' => $row->reimb_receipt ?? null,
|
||||
'reimb_status' => $row->reimb_status ?? null,
|
||||
'created_at' => $row->created_at ?? null,
|
||||
'purchaser_firstname' => $row->purchaser_firstname ?? null,
|
||||
'purchaser_lastname' => $row->purchaser_lastname ?? null,
|
||||
'approver_firstname' => $row->approver_firstname ?? null,
|
||||
'approver_lastname' => $row->approver_lastname ?? null,
|
||||
'expense_receipt_url' => $this->files->expenseReceiptUrl($row->expense_receipt ?? null),
|
||||
'reimb_receipt_url' => $this->files->receiptUrl($row->reimb_receipt ?? null),
|
||||
];
|
||||
}
|
||||
|
||||
return $expenses;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user