feat: add reporit
This commit is contained in:
parent
6dd24df259
commit
2397e1ed7e
@ -5,6 +5,7 @@ namespace App\Filament\Resources\TrTransaksiResource\Pages;
|
||||
use App\Filament\Resources\TrTransaksiResource;
|
||||
use Filament\Actions;
|
||||
use Filament\Resources\Pages\ViewRecord;
|
||||
use Torgodly\Html2Media\Actions\Html2MediaAction;
|
||||
|
||||
class ViewTrTransaksi extends ViewRecord
|
||||
{
|
||||
@ -26,6 +27,23 @@ class ViewTrTransaksi extends ViewRecord
|
||||
})->visible(function ($record) {
|
||||
return $record->status == 'pending';
|
||||
}),
|
||||
Html2MediaAction::make('print')
|
||||
->scale(2)
|
||||
->print() // Enable print option
|
||||
->preview()
|
||||
->filename(function ($record) {
|
||||
return 'invoice-' . $record->id_transaksi . '.pdf';
|
||||
})
|
||||
->content(function ($record) {
|
||||
return view('components.pdf.invoice-detail', ['record' => $record]);
|
||||
})
|
||||
->savePdf() // Enable save as PDF option
|
||||
->requiresConfirmation() // Show confirmation modal
|
||||
->pagebreak('section', ['css', 'legacy'])
|
||||
->orientation('portrait') // Portrait orientation
|
||||
->format('a4', 'mm') // A4 format with mm units
|
||||
->enableLinks() // Enable links in PDF
|
||||
->margin([25, 50, 0, 50]) //
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,17 +15,21 @@ class StatsOverview extends BaseWidget
|
||||
protected function getStats(): array
|
||||
{
|
||||
return [
|
||||
Stat::make('Total Pasien', TrRegistrasi::count())
|
||||
->description(new HtmlString('<a class="underline" href="' . TrRegistrasiResource::getUrl('index') . '">Lihat Semua Pasien</a>')),
|
||||
// total pasien hari ini, deskripsi jumlah keseluruhan pasien dengan link ke halaman pasien
|
||||
Stat::make('Total Pasien Hari Ini', TrRegistrasi::whereDate('tgl_registrasi', now()->toDateString())->count())
|
||||
->description(new HtmlString(
|
||||
'Jumlah keseluruhan ' . TrRegistrasi::count() . ' pasien'
|
||||
. '<br/><a class="underline" href="' . TrRegistrasiResource::getUrl('index') . '"> Lihat Semua Pasien</a>'
|
||||
)),
|
||||
|
||||
// total tagihan, deskripsi jumlah keseluruhan tagihan dengan link ke halaman tagihan
|
||||
Stat::make('Total Pendapatan Hari Ini', 'Rp ' . number_format(TrTransaksi::whereDate('created_at', now()->toDateString())->where('status', 'paid')->sum('total_harga'), 0, ',', '.'))
|
||||
->description(new HtmlString(
|
||||
'Jumlah keseluruhan <strong>Rp.' . number_format(TrTransaksi::where('status', 'paid')->sum('total_harga'), 0, ',', '.') . '</strong> tagihan'
|
||||
. '<br/><a class="underline" href="' . TrTransaksiResource::getUrl('index') . '"> Lihat Semua Tagihan</a>'
|
||||
)),
|
||||
|
||||
// section 2
|
||||
//
|
||||
Stat::make('Total Tagihan', 'Rp ' . number_format(TrTransaksi::sum('total_harga'), 0, ',', '.'))
|
||||
->description(new HtmlString('<a class="underline" href="' . TrTransaksiResource::getUrl('index') . '">Lihat Semua Tagihan</a>')),
|
||||
|
||||
// Registrasi yang belum ada transaksi
|
||||
Stat::make('Total Pasien Belum Ada Transaksi', TrRegistrasi::whereDoesntHave('transaksi')->count())
|
||||
->description(new HtmlString('<a class="underline" href="' . TrRegistrasiResource::getUrl('index') . '">Lihat Semua Pasien Belum Ada Transaksi</a>')),
|
||||
|
||||
];
|
||||
}
|
||||
|
||||
@ -9,7 +9,8 @@
|
||||
"php": "^8.2",
|
||||
"filament/filament": "^3.3",
|
||||
"laravel/framework": "^11.31",
|
||||
"laravel/tinker": "^2.9"
|
||||
"laravel/tinker": "^2.9",
|
||||
"torgodly/html2media": "^1.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"fakerphp/faker": "^1.23",
|
||||
|
||||
61
composer.lock
generated
61
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "b10697b45fe4a086f6982a8e9998fea8",
|
||||
"content-hash": "53b21f71a3004eddc3866a7af901cea9",
|
||||
"packages": [
|
||||
{
|
||||
"name": "anourvalar/eloquent-serialize",
|
||||
@ -7241,6 +7241,65 @@
|
||||
},
|
||||
"time": "2024-12-21T16:25:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "torgodly/html2media",
|
||||
"version": "1.1.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/torgodly/Html2Media.git",
|
||||
"reference": "58c31b08fc46fa2dbf307e7bf88d833c4d933c05"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/torgodly/Html2Media/zipball/58c31b08fc46fa2dbf307e7bf88d833c4d933c05",
|
||||
"reference": "58c31b08fc46fa2dbf307e7bf88d833c4d933c05",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"filament/filament": "^3.0",
|
||||
"php": "^8.1"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Torgodly\\Html2Media\\Html2MediaServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Torgodly\\Html2Media\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Abdullah Alhaj",
|
||||
"email": "torgodly@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Html2Media is a versatile Laravel package that allows users to convert HTML content into high-quality PDFs with options for either downloading or triggering a print dialog. Ideal for generating documents, invoices, and reports, this package includes configurable settings for file name, page orientation, format, margins, and scale. Html2Media also provides seamless integration with Filament actions, enabling dynamic content rendering in modals and customizable output previews. Whether you need to save a PDF or send it directly to the printer, Html2Media simplifies the process with robust, flexible features.",
|
||||
"keywords": [
|
||||
"documents",
|
||||
"filament",
|
||||
"html-to-pdf",
|
||||
"invoice",
|
||||
"laravel",
|
||||
"pdf",
|
||||
"pdf-generation",
|
||||
"printing",
|
||||
"reporting"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/torgodly/Html2Media/issues",
|
||||
"source": "https://github.com/torgodly/Html2Media/tree/1.1.4"
|
||||
},
|
||||
"time": "2025-03-15T22:59:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "vlucas/phpdotenv",
|
||||
"version": "v5.6.1",
|
||||
|
||||
97
public/js/html2media/html2pdf-script.js
Normal file
97
public/js/html2media/html2pdf-script.js
Normal file
@ -0,0 +1,97 @@
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
Livewire.on('triggerPrint', function (options = {}) {
|
||||
console.log('triggerPrint', options);
|
||||
|
||||
performAction(options);
|
||||
});
|
||||
});
|
||||
|
||||
function performAction({ action = 'print', element, ...customOptions } = {}) {
|
||||
const printElement = document.getElementById(`print-smart-content-${element}`);
|
||||
|
||||
// Default options for html2pdf
|
||||
const defaultOptions = {
|
||||
filename: 'document.pdf',
|
||||
pagebreak: {
|
||||
mode: ['css', 'legacy'],
|
||||
after: 'section'
|
||||
},
|
||||
jsPDF: {
|
||||
unit: 'mm',
|
||||
format: 'a4',
|
||||
orientation: 'portrait'
|
||||
},
|
||||
html2canvas: {
|
||||
scale: 2,
|
||||
useCORS: true,
|
||||
logging: true
|
||||
},
|
||||
margin: 0
|
||||
};
|
||||
|
||||
// Merge custom options with defaults
|
||||
const options = {
|
||||
...defaultOptions,
|
||||
...customOptions,
|
||||
pagebreak: {
|
||||
...defaultOptions.pagebreak,
|
||||
...(customOptions.pagebreak || {})
|
||||
},
|
||||
jsPDF: {
|
||||
...defaultOptions.jsPDF,
|
||||
...(customOptions.jsPDF || {})
|
||||
},
|
||||
html2canvas: {
|
||||
...defaultOptions.html2canvas,
|
||||
...(customOptions.html2canvas || {})
|
||||
}
|
||||
};
|
||||
|
||||
if (printElement) {
|
||||
switch (action) {
|
||||
case 'savePdf':
|
||||
// Save as PDF
|
||||
html2pdf()
|
||||
.from(printElement)
|
||||
.set(options)
|
||||
.save();
|
||||
break;
|
||||
case 'print':
|
||||
// Print action
|
||||
html2pdf()
|
||||
.from(printElement)
|
||||
.set(options)
|
||||
.toPdf()
|
||||
.get('pdf')
|
||||
.then(function (pdf) {
|
||||
const blob = pdf.output('blob');
|
||||
const url = URL.createObjectURL(blob);
|
||||
const iframe = document.getElementById(`print-smart-iframe-${element}`);
|
||||
iframe.src = url;
|
||||
|
||||
iframe.onload = function () {
|
||||
iframe.contentWindow.focus();
|
||||
iframe.contentWindow.print();
|
||||
iframe.contentWindow.onafterprint = function () {
|
||||
URL.revokeObjectURL(url);
|
||||
};
|
||||
};
|
||||
});
|
||||
break;
|
||||
default:
|
||||
console.error('Unsupported action:', action);
|
||||
}
|
||||
} else {
|
||||
console.error(`Element with ID "print-smart-content-${element}" not found.`);
|
||||
}
|
||||
}
|
||||
|
||||
function replaceSpacesInTextNodes(element) {
|
||||
element.childNodes.forEach(node => {
|
||||
if (node.nodeType === Node.TEXT_NODE && node.textContent.trim() !== '') {
|
||||
node.textContent = node.textContent.replace(/\s/g, "\u00a0");
|
||||
} else if (node.nodeType === Node.ELEMENT_NODE) {
|
||||
replaceSpacesInTextNodes(node);
|
||||
}
|
||||
});
|
||||
}
|
||||
90
resources/views/components/pdf/invoice-detail.blade.php
Normal file
90
resources/views/components/pdf/invoice-detail.blade.php
Normal file
@ -0,0 +1,90 @@
|
||||
<div>
|
||||
<div>
|
||||
<title>Laporan Transaksi Pasien</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 12px;
|
||||
margin: 20px;
|
||||
}
|
||||
.header {
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.patient-info, .transaction-info {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
table th, table td {
|
||||
border: 1px solid #000;
|
||||
padding: 6px;
|
||||
text-align: left;
|
||||
}
|
||||
.grand-total {
|
||||
text-align: right;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="header">
|
||||
<h2>Rumah Sakit Sehat Sentosa</h2>
|
||||
<p>Laporan Transaksi Pasien</p>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="patient-info">
|
||||
<h4>Informasi Pasien</h4>
|
||||
<p><strong>Nama:</strong> {{ $record->pasien->nama }}</p>
|
||||
<p><strong>Tanggal Lahir:</strong> {{ \Carbon\Carbon::parse($record->pasien->tgl_lahir)->format('d-m-Y') }}</p>
|
||||
<p><strong>Jenis Kelamin:</strong> {{ ucfirst($record->pasien->jenis_kelamin) }}</p>
|
||||
<p><strong>No Kartu Asuransi:</strong> {{ $record->registrasi->nomor_kartu_asuransi }}</p>
|
||||
<p><strong>Asuransi:</strong> {{ $record->registrasi->asuransi->nama_asuransi }}</p>
|
||||
</div>
|
||||
|
||||
<div class="transaction-info">
|
||||
<h4>Informasi Registrasi</h4>
|
||||
<p><strong>Tanggal Registrasi:</strong> {{ \Carbon\Carbon::parse($record->registrasi->tgl_registrasi)->format('d-m-Y') }}</p>
|
||||
<p><strong>Ruang Pelayanan:</strong> {{ $record->registrasi->ruangPelayanan->nama_ruang_pelayanan }}</p>
|
||||
</div>
|
||||
|
||||
<div class="transaction-detail">
|
||||
<h4>Detail Tindakan</h4>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>No</th>
|
||||
<th>Nama Tindakan</th>
|
||||
<th>Tarif</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@php
|
||||
$grandTotal = 0;
|
||||
@endphp
|
||||
@foreach ($record->id_tindakan as $index => $item)
|
||||
|
||||
@php
|
||||
$tindakan = \App\Models\MsTindakan::find($item);
|
||||
$grandTotal += $tindakan->tarif_tindakan;
|
||||
@endphp
|
||||
<tr>
|
||||
<td>{{ $index + 1 }}</td>
|
||||
<td>{{ $tindakan->nama_tindakan }}</td>
|
||||
<td>Rp {{ number_format($tindakan->tarif_tindakan, 0, ',', '.') }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p class="grand-total">Grand Total: Rp {{ number_format($grandTotal, 0, ',', '.') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user