asked on
How to implement hide or display price when printing voucher to PDF
Hi Experts,
I have a create-voucher model and I would like to add the possibility to display and hide the price of the room on the voucher when printed only
My Model:
https://gitlab.com/webdev866/vouchermanager/-/blob/master/app/CreateVoucher.php
View:
What is the best way to achieve this?
ASKER
Hi Chris,
Right, however if I want to hide it, it's what I'm trying to achieve, like a selection menu, Hide Price (Yes/No)
Few ways to do it - basically, you'll need a way to pass a value into your Controller. You could do this with a simple radio and a form POST:
<form method="post" action="some_route">
<input type="radio" name="showprice" value="yes" selected>
<input type="radio" name="showprice" value="no">
<input type="submit" value="Get PDF">
</form>
Then, in your Controller, just read in $request->showprice and pass it into your View:$showprice = $request->showprice == "yes";
$pdf = PDF::loadView('admin.vouchersAccountings.get_single_pdf', compact('voucher', 'showprice'));
You can see we're passing showprice into the view as a Boolean, so now in your view you can do;:@if ($showprice)
// show the price data here :)
@endif
ASKER
That's great route, I will do my best to implement it by myself, just a question, do we need to store showprice in database in case we wanted to re-print it?
ASKER
Ok I have added show_price to the create_vouchers table
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class UpdateVouchersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('create_vouchers', function (Blueprint $table) {
$table->string('show_price')->after('total_amount');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('create_vouchers', function (Blueprint $table) {
$table->dropColumn('show_price');
});
}
}
Model:
public const SHOWPRICE_RADIO = [
'yes' => 'Yes',
'no' => 'No',
];
then I added showprice in every possible view:
<div class="form-group {{ $errors->has('showprice') ? 'has-error' : '' }}">
<label class="required">{{ trans('cruds.createVoucher.fields.showprice') }}</label>
@foreach(App\CreateVoucher::SHOWPRICE_RADIO as $key => $label)
<div>
<input type="radio" id="showprice_{{ $key }}" name="showprice" value="{{ $key }}" {{ old('showprice', '') === (string) $key ? 'checked' : '' }} required>
<label for="showprice_{{ $key }}" style="font-weight: 400">{{ $label }}</label>
</div>
@endforeach
@if($errors->has('showprice'))
<span class="help-block" role="alert">{{ $errors->first('showprice') }}</span>
@endif
<span class="help-block">{{ trans('cruds.createVoucher.fields.showprice_helper') }}</span>
</div>
I get this error while trying to create a voucher for testing:
First off, I'd suggest you use a Boolean for your show_price column. Using magic strings such as Yes/No only leads to problems down the line, whereas a true/false removes ambiguity and any chance of errors. Set your array to 1 and 0 instead of yes/no:
public const SHOWPRICE_RADIO = [
0 => 'No',
1 => 'Yes',
];
and then add it to the $casts array in your model:protected $casts = [
'show_price' => 'boolean',
];
Because you're casting the property to boolean, it means that you can easily use it your logic / blade:if ($voucher->show_price) {
//
}
The error you're getting is exactly as it says - you haven't set a default value for the show_price field, and you can't leave it null (it's not nullable), so you MUST provide a value when you create a new record. Now, in your form you've named the radio showprice, but the column in your DB is called show_price, so the 2 won't match up when you call create(). Keep the names the same as your DB column. You must also add the show_price column to the $fillable array on your Model otherwise you can't mass to assign it.ASKER
You are correct Chris, I changed show_price column to showprice and it worked, but I had to do it manually I was looking for a quick fix.
Where that $cast came from? I don't have it in the Model but I added it
if ($voucher->show_price) { <== This line means True by default?
//
}
Ok I'm at the final step, should I create a method in controller that takes me to a new view with removed price if I select No ?
Yeah - manually changing the column is the quick and easy way - just make sure you update your previous migration as well. You're not going to re-run it, but in the future if you need to rebuild the DB, you'll want it to be correct.
The $casts property allows you to tell your Model that certain columns should be treated as certain types, and if it doesn't exists, then you're right to add it. For example, if you have a DateOfBirth column, you would want to cast that to a Date. MySQL doesn't actually have a Boolean data type, so it stores the values as 0 and 1 (tinyint). By adding the property to $casts[] means that when we read and write to the database, the values of 0 and 1 are converted to true and false automatically.
if ($voucher->show_price) {
Yeah - that basically says "if show_price === true"
The opposite would be:
if ( ! $voucher->show_price) {
which is "if show_price === false"
You don't need a new view to display or hide the price - you've now got the show_price (boolean), so just add the logic into your view. Something like this maybe ??
@if ($voucher->showprice)
<h4>Price</h4>
<p>{{ $voucher->total_amount }}</p>
@endif
ASKER
Maybe I've done something wrong
my controller:
public function get_single_pdf(CreateVoucher $voucher, Request $request)
{
$showprice = $request->showprice == "yes";
$voucher->loadMissing(['hotel_name', 'agent', 'room_type']);
$pdf = PDF::loadView('admin.vouchersAccountings.get_single_pdf', compact('voucher','showprice'));
return $pdf->download('voucher.pdf');
}
View
<tr>
<th>
{{ trans('cruds.createVoucher.fields.total_amount') }}
</th>
@if (!$voucher->showprice)
<h4>Price</h4>
<p>{{ $voucher->total_amount }}</p>
@endif
</tr>
<tr>
total is displaying
Can we simply remove the total amount and Rate Per Night
So $request->showprice only exists when you POST that value and you only need to do that when you're updating or creating a new Voucher. Once you've created the Voucher in the DB, then you access the showprice property just like any other. In your Controller all you need is this:
public function get_single_pdf(CreateVoucher $voucher, Request $request)
{
$voucher->loadMissing(['hotel_name', 'agent', 'room_type']);
$pdf = PDF::loadView('admin.vouchersAccountings.get_single_pdf', compact('voucher'));
return $pdf->download('voucher.pdf');
}
You're passing the $voucher into the view, and the $voucher has a showprice property, so in your view you just access it like any other property.Also, in your view code above, you have this:
@if (!$voucher->showprice)
The Exclamation mark means NOT, so that line says "if showprice is false (NOT true)". Drop the exclamation mark (!) :
@if ($voucher->showprice)
If you want to hide the total price, then just wrap it in the @if ($voucher->showprice) check:
@if ($voucher->showprice)
<tr>
<th>
{{ trans('cruds.createVoucher.fields.total_amount') }}
</th>
<td>
{{ $voucher->total_amount }}
</td>
</tr>
@endif
@if ($voucher->showprice == "yes")
This is why we use Booleans and not strings !!
ASKER
Okay, I'm still facing issues
I got an error
ErrorException
Undefined variable: voucher (View: /var/www/vouchermanager/resources/views/layouts/print.blade.php)
http://vouchermanager.test/admin/create-vouchers/getpdf/7
Hide solutions
Possible typo $voucher
Did you mean $createVoucher?
changing $voucher to $createVoucher display the PDF still with total_amount showing up.
Then again when I try to re-generate the PDF I got a different error:
ErrorException
Undefined variable: createVoucher (View: /var/www/vouchermanager/resources/views/admin/vouchersAccountings/get_single_pdf.blade.php)
http://vouchermanager.test/admin/vouchers-accountings/getpdf/7
Hide solutions
Possible typo $createVoucher
Did you mean $voucher?
the get_single_pdf blade is having a fight with print blade :)
I guess there is a simpler way, if you select ShowPrice = No, then it takes you to another view with pricing <tr> removed, if it's yes then no change What do you think?
I definitely wouldn't have 2 different views - you're just doubling up your code which goes against best practice.
I don't know what state your code is in at the moment - if I look at your GitLab repo, it seems like you have a print.blade file which is a full HTML document, and then you have a get_single_pdf.blade file, which is a partial template. That partial extends print, but print doesn't look extendable, so somethings wrong. Push all your changes to your repo and then I'll take a look.
ASKER
Thank you Chris,
https://gitlab.com/webdev866/vouchermanager
latest commit push
https://gitlab.com/webdev866/vouchermanager/-/commit/a40e36aa2494e68acfb2d6e0bf600d503caea3fa
First off, you've still got a disconnect on your showprice field. You're casting show_price (underscore) but in $fillable, you've added showprice (no underscore). The field in your Database is called showprice, so go with that everywhere.
The field in your DB is still an string, according to the migration, so you might want to chagne that to a boolean. If you do that, then drop the quotes around 0 and 1 in your SHOWPRICE_RADIO array.
Now - onto your PDF. You're still getting this all quite wrong !! In your CreateVoucherController, you have a method called getpdf. Now in that method, you're loading up your voucher and storing it in a variable called $createVoucher - you then pass this into the createVouchers/getpdf view - all good so far.
Now, this is where it starts to go wrong. If you take a look at your getpdf view, you'll see that it uses the $createVoucher variable, as it should, but nowhere in there do you do the showprice check. Because your voucher is in the $createVoucher variable, then you'd need $createVoucher->showprice.
However, if you take a look at the print.blade.php template, that is a full HTML page, with no way of extending it and that uses a couple of variables - one called $voucher and one called $voucherId which NEVER get passed into the view. Because it's not extendable, your getpdf.blade view NEVER get's rendered. We've gone through this before and I though we had it sorted. Your base template (print.blade in your case), should NOT have data in it - it should however have a @yield('content') line so that the child template (getpdf.blade in your case) knows where to get rendered.
ASKER
Thank you Chris for your help, you are a real troubleshooter :)
First off, you've still got a disconnect on your showprice field. You're casting show_price (underscore) but in $fillable, you've added showprice (no underscore). The field in your Database is called showprice, so go with that everywhere.
=> Right, I've corrected it.
The field in your DB is still an string, according to the migration, so you might want to chagne that to a boolean. If you do that, then drop the quotes around 0 and 1 in your SHOWPRICE_RADIO array.
=> I've corrected it manually, however can you confirm if this is the right syntaxe
public function up()
{
Schema::table('create_vouchers', function (Blueprint $table) {
$table->boolean('showprice')->after('total_amount');
});
}
Now - onto your PDF. You're still getting this all quite wrong !! In your CreateVoucherController, you have a method called getpdf. Now in that method, you're loading up your voucher and storing it in a variable called $createVoucher - you then pass this into the createVouchers/getpdf view - all good so far.
Now, this is where it starts to go wrong. If you take a look at your getpdf view, you'll see that it uses the $createVoucher variable, as it should, but nowhere in there do you do the showprice check. Because your voucher is in the $createVoucher variable, then you'd need $createVoucher->showprice.
=> This is where I lost it, putting @yield content in print.blade.php obviously rendered the view with no css
What I did is something different, I guess you won't like it, I created different blades, I left print.blade.php as is with HTML and I make it to render createvoucher
Then I created another print_get_single_pdf.blade.php to render single_pdf and I put $voucher all in.
Result=> it worked out just fine. Vouchers with ShowPrice set to No, doesn't show the pricing as expected.
what do you think.
I'm opening another question because when I select a range in Voucher Accounting if there is no data, it still output a random total balance instead of zero, not sure if it has to do something with
$total_balance = $vouchers->sum('total_amount');
ASKER
Thank you so much Chris, love you man :)
Not entirely clear what you're asking. When you create a PDF, you use a View, so if you want to show the Price, just add it to the View !!