Stubbing invoice design templates

This commit is contained in:
David Bomba 2019-08-29 14:07:04 +10:00
parent b7d9ad1808
commit 668e01b814
11 changed files with 718 additions and 3 deletions

View File

@ -13,6 +13,7 @@ namespace App\Http\Controllers\ClientPortal;
use App\Filters\InvoiceFilters;
use App\Http\Controllers\Controller;
use App\Http\Requests\ClientPortal\ShowInvoiceRequest;
use App\Jobs\Entity\ActionEntity;
use App\Models\Invoice;
use App\Repositories\BaseRepository;
@ -83,10 +84,13 @@ class InvoiceController extends Controller
*
* @return \Illuminate\Http\Response
*/
public function show(Invoice $invoice)
public function show(ShowInvoiceRequest $request, Invoice $invoice)
{
$data = [
'invoice' => $invoice
];
return view('portal.default.invoices.show', $invoice);
}
/**

View File

@ -0,0 +1,30 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com)
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2019. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Http\Requests\ClientPortal;
use App\Http\Requests\Request;
use App\Models\Invoice;
class ShowInvoiceRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize() : bool
{
return auth()->user()->client->id === $this->invoice->client_id;
}
}

View File

@ -0,0 +1,75 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com)
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2019. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Listeners\Invoice;
use App\Utils\Traits\MakesHash;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Storage;
use Spatie\Browsershot\Browsershot;
class CreateInvoicePdf
{
protected $activity_repo;
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
}
/**
* Handle the event.
*
* @param object $event
* @return void
*/
public function handle($event)
{
$invoice = $event->invoice;
$path = $invoice->client->client_hash . '/invoices/';
$file = $path . $invoice->invoice_number . '.pdf';
//get invoice template
$html = $this->generateInvoiceHtml($invoice->settings->template, $invoice)
//todo - move this to the client creation stage so we don't keep hitting this unnecessarily
Storage::makeDirectory('public/' . $path, 0755);
//create pdf
$this->makePdf(null,null,$html,$file)
//store pdf
//$path = Storage::putFile('public/' . $path, $this->file);
//$url = Storage::url($path);
}
private function makePdf($header, $footer, $html, $pdf)
{
Browsershot::html($html)
//->showBrowserHeaderAndFooter()
//->headerHtml($header)
//->footerHtml($footer)
->waitUntilNetworkIdle()
//->margins(10,10,10,10)
->savePdf($pdf);
}
private function generateInvoiceHtml($template, $invoice)
{
}
}

View File

@ -17,4 +17,13 @@ class Country extends Model
{
public $timestamps = false;
/**
* Localizes the country name for the clients language.
*
* @return string The translated country name
*/
public function getName() :string
{
return trans('texts.country_' . $this->name);
}
}

View File

@ -19,6 +19,7 @@ use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Log;
use Laracasts\Presenter\PresentableTrait;
class Invoice extends BaseModel
{
@ -26,6 +27,9 @@ class Invoice extends BaseModel
use Filterable;
use NumberFormatter;
use MakesDates;
use PresentableTrait;
protected $presenter = 'App\Models\Presenters\InvoicePresenter';
protected $hidden = [
'id',

View File

@ -113,6 +113,22 @@ class EntityPresenter extends Presenter
}
}
public function getShippingCityState()
{
$client = $this->entity;
$swap = $client->shipping_country && $client->shipping_country->swap_postal_code;
$city = e($client->shipping_city);
$state = e($client->shipping_state);
$postalCode = e($client->shipping_postal_code);
if ($city || $state || $postalCode) {
return $this->cityStateZip($city, $state, $postalCode, $swap);
} else {
return false;
}
}
public function cityStateZip($city, $state, $postalCode, $swap)
{
$str = $city;

View File

@ -0,0 +1,43 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com)
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2019. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Models\Presenters;
/**
* Class InvoicePresenter
*
* For convenience and to allow users to easiliy
* customise their invoices, we provide all possible
* invoice variables to be available from this presenter.
*
* Shortcuts to other presenters are here to facilitate
* a clean UI / UX
*
* @package App\Models\Presenters
*/
class InvoicePresenter extends EntityPresenter
{
public function clientName()
{
return $this->client->present()->name();
}
public function address()
{
return $this->client->present()->address();
}
pubic function shipping_address()
{
return $this->client->present()->shipping_address();
}
}

View File

@ -24,6 +24,7 @@ use App\Listeners\Activity\PaymentCreatedActivity;
use App\Listeners\Contact\UpdateContactLastLogin;
use App\Listeners\Invoice\CreateInvoiceActivity;
use App\Listeners\Invoice\CreateInvoiceInvitations;
use App\Listeners\Invoice\CreateInvoicePdf;
use App\Listeners\Invoice\UpdateInvoiceActivity;
use App\Listeners\SendVerificationNotification;
use App\Listeners\User\UpdateUserLastLogin;
@ -76,9 +77,11 @@ class EventServiceProvider extends ServiceProvider
],
InvoiceWasUpdated::class => [
UpdateInvoiceActivity::class,
CreateInvoicePdf::class,
],
InvoiceWasCreated::class => [
CreateInvoiceActivity::class,
CreateInvoicePdf::class,
],
];

View File

@ -0,0 +1,515 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>A simple, clean, and responsive HTML invoice template</title>
<style>
html {
-webkit-print-color-adjust: exact;
}
.invoice-box {
max-width: 800px;
margin: auto;
padding: 30px;
border: 1px solid #eee;
box-shadow: 0 0 10px rgba(0, 0, 0, .15);
font-size: 16px;
line-height: 24px;
font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;
color: #555;
}
.invoice-box table {
width: 100%;
line-height: inherit;
text-align: left;
}
.invoice-box table td {
padding: 5px;
vertical-align: top;
}
.invoice-box table tr td:nth-child(2) {
text-align: right;
}
.invoice-box table tr.top table td {
padding-bottom: 20px;
}
.invoice-box table tr.top table td.title {
font-size: 45px;
line-height: 45px;
color: #333;
}
.invoice-box table tr.information table td {
padding-bottom: 40px;
}
.invoice-box table tr.heading td {
background: #eee;
border-bottom: 1px solid #ddd;
font-weight: bold;
}
.invoice-box table tr.details td {
padding-bottom: 20px;
}
.invoice-box table tr.item td{
border-bottom: 1px solid #eee;
}
.invoice-box table tr.item.last td {
border-bottom: none;
}
.invoice-box table tr.total td:nth-child(2) {
border-top: 2px solid #eee;
font-weight: bold;
}
@media only screen and (max-width: 600px) {
.invoice-box table tr.top table td {
width: 100%;
display: block;
text-align: center;
}
.invoice-box table tr.information table td {
width: 100%;
display: block;
text-align: center;
}
}
/** RTL **/
.rtl {
direction: rtl;
font-family: Tahoma, 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;
}
.rtl table {
text-align: right;
}
.rtl table tr td:nth-child(2) {
text-align: left;
}
</style>
</head>
<body>
<div class="invoice-box">
<table cellpadding="0" cellspacing="0">
<tr class="top">
<td colspan="2">
<table>
<tr>
<td class="title">
<img src="https://www.sparksuite.com/images/logo.png" style="width:100%; max-width:300px;">
</td>
<td>
Invoice #: {{ $invoice->invoice_number }}<br>
Created: {{ $invoice->invoice_date }}<br>
Due: {{ $invoice->due_date }}
</td>
</tr>
</table>
</td>
</tr>
<tr class="information">
<td colspan="2">
<table>
<tr>
<td>
Sparksuite, Inc.<br>
12345 Sunny Road<br>
Sunnyville, CA 12345
</td>
<td>
Acme Corp.<br>
John Doe<br>
john@example.com
</td>
</tr>
</table>
</td>
</tr>
</table>
<table cellpadding="0" cellspacing="0">
<thead>
<tr class="heading">
<td>
Item
</td>
<td>
Price
</td>
</tr>
</thead>
<tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr>
<tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr> <tr class="item">
<td>
Website design
</td>
<td>
$300.00
</td>
</tr>
<tr class="item">
<td>
Hosting (3 months)
</td>
<td>
$75.00
</td>
</tr>
<tr class="item last">
<td>
Domain name (1 year)
</td>
<td>
$10.00
</td>
</tr>
<tr class="total">
<td></td>
<td>
Total: $385.00
</td>
</tr>
</table>
</div>
</body>
</html>

View File

@ -0,0 +1,14 @@
@extends('portal.default.layouts.master')
@section('body')
<main class="main">
<div class="container-fluid">
<object id="pdfObject" type="application/pdf" style="display:block;background-color:#525659;border:solid 2px #9a9a9a;" frameborder="1" width="100%" height="1180px"></object>
<div id="pdfCanvas" style="display:none;width:100%;background-color:#525659;border:solid 2px #9a9a9a;padding-top:40px;text-align:center">
<canvas id="theCanvas" style="max-width:100%;border:solid 1px #CCCCCC;"></canvas>
</div>
</div>
</main>
</body>
@endsection

View File

@ -18,6 +18,8 @@ Route::group(['middleware' => ['auth:contact'], 'prefix' => 'client', 'as' => 'c
Route::get('invoices', 'ClientPortal\InvoiceController@index')->name('invoices.index');
Route::post('invoices/payment', 'ClientPortal\InvoiceController@bulk')->name('invoices.bulk');
Route::get('invoice/{invoice}', 'ClientPortal\InvoiceController@show')->name('invoice.show');
Route::get('invoice/{invoice_invitation}', 'ClientPortal\InvoiceController@show')->name('invoice.show_invitation');
Route::get('recurring_invoices', 'ClientPortal\RecurringInvoiceController@index')->name('recurring_invoices.index');