Merge pull request #9 from okorpheus/invoice-pdfs

PDF Invoices Working
This commit is contained in:
Matt 2024-06-29 13:25:55 -05:00 committed by GitHub
commit 54db5136d7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 250 additions and 1 deletions

View File

@ -0,0 +1,143 @@
<?php
namespace App\Http\Controllers;
use App\Models\School;
use App\Services\Invoice\InvoiceDataService;
use Codedge\Fpdf\Fpdf\Fpdf;
use Illuminate\Http\Request;
use function auditionSetting;
class PdfInvoiceController extends Controller
{
protected $pdf;
protected $margin = .3;
protected $entriesPerPage = 45;
protected $invoiceTitle;
protected $paymentAddress;
protected $school;
protected $invoiceDataService;
protected $invoiceData;
/**
* Handle the incoming request.
*/
public function __construct(InvoiceDataService $invoiceDataService)
{
$this->invoiceDataService = $invoiceDataService;
// Set up our PDF
$this->pdf = new Fpdf('P', 'in', 'letter');
$this->pdf->AliasNbPages();
$this->pdf->SetMargins($this->margin, $this->margin);
$this->pdf->SetAutoPageBreak(false);
}
public function __invoke(Request $request, School $school)
{
$this->school = $school;
$this->invoiceData = $this->invoiceDataService->allData($school->id);
$this->invoiceTitle = auditionSetting('auditionAbbreviation').' entry report for '.$this->school->name;
$this->paymentAddress = auditionSetting('auditionName')."\n".
auditionSetting('payment_address')."\n".
auditionSetting('payment_city').', '.auditionSetting('payment_state').' '.auditionSetting('payment_zip');
$this->newInvoicePage();
$this->itemizeEntries();
$this->entryTotals();
if (auditionSetting('school_fee') > 0) {
$this->schoolFee(number_format(auditionSetting('school_fee') / 100, 2));
}
$this->grandTotal();
$this->output();
return redirect()->back();
}
protected function newInvoicePage()
{
$this->pdf->AddPage();
$this->pdf->SetFont('Arial', 'B', 12);
$this->pdf->cell(4, .3, $this->invoiceTitle, 0, 1);
$this->pdf->SetFont('Arial', '', 9);
$this->pdf->cell(4, .1, 'Reflects entries as of '.date('g:i A').' on '.date('F j, Y'), 0, 1);
$this->pdf->cell(4, .15, 'Additional entries may result in additional charges');
$this->pdf->setXY(-3, $this->margin + .45);
$this->pdf->cell(0, 0, 'Page '.$this->pdf->PageNo().' of {nb}', 0, 0, 'R');
$this->pdf->line($this->margin, .6 + $this->margin, 8.5 - $this->margin, .6 + $this->margin);
$this->pdf->setXY($this->margin, $this->margin + .65);
$this->pdf->SetFont('Arial', 'B', 9);
$this->pdf->cell(0, .15, 'SEND PAYMENT TO:', 0, 1);
$this->pdf->SetFont('Arial', '', 9);
$this->pdf->MultiCell(0, .12, $this->paymentAddress);
$this->pdf->setXY($this->margin, $this->margin + 1.4);
$this->pdf->SetFont('Arial', 'B', 9);
$this->pdf->Cell(2.1, .15, 'Student Name', 1);
$this->pdf->Cell(2.1, .15, 'Instrument', 1);
$this->pdf->Cell(1.7, .15, 'Entry Timestamp', 1);
$this->pdf->Cell(1, .15, 'Entry Fee', 1);
$this->pdf->Cell(1, .15, 'Late Fee', 1, 1);
$this->pdf->SetFont('Arial', '', 9);
}
protected function itemizeEntries()
{
$entriesThisPage = 0;
foreach ($this->invoiceData['lines'] as $line) {
if ($entriesThisPage >= $this->entriesPerPage) {
$this->newInvoicePage();
$entriesThisPage = 0;
}
$this->pdf->Cell(2.1, .15, $line['student_name'], 1);
$this->pdf->Cell(2.1, .15, $line['audition'], 1);
$this->pdf->Cell(1.7, .15, $line['entry_timestamp'], 1);
$this->pdf->Cell(1, .15, number_format($line['entry_fee'], 2), 1);
$this->pdf->Cell(1, .15, number_format($line['late_fee'], 2), 1, 1);
$entriesThisPage++;
}
}
protected function entryTotals()
{
$this->pdf->SetFont('Arial', 'B', 9);
$this->pdf->Cell(2.1, .3, '', 0);
$this->pdf->Cell(2.1, .3, '', 0);
$this->pdf->Cell(1.7, .3, 'TOTAL', 1);
$this->pdf->Cell(1, .3, '$'.number_format($this->invoiceData['linesTotal'], 2), 1);
$this->pdf->Cell(1, .3, '$'.number_format($this->invoiceData['lateFeesTotal'], 2), 1, 1);
}
protected function schoolFee($fee)
{
$this->pdf->Cell(2.1, .3, '', 0);
$this->pdf->Cell(2.1, .3, '', 0);
$this->pdf->Cell(1.7, .3, 'SCHOOL FEE', 1);
$this->pdf->Cell(2, .3, '$'.$fee, 1, 1);
}
protected function grandTotal()
{
$this->pdf->Cell(2.1, .3, '', 0);
$this->pdf->Cell(2.1, .3, '', 0);
$this->pdf->Cell(1.7, .3, 'GRAND TOTAL', 1);
$this->pdf->Cell(2, .3, '$'.number_format($this->invoiceData['grandTotal'], 2), 1);
}
public function output($dest = 'D', $name = null)
{
if (! $name) {
$name = auditionSetting('auditionAbbreviation').' Invoice for '.$this->school->name.'.pdf';
$this->pdf->Output($dest, $name);
}
}
}

View File

@ -6,6 +6,7 @@
"license": "MIT", "license": "MIT",
"require": { "require": {
"php": "^8.2", "php": "^8.2",
"codedge/laravel-fpdf": "^1.12",
"laravel/fortify": "^1.21", "laravel/fortify": "^1.21",
"laravel/framework": "^11.0", "laravel/framework": "^11.0",
"laravel/tinker": "^2.9", "laravel/tinker": "^2.9",

69
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "621017524a521b75138e8a946978fb42", "content-hash": "8a539bb700e8acfbb39c896521c16609",
"packages": [ "packages": [
{ {
"name": "bacon/bacon-qr-code", "name": "bacon/bacon-qr-code",
@ -189,6 +189,73 @@
], ],
"time": "2024-02-09T16:56:22+00:00" "time": "2024-02-09T16:56:22+00:00"
}, },
{
"name": "codedge/laravel-fpdf",
"version": "1.12.1",
"source": {
"type": "git",
"url": "https://github.com/codedge/laravel-fpdf.git",
"reference": "9319768852f483ec5a3b00ca19b2157349c88fb9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/codedge/laravel-fpdf/zipball/9319768852f483ec5a3b00ca19b2157349c88fb9",
"reference": "9319768852f483ec5a3b00ca19b2157349c88fb9",
"shasum": ""
},
"require": {
"illuminate/support": "^9.0 || ^10.0 || ^11.0",
"php": "^8.1"
},
"require-dev": {
"ergebnis/composer-normalize": "^2.39",
"orchestra/testbench": "^7.35.0 || ^8.0 || ^9.0",
"phpunit/phpunit": "^9.6.0 || ^10.5"
},
"type": "library",
"extra": {
"laravel": {
"aliases": {
"Fpdf": "Codedge\\Fpdf\\Facades\\Fpdf"
},
"providers": [
"Codedge\\Fpdf\\FpdfServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Codedge\\Fpdf\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Holger Lösken",
"email": "holger.loesken@codedge.de"
}
],
"description": "Laravel package to include Fpdf. It ships with Fpdf 1.86.",
"keywords": [
"fpdf",
"laravel",
"pdf"
],
"support": {
"issues": "https://github.com/codedge/laravel-fpdf/issues",
"source": "https://github.com/codedge/laravel-fpdf"
},
"funding": [
{
"url": "https://github.com/codedge",
"type": "github"
}
],
"time": "2024-03-19T13:25:39+00:00"
},
{ {
"name": "dasprid/enum", "name": "dasprid/enum",
"version": "1.0.5", "version": "1.0.5",

30
config/fpdf.php Normal file
View File

@ -0,0 +1,30 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Default configuration for FPDF
|--------------------------------------------------------------------------
|
| Specify the default values for creating a PDF with FPDF
|
*/
'orientation' => 'P',
'unit' => 'in',
'size' => 'Letter',
'font_path' => env('FPDF_FONTPATH'),
/*
|--------------------------------------------------------------------------
| With Laravel Vapor hosting
|--------------------------------------------------------------------------
|
| If the application is to be hosted in the Laravel Vapor hosting platform,
| a special header needs to be attached to each download response.
|
*/
'useVaporHeaders' => env('FPDF_VAPOR_HEADERS', false),
];

View File

@ -2,6 +2,10 @@
<x-layout.app> <x-layout.app>
<x-slot:page_title>Invoice - {{ $school->name }}</x-slot:page_title> <x-slot:page_title>Invoice - {{ $school->name }}</x-slot:page_title>
<x-slot:title_bar_right>
<x-form.button href="{{ route('pdf_invoice',$school->id) }}">Download PDF Invoice</x-form.button>
</x-slot:title_bar_right>
<div class=""> <div class="">
<x-table.table class=""> <x-table.table class="">
<thead class=""> <thead class="">

View File

@ -3,6 +3,7 @@
// Dashboard Related Routes // Dashboard Related Routes
use App\Http\Controllers\DashboardController; use App\Http\Controllers\DashboardController;
use App\Http\Controllers\EntryController; use App\Http\Controllers\EntryController;
use App\Http\Controllers\PdfInvoiceController;
use App\Http\Controllers\SchoolController; use App\Http\Controllers\SchoolController;
use App\Http\Controllers\StudentController; use App\Http\Controllers\StudentController;
use App\Http\Controllers\UserController; use App\Http\Controllers\UserController;
@ -13,6 +14,7 @@ Route::middleware(['auth', 'verified'])->group(function () {
Route::get('/profile', [DashboardController::class, 'profile'])->name('my_profile'); Route::get('/profile', [DashboardController::class, 'profile'])->name('my_profile');
Route::get('/my_school', [DashboardController::class, 'my_school'])->name('my_school'); Route::get('/my_school', [DashboardController::class, 'my_school'])->name('my_school');
Route::get('/my_invoice', [DashboardController::class, 'my_invoice'])->name('my_invoice'); Route::get('/my_invoice', [DashboardController::class, 'my_invoice'])->name('my_invoice');
Route::get('/pdf-invoice/{school}', PdfInvoiceController::class)->name('pdf_invoice');
}); });
// Entry Related Routes // Entry Related Routes

View File

@ -4,6 +4,7 @@ use App\Http\Controllers\DashboardController;
use App\Http\Controllers\EntryController; use App\Http\Controllers\EntryController;
use App\Http\Controllers\FilterController; use App\Http\Controllers\FilterController;
use App\Http\Controllers\JudgingController; use App\Http\Controllers\JudgingController;
use App\Http\Controllers\PdfInvoiceController;
use App\Http\Controllers\SchoolController; use App\Http\Controllers\SchoolController;
use App\Http\Controllers\StudentController; use App\Http\Controllers\StudentController;
use App\Http\Controllers\Tabulation\DoublerDecisionController; use App\Http\Controllers\Tabulation\DoublerDecisionController;
@ -22,6 +23,7 @@ require __DIR__.'/user.php';
Route::get('/test', [TestController::class, 'flashTest'])->middleware('auth', 'verified'); Route::get('/test', [TestController::class, 'flashTest'])->middleware('auth', 'verified');
Route::view('/', 'welcome')->middleware('guest')->name('home'); Route::view('/', 'welcome')->middleware('guest')->name('home');
Route::get('/results', [App\Http\Controllers\ResultsPage::class, '__invoke'])->name('results'); Route::get('/results', [App\Http\Controllers\ResultsPage::class, '__invoke'])->name('results');