Files
aso/app/Exports/Sheets/Invoices/VOPSheet.php
2025-12-18 09:53:01 +07:00

350 lines
10 KiB
PHP

<?php
namespace App\Exports\Sheets\Invoices;
use Illuminate\Support\Facades\DB;
use PhpOffice\PhpSpreadsheet\Cell\{
Cell,
DataType,
StringValueBinder
};
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use Maatwebsite\Excel\Concerns\{
FromCollection,
WithHeadings,
WithMapping,
WithTitle,
WithCustomValueBinder,
WithEvents
};
use Maatwebsite\Excel\Events\AfterSheet;
class VOPSheet extends StringValueBinder implements
FromCollection,
WithHeadings,
WithMapping,
WithTitle,
WithCustomValueBinder,
WithEvents
{
protected array $filters;
protected int $no = 0;
protected float $grandTotal = 0;
protected array $benefits = [];
protected $benefitAmounts;
protected bool $benefitInitialized = false;
public function __construct(array $filters = [])
{
$this->filters = $filters;
}
public function collection()
{
$query = DB::table('invoice_payments')
->leftJoin('invoice_payment_details', 'invoice_payment_details.invoice_payment_id', '=', 'invoice_payments.id')
->leftJoin('claim_requests', 'claim_requests.id', '=', 'invoice_payment_details.claim_request_id')
->leftJoin('request_logs', 'request_logs.id', '=', 'claim_requests.request_log_id')
->leftJoin('organizations', 'organizations.id', '=', 'request_logs.organization_id')
->leftJoin('members', 'members.id', '=', 'request_logs.member_id')
->leftJoin('specialities', 'specialities.id', '=', 'request_logs.specialities_id')
->leftJoin('icd', DB::raw("icd.code"), '=', DB::raw("SUBSTRING_INDEX(request_logs.diagnosis, ',', 1)"))
->orderBy('request_logs.service_code', 'desc')
->select(
'invoice_payments.*',
'organizations.name as organization_name',
'members.name as member_name',
'request_logs.diagnosis as code_diagnosis',
'request_logs.service_code',
'request_logs.dppj',
'specialities.name as specialities_name',
'request_logs.submission_date as in',
'request_logs.discharge_date as out',
'request_logs.code as code_log',
'members.payor_id',
'request_logs.nominal as amount',
'claim_requests.request_log_id',
'members.member_id as batch_number',
'request_logs.keterangan',
'icd.name as diagnosis',
'request_logs.type_of_member'
);
if (!empty($this->filters['search'])) {
$query->where('invoice_number', 'like', '%' . $this->filters['search'] . '%');
}
if (!empty($this->filters['start_date'])) {
$query->whereDate('invoice_payments.created_at', '>=', $this->filters['start_date']);
}
if (!empty($this->filters['end_date'])) {
$query->whereDate('invoice_payments.created_at', '<=', $this->filters['end_date']);
}
if (!empty($this->filters['orderBy'])) {
$query->orderBy(
$this->filters['orderBy'],
$this->filters['order'] ?? 'asc'
);
}
$items = $query->get();
// ambil request_log_id
$requestLogIds = $items
->pluck('request_log_id')
->filter()
->unique()
->values();
// set benefit header (hanya yg dipakai)
$this->benefits = DB::table('request_log_benefits')
->join('benefits', 'benefits.id', '=', 'request_log_benefits.benefit_id')
->whereIn('request_log_benefits.request_log_id', $requestLogIds)
->select('benefits.id', 'benefits.description')
->distinct()
->orderBy('benefits.id')
->pluck('benefits.description', 'benefits.id')
->toArray();
// 🔥 preload benefit amount SEKALI (anti N+1)
$this->benefitAmounts = DB::table('request_log_benefits')
->whereIn('request_log_id', $requestLogIds)
->get()
->groupBy('request_log_id');
return $items;
}
public function map($item): array
{
$this->no++;
$this->grandTotal += (float) $item->amount_paid;
$benefitData = $this->getBenefitAmountsWithTotal($item->request_log_id);
return array_merge([
// $this->no,
(string) $item->invoice_number,
// (string) $item->payment_number,
'',
'',
'',
(string) $item->no_reference,
'',
'',
(string) ($item->code_log ?? '-'),
(string) ($item->payor_id ?? '-'),
'',
'',
(string) ($item->organization_name ?? '-'),
(string) ($item->member_name ?? '-'),
(string) ($item->batch_number ?? '-'),
(string) $benefitData['total'],
'',
'',
],
$benefitData['amounts'],
[
(string) ($item->in ?? '-'),
(string) ($item->out ?? '-'),
'',
(string) ($item->diagnosis ?? '-'),
(string) ($item->type_of_member ?? '-'), // omt
(string) ($item->service_code == 'OP' ? 'RJ' : 'RI'),
'',
'',
'',
(string) ($item->dppj ?? '-'),
(string) ($item->in ?? '-'),
(string) ($item->out ?? '-'),
(string) ($item->specialities_name ?? '-'),
'Karyawan',
'',
'',
'',
(string) ($item->keterangan ?? '-'),
// (string) $item->invoice_date,
// (string) $item->start_date,
// (string) $item->end_date,
// (float) $item->amount_paid,
// (string) $item->created_at,
// (string) $item->updated_at,
]);
}
public function headings(): array
{
$this->initBenefits();
return array_merge([
// 'No',
'No Invoice', //ok
// 'Pembayaran Ke',
'MONTH', //ok
'PERIODE SES', //ok
'SUBMIT INV/SES', //ok
'REFERENCE', //ok
'RECEIVED', //ok
'INV. DATE', //ok
'CODE', //ok
'VENDOR', //ok
'PO', //ok
'SES', //ok
'MAIN DESCRIPTION', //ok
'DESCRIPTION', //ok
'BN', //ok
'AMOUNT', //ok
'WBS', // ok
'NOTE', // ok
],
array_values($this->benefits),
[ 'DEPARTURE', // ok
'ARRIVED', // ok
'TEMPORARY DIAGNOSA', // ok
'FINAL DIAGNOSA',
'NOTE (OMT / NON OMT)',
'RI/RJ', // OK
'Dept', // OK
'Cost Center', // OK
'No.TA', // OK
'DPJP', // OK
'IN', // OK
'OUT', // OK
'SPECIALIST', // OK
'Employee', // OK
'Total Invoice sebelum BPJS', // OK
'BPJS', // OK
'Ditanggung Perusahaan', // OK
'KETERANGAN', // OK
// 'Tanggal Invoice',
// 'Start Date',
// 'End Date',
// 'Nominal Pembayaran',
// 'Created At',
// 'Updated At',
]);
}
public function title(): string
{
return 'VOP & VIP';
}
/**
* FOOTER: Grand Total
*/
public function registerEvents(): array
{
return [
AfterSheet::class => function (AfterSheet $event) {
// $event->sheet->getStyle('A1:AO1')
// ->getFont()
// ->setBold(true);
$highestColumn = $event->sheet->getDelegate()->getHighestColumn();
$event->sheet->getStyle('A1:' . $highestColumn . '1')
->getFont()
->setBold(true);
// $row = $event->sheet->getHighestRow() + 1;
// $event->sheet->setCellValue("A{$row}", 'Grand Total');
// $event->sheet->setCellValue("G{$row}", $this->grandTotal);
// // Bold footer
// $event->sheet->getStyle("A{$row}:G{$row}")
// ->getFont()
// ->setBold(true);
},
];
}
/**
* FORCE: object → string
*/
public function bindValue(Cell $cell, $value)
{
if (is_object($value) || is_array($value)) {
$value = json_encode($value);
}
$cell->setValueExplicit($value, DataType::TYPE_STRING);
return true;
}
protected function getBenefitAmountsWithTotal(?int $requestLogId): array
{
if (!$requestLogId || !isset($this->benefitAmounts[$requestLogId])) {
return [
'amounts' => array_fill(0, count($this->benefits), 0),
'total' => 0,
];
}
$rows = $this->benefitAmounts[$requestLogId]
->pluck('amount_approved', 'benefit_id')
->toArray();
$amounts = [];
$total = 0;
foreach ($this->benefits as $benefitId => $desc) {
$amount = (float) ($rows[$benefitId] ?? 0);
$amounts[] = $amount;
$total += $amount;
}
// 🔥 kalau ini memang mau jadi grand total global
$this->grandTotal += $total;
return [
'amounts' => $amounts,
'total' => $total,
];
}
protected function initBenefits(): void
{
if ($this->benefitInitialized) {
return;
}
// ambil request_log_id dulu
$requestLogIds = DB::table('invoice_payments')
->leftJoin('invoice_payment_details', 'invoice_payment_details.invoice_payment_id', '=', 'invoice_payments.id')
->leftJoin('claim_requests', 'claim_requests.id', '=', 'invoice_payment_details.claim_request_id')
->whereNotNull('claim_requests.request_log_id')
->pluck('claim_requests.request_log_id')
->unique()
->values();
if ($requestLogIds->isEmpty()) {
$this->benefits = [];
return;
}
$this->benefits = DB::table('request_log_benefits')
->join('benefits', 'benefits.id', '=', 'request_log_benefits.benefit_id')
->whereIn('request_log_benefits.request_log_id', $requestLogIds)
->select('benefits.id', 'benefits.description')
->distinct()
->orderBy('benefits.id')
->pluck('benefits.description', 'benefits.id')
->toArray();
$this->benefitInitialized = true;
}
}