Link to home
Start Free TrialLog in
Avatar of zack tim
zack timFlag for Morocco

asked on

How to add printing functionality to laravel form

Hello Experts,


I'm using Laravel 8


I have this git repo project https://github.com/webdev866/vouchermanager


When I create a Voucher, I would like to have the functionality to print it.


Example in the screenshot.


What is the best solution to achieve this?


User generated image

Avatar of Michel Plungjan
Michel Plungjan
Flag of Denmark image

If you can create the voucher HTML as a div, you can use one of these
https://stackoverflow.com/questions/2255291/print-the-contents-of-a-div

I prefer the one where your CSS uses a media print directive: https://developer.mozilla.org/en-US/docs/Web/CSS/@media#print
To add what Michel has provided https://developer.mozilla.org/en-US/docs/Web/Guide/Printing  You have an option to send the page with the print media query directly to the users print options as if they selected File->Print and are left with options for selecting printers. 
Hello zack,
are you interessted in downloading a PDF from your show-voucher page?
User generated image

I have problems fetching the voucher values to PDF but if you are interested then I will look into it.

The PDF looks so far also strange but I think we can handle that:
voucher (2).pdf





Avatar of zack tim

ASKER

Hello Zvonko, how are you doing :)

It's exactly what I want, some experts suggested to use css to print the data... can we fetch it with php from the DB
You can create a pdf on the server side, but it is easy enough to do it on the client side with jsbpdf

https://artskydj.github.io/jsPDF/docs/index.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>test</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.5.3/jspdf.debug.js" integrity="sha384-NaWTHo/8YCBYJ59830LTz/P4aQZK1sS0SneOgAvhsIl3zBu8r9RevNg5lHCHAuQ/" crossorigin="anonymous"></script>


  <script>
var doc = new jsPDF()


doc.text('Hello world!', 10, 10)
doc.save('a4.pdf')
 
  </script>
  </head>
<body>


</body>
</html>

Open in new window


Another is htmltodpf https://github.com/eKoopmans/html2pdf.js 

You just need to recreate what you want for this specific purpose. The nice thing about doing this client side is it does not consume resources like it could server side.
Hello Scott, I guess your suggested idea is more useful and practical than processing the printing job on the server side.

@Zvonko, can we go Scott's route since JS is involved within the code?
it's your choice.

But always keep in mind that you can only maintain those code that you can master.
Do you master PHP and JavaScript?
I don't master JS unfortunately, I'm trying my best on PHP, I want to achieve it with the least overhead
My soulution is pure PHP.
...but I am still learning Laravel. At the moment I am not able to pass Voucher id to pdfprint controller.

Are you interested in my solution?

Yes Zvonko, let's try it
OK, here we go!
I have used this guid to collect all steps that you need to generate PDF from Laravel:
https://www.itsolutionstuff.com/post/laravel-8-pdf-laravel-8-generate-pdf-file-using-dompdfexample.html

So this are the steps:

1.) Install dompdf package by entering following on your Laragon console:
C:\laragon\www\app>composer require barryvdh/laravel-dompdf

2:) Add dompdf in your config/app.php
'providers' => [
...
/*
         * Package Service Providers...
         */
      Barryvdh\DomPDF\ServiceProvider::class,
     
'aliases' => [
...
      'PDF' => Barryvdh\DomPDF\Facade::class,

Open in new window


3.)  Add getpdf route in routes/web.php 
// Create Voucher
   Route::get('create-vouchers/getpdf/{id}', 'CreateVoucherController@getpdf')->name('create-vouchers.getpdf');

Open in new window


4.) Add getpdf Controller in C:\laragon\www\app\app\Http\Controllers\Admin\CreateVoucherController.php
    public function getpdf($VoucherId)
    {
      abort_if(Gate::denies('create_voucher_show'), Response::HTTP_FORBIDDEN, '403 Forbidden');
      
      $createVoucher = CreateVoucher::findOrFail($VoucherId);

      $createVoucher->load('agent', 'client', 'hotel_name');
      
      $pdf = PDF::loadView('admin.createVouchers.getpdf', compact('createVoucher'));
      
      return $pdf->download('voucher.pdf');
    }

Open in new window


5.) Add this layout for print header to following location:
C:\laragon\www\app\resources\views\layouts\print.blade.php
print.blade.php

6.) Add this PDF html template to following location:
C:\laragon\www\app\resources\views\admin\createVouchers\getpdf.blade.php
getpdf.blade.php

Now test it and tell me what I have missed  :  )


I forgot one step: you have to create one folder manualy:

C:\laragon\www\app\storage\fonts


Thank you very much for your efforts.

I don't see a print button to execute it, can you test
Sorry I missed that file with the button.
The Button ist labeled: PDF
The file is located here:
C:\laragon\www\app\resources\views\admin\createVouchers\show.blade.php

show.blade.php

Hello Zvonko,

I got this error

Error    Class 'App\Http\Controllers\Admin\PDF' not found


             http://la5.test/admin/create-vouchers/getpdf/1        

Open in new window



I found the issue, On CreateVoucherController I must add
use Barryvdh\DomPDF\Facade\Pdf;

Open in new window

I guess now I can customize the generated pdf from print.blade.php ?
Sorry missed that too.
In this file:
C:\laragon\www\app\app\Http\Controllers\Admin\CreateVoucherController.php

add this:
use PDF;

You can change the look of PDF file in this template file:
C:\laragon\www\app\resources\views\admin\createVouchers\getpdf.blade.php

And in this file you can change the style of the PDF header and content:
C:\laragon\www\app\resources\views\layouts\print.blade.php

For example, to change the hight of the PDF content area change this:

        <div class="content-wrapper" style="min-height: 928px;">
            @yield('content')
        </div>




Hello zack, is your PDF created now?
ASKER CERTIFIED SOLUTION
Avatar of Zvonko
Zvonko
Flag of North Macedonia image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Hello Zvonko how are you doing, I have few issues with the template, please save the following code in an html file along with css and run it.
now i have updated the print.blade.php but the layout looks not good I don't know why:
HTML

<html>

<head>
    <meta charset="utf-8">
    <title>VOUCHER</title>
    <link rel="stylesheet" href="css/mycss.css">
    <link rel="license" href="https://www.opensource.org/licenses/mit-license/">

</head>

<body>
    <center><span><img alt="" src="logo-invoice.png"></span></center>
    <header>

        <h1>VOUCHER</h1>
        <address contenteditable>
            <p>Guest's Name: {{ $createVoucher->client->fullname ?? '' }}</p>
            <p>Arrival Date: {{ $createVoucher->arrival_date_and_time }} </p>
            <p>Departure Date:{{ $createVoucher->departuredate }}</p>
        </address>




    </header>
    <article>
        <h1>Recipient</h1>
        <address contenteditable>
            <p><br>AGENCY</p>
        </address>
        <table class="meta">
            <tr>
                <th><span contenteditable>Voucher #</span></th>
                <td><span contenteditable> {{ $createVoucher->id }} </span></td>
            </tr>
            <tr>
                <th><span contenteditable>Date</span></th>
                <td><span contenteditable></span></td>
            </tr>
            <tr>
                <th><span contenteditable>Total</span></th>
                <td><span id="prefix" contenteditable>MAD {{ $createVoucher->total_amount }}</span><span></span></td>
            </tr>
        </table>
        <table class="inventory">
            <thead>
                <tr>
                    <th><span contenteditable>Hotel</span></th>
                    <th><span contenteditable>No Of Nights</span></th>
                    <th><span contenteditable>Rate Per Night</span></th>
                    <th><span contenteditable>Room Type</span></th>
                    <th><span contenteditable>Rooms</span></th>
                    <th><span contenteditable>Payment Method</span></th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td><a class="cut">-</a> {{ $createVoucher->hotel_name->hotel_name ?? '' }}<span contenteditable></span></td>
                    <td><span contenteditable>{{ $createVoucher->night }}</span></td>
                    <td><span data-prefix>MAD {{ $createVoucher->room_price }}</span><span contenteditable></span></td>
                    <td><span contenteditable>{{ App\CreateVoucher::ROOM_TYPE_SELECT[$createVoucher->room_type] ?? '' }}</span></td>
                    <td><span data-prefix>{{ $createVoucher->number_of_room }}</span><span></span></td>
                    <td><span contenteditable> {{ App\CreateVoucher::PAYMENT_MODE_SELECT[$createVoucher->payment_mode] ?? '' }}</span></td>
                </tr>
            </tbody>
        </table>

        <table class="balance">
            <tr>
                <th><span contenteditable>Total</span></th>
                <td><span data-prefix>$</span><span>600.00</span></td>
            </tr>
            <tr>
                <th><span contenteditable>Amount Paid</span></th>
                <td><span data-prefix>$</span><span contenteditable>0.00</span></td>
            </tr>
            <tr>
                <th><span contenteditable>Balance Due</span></th>
                <td><span data-prefix>$</span><span>600.00</span></td>
            </tr>
        </table>
    </article>
    <aside>
        <h1><span contenteditable>Observation</span></h1>
        <p>{{ $createVoucher->observation }}</p>

    </aside>
</body>

</html>



Open in new window

CSS

/* reset */

* {
    border: 0;
    box-sizing: content-box;
    color: inherit;
    font-family: inherit;
    font-size: inherit;
    font-style: inherit;
    font-weight: inherit;
    line-height: inherit;
    list-style: none;
    margin: 0;
    padding: 0;
    text-decoration: none;
    vertical-align: top;
}


/* content editable */

*[contenteditable] {
    border-radius: 0.25em;
    min-width: 1em;
    outline: 0;
}

*[contenteditable] {
    cursor: pointer;
}

*[contenteditable]:hover,
*[contenteditable]:focus,
td:hover *[contenteditable],
td:focus *[contenteditable],
img.hover {
    background: #DEF;
    box-shadow: 0 0 1em 0.5em #DEF;
}

span[contenteditable] {
    display: inline-block;
}


/* heading */

h1 {
    font: bold 100% sans-serif;
    letter-spacing: 0.5em;
    text-align: center;
    text-transform: uppercase;
}


/* table */

table {
    font-size: 75%;
    table-layout: fixed;
    width: 100%;
}

table {
    border-collapse: separate;
    border-spacing: 2px;
}

th,
td {
    border-width: 1px;
    padding: 0.5em;
    position: relative;
    text-align: left;
}

th,
td {
    border-radius: 0.25em;
    border-style: solid;
}

th {
    background: #EEE;
    border-color: #BBB;
}

td {
    border-color: #DDD;
}


/* page */

html {
    font: 16px/1 'Open Sans', sans-serif;
    overflow: auto;
    padding: 0.5in;
}

html {
    background: #999;
    cursor: default;
}

body {
    box-sizing: border-box;
    height: 11in;
    margin: 0 auto;
    overflow: hidden;
    padding: 0.5in;
    width: 8.5in;
}

body {
    background: #FFF;
    border-radius: 1px;
    box-shadow: 0 0 1in -0.25in rgba(0, 0, 0, 0.5);
}


/* header */

header {
    margin: 0 0 3em;
}

header:after {
    clear: both;
    content: "";
    display: table;
}

header h1 {
    background: #000;
    border-radius: 0.25em;
    color: #FFF;
    margin: 0 0 1em;
    padding: 0.5em 0;
}

header address {
    float: left;
    font-size: 75%;
    font-style: normal;
    line-height: 1.25;
    margin: 0 1em 1em 0;
}

header address p {
    margin: 0 0 0.25em;
}

header span,
header img {
    display: block;
    float: right;
}

header span {
    margin: 0 0 1em 1em;
    max-height: 25%;
    max-width: 60%;
    position: relative;
}

header img {
    max-height: 100%;
    max-width: 100%;
}

header input {
    cursor: pointer;
    -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
    height: 100%;
    left: 0;
    opacity: 0;
    position: absolute;
    top: 0;
    width: 100%;
}


/* article */

article,
article address,
table.meta,
table.inventory {
    margin: 0 0 3em;
}

article:after {
    clear: both;
    content: "";
    display: table;
}

article h1 {
    clip: rect(0 0 0 0);
    position: absolute;
}

article address {
    float: left;
    font-size: 125%;
    font-weight: bold;
}


/* table meta & balance */

table.meta,
table.balance {
    float: right;
    width: 36%;
}

table.meta:after,
table.balance:after {
    clear: both;
    content: "";
    display: table;
}


/* table meta */

table.meta th {
    width: 40%;
}

table.meta td {
    width: 60%;
}


/* table items */

table.inventory {
    clear: both;
    width: 100%;
}

table.inventory th {
    font-weight: bold;
    text-align: center;
}

table.inventory td:nth-child(1) {
    width: 26%;
}

table.inventory td:nth-child(2) {
    width: 38%;
}

table.inventory td:nth-child(3) {
    text-align: right;
    width: 12%;
}

table.inventory td:nth-child(4) {
    text-align: right;
    width: 12%;
}

table.inventory td:nth-child(5) {
    text-align: right;
    width: 12%;
}


/* table balance */

table.balance th,
table.balance td {
    width: 50%;
}

table.balance td {
    text-align: right;
}


/* aside */

aside h1 {
    border: none;
    border-width: 0 0 1px;
    margin: 0 0 1em;
}

aside h1 {
    border-color: #999;
    border-bottom-style: solid;
}


/* javascript */

.add,
.cut {
    border-width: 1px;
    display: block;
    font-size: .8rem;
    padding: 0.25em 0.5em;
    float: left;
    text-align: center;
    width: 0.6em;
}

.add,
.cut {
    background: #9AF;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
    background-image: -moz-linear-gradient(#00ADEE 5%, #0078A5 100%);
    background-image: -webkit-linear-gradient(#00ADEE 5%, #0078A5 100%);
    border-radius: 0.5em;
    border-color: #0076A3;
    color: #FFF;
    cursor: pointer;
    font-weight: bold;
    text-shadow: 0 -1px 2px rgba(0, 0, 0, 0.333);
}

.add {
    margin: -2.5em 0 0;
}

.add:hover {
    background: #00ADEE;
}

.cut {
    opacity: 0;
    position: absolute;
    top: 0;
    left: -1.5em;
}

.cut {
    -webkit-transition: opacity 100ms ease-in;
}

tr:hover .cut {
    opacity: 1;
}

@media print {
    * {
        -webkit-print-color-adjust: exact;
    }
    html {
        background: none;
        padding: 0;
    }
    body {
        box-shadow: none;
        margin: 0;
    }
    span:empty {
        display: none;
    }
    .add,
    .cut {
        display: none;
    }
}

@page {
    margin: 0;
}



Open in new window

My Result:

User generated image
Expected result:
User generated image

can you help @Zvonko
Of course I can zack  :  )

I am so happy that I performed this dance with the children and the mayor at the street festival in my town today and everything went smoothly:
 https://groebenzell-ist-bunt.de/2022/jerusalema_live.mp4
The guy with the mic on the far left side of the stage is me :-)


Back to your Question. From your screenshot I see that you sucseeded in getting your PHP to produce a PDF file. Is that correct? If the answer is "yes" then I expect that you say "thank you" for this question. The other one or two solution for your next challenges we can handle either in some fresh Questions or in one EE Live Session  :  )

in this file:
C:\laragon\www\app\public\css\mycss.css

change this:
body {
    box-sizing: border-box;
    height: 11in;
    margin: 0 auto;
    overflow: hidden;
    padding: 0.5in;
    max-width: 8.5in;
}

Add this file:
C:\laragon\www\app\public\logo-invoice.png
logo-invoice.png


I really liked the dance Zvonko, that's great, you seem to be having good times with the kids, it makes me happy too :)

Well, 'thank you' is not enough because you've been spending alot of time helping me, so maybe a THANK YOUUUUUU in capital is a good one :)

Okay, I will mark this as a solution and will open a new question

THANKS ALOT
Thank you Zack, it was a pleasure for me <|:-)