So let's get started creating an invoice in the form of a PDF.
Now, as I'm sure a quick Google search will tell you, there are lots of different ways to create PDF,
either Engo or using a darker image or many different ways.
But if you actually search for PDF and go or go langue, you're almost certainly going to get return
to this repository.
Let's have a look at it over here.
Jegue Inkheart ago for PDF.
And the first thing you'll notice is that the repository has been archived, which is never a good sign.
And if you scroll down to the README and actually says we are closed, the repository will not be maintained.
And when I saw that must have been about a year ago now, I was a little disheartened because I use
this package all the time.
It works really well.
So I decided I'd fork it and maintain it myself.
But it turns out somebody had already done that.
And this is the one we're going to use, as you can see here, has been forked from the repository I
just looked at.
But it's actually maintained and it's maintained reasonably well.
So let's go get that.
So, first of all, let's go back to our idea and open our terminal and we'll type go get and the USL
is GitHub dot com slash p hp Dave one one slash go f f, which I usually mistype.
So I hope I got it right.
And there it is, and now I'm going to get a second package, go get in this one, I copied and pasted
because I will miss type typing that one.
It's GitHub dotcom slash Dave 11 slash go f pdf slash contribute, go f P.D.A.
So let's go get that.
And that's now available to us and these are the packages we're going to use now when I create a PDF,
I could if I wanted to write the code to create every single part of that PDF, write from scratch and
it's quite achievable.
You could do it.
You can embed images, you can do whatever you want.
But I like to start with a PDF that I've created beforehand and then right on top of that, and that
was the reason I imported that second package, which is go for PDI from the Cantrip directory of that
repository.
And if you look at the course resources for this lecture, you'll see a PDF you can download.
I'll show you what it looks like.
It's not very pretty because I didn't put much effort into making it pretty.
It's a blank invoice and it has terms on receipt balance.
Do we're going to populate this part and we're going to populate this part and we're going to leave
this one as an exercise for you because it's simply working with a ruler you'll see momentarily.
So let's get straight back over to our code.
What I have done is I've downloaded that PDF or you should download that PDF.
And at the root level of your project, in other words, at the same level as the CMD folder, create
a folder called PDF dash templates.
Inside of that, put the file you downloaded called invoice PDF and make sure it's at the root level
of your project at the same level as CMD and Internal and Migration's and so on and so forth.
So that needs to be there or what we're about to do just won't work.
So let's go over to invoice handlers again and get started.
So if you remember over in CMD Micro Invoice invoice routes, we change this to a post last time around,
change it back to a get for now.
It'll be a post at the end of the day, but change it back to a get and then go over to invoice handlers.
And we're at this step right here.
Generate a PDF invoice.
Now, I could put everything right here in this handler, but chances are I'm going to want to do this
from other places.
And also, it's it's always better practice to have one function, do one thing.
So here I'll create another function, which I'm going to call func with the receiver of appointer to
application.
I'll call it create invoice PDF.
And it will take one argument, which will be order of type order, which is defined right at the top
of this file.
And potentially it returns an error.
OK.
And the first thing I'm going to do is take advantage of that go PDF package we just imported, so a
variable called PDF and that's a sign the value of from go f pdaf right there.
Not that one.
This one.
That again.
Right there, Dave.
11, as you can see, I had the other one imported and available to me.
But we want GitHub dot com Dave 11 Shūgo of PDF.
We want that and we want to create a new PDF and it requires a few parameters, as you can see here.
So the orientation, the unit, the size, the font door, those sort of things.
OK, so the first thing is the orientation.
And in my case it's Porter and my units of measurement.
I'm in Canada, so I'm going to use MMS and they're really easy to work with.
My paper size is a letter and I'm going to leave the last one.
The font, dear empty because I'm not going to use custom fonts.
But if you read the documentation for this package, you'll see you can if you want to.
Then I'll set my mergence PDF set margins and I'm going to set them to 10, 13 and 10, all of which
are in MMS in my case.
OK, and now I'll say PDF set, auto page break, which doesn't really matter for our case, but it's
good practice.
I'm going to such a true and zero hour.
Our invoices will all be one page long, so you don't actually have to do that.
But I like to be consistent and do the things you're supposed to do.
Now I want to create an importer that will allow me to import the PDF.
I want to write on that way.
I only have to put a few things in there programmatically.
So let's create a variable which I'll call importer and that's going to be assigned the value of from
go f PDI.
Sometimes this has problems getting in there.
Go Phaedo not John Kirt that one.
Dave Oliver.
So go FPI dot new importer and that takes no arguments.
OK, and we have an error here that says undeclared name application compiler lets you save it and see
what happens.
Yeah.
You get confused again.
So we'll go back up here to Dave 11 and put Cantrip ago.
FP the.
And this over here should be an F and hopefully that will solve the problem and it did.
I don't know why it gets confused.
I think it's because in the past, I've imported the old Joan Kirt version.
And that may not happen to you, but if it does, just make sure that you have these two lines in your
import statement and all will be well.
So baktun in our create invoice PDF function, I've created this importer and I don't want to use it.
So carried a variable penalty for template.
And that's a sign the value of importer dot import page.
And it takes a few arguments.
First of all, what PDF do you want to import it to?
And our variable is called PDF.
And then where does the template exist?
And in our case, because it's the root level of our application and that's where our application is
started from, which is why it has to be at the root level.
Make starts for me at the root level of my folder.
So I say start wherever you started dot pdf dash templates, dot invoice dot pdf, not dot invoice,
slash invoice, slash invoice.
So that's a second order argument.
The third one is just the number one and that's page number.
OK, and the last one is something specific to this particular package.
Media box need the box and it's case sensitive.
So make sure you enter it exactly like that.
Now I have this variable t so first thing I'll do now that I have this variable T is a PDF had a page
so it actually adds a page for me.
OK, and now I say I want to use the imported template I just created.
So Importer don't use imported template and it requires pdf the template I want to use which is T and
the rest of them are just measurements which I'm going to set to zero zero to one five point nine which
is again and.
Mm.
And zero and hopefully that's all right.
Looks good so far.
Now I've done all of the work with an eight and a half by 11 sheet of paper and a ruler measuring exactly
where things should go.
And that's why I use.
Mm.
Because they're easy to work with.
Everything is based.
Now let's go a little bit further.
First thing I'm going to do is say I want to write on this template, but I need to tell it where I
want to write.
So I'm going to set on the Y axis thinking about an x y axis where X goes horizontally and Y goes up
and down at position 20.
Mm.
And I'll say write info.
And the only information I need to write here right now if you go back to the template.
I want to right things right here, Bill, too.
OK, so let's try this will say.
Should I should be 50, not 20?
I'm going to move this down here so everything is clear and I have a typo, I should be setting PDF
set, why two fifty?
So I'm moving down 50 miles.
Mm.
And then PDF set X, move it over ten millimeters.
And now I say, what font do you want to use.
PDF dot set font.
And I'm going to choose times and I'll use times with no modifications.
So not boulder italics or leave an empty string for my second parameter and I'll say my size will be
eleven.
That's the font size I want to use.
Now I'm going to write a cell with a particular format, so PDF, not cell format, and it has a lot
of parameters.
So the first one is width.
I'll make it ninety seven millimeters wide and the next one is the height.
I'll make that eight millimeters tall and then I'm going to print the text I want.
So I'll say format or print f it needs to be in the form of a string.
I'll say attention column space placenta's percent s and in here I'll substitute ordered a first name
and order last name.
So now I have my text and we're not finished yet.
The next thing is what border do I want to be around myself and I don't want one, so I'm going to leave
an empty string then for L.N., I can just put a zero in there and it will work perfectly fine then
alignment.
I want it to be left, then faults.
Don't fill this, don't shade it.
In other words.
And the last two are zero.
There's no link and link string which is an empty string and that will actually write a tension.
First name, last name apposition.
Fifty ten or ten fifty prefer x y using the font times size 11 with no modifications to the font.
So it's not bold or underline for example.
So that's a lot of writing to get the first name and last name there.
And after I've written that line I want a blank line.
So PDF Ellan and I'll just put the number five in there which will give me a line height five to space
it down and I will write the person's email, which is again PDF cell format, and I'm going to go again
with ninety seven and eight.
So it starts at exactly the same location just down one line and I'll put the email order to email and
again I want nothing and zero and left justified and false and zero and nothing because there's no links
anywhere.
OK, so we've done that and the last thing I want to do and I'll just copy these to save some time is
to print the order date underneath.
So print that.
And this time it's border dot created at DOT format and I'll use two zero zero six zero one zero two,
which will give me your month date in the format that I like.
And of course you can use whatever format you want there.
So I've done that.
The next thing to do is actually to print things in the table.
So what we've done so far back to the PDF is put the name, email address and the date up here.
And now I want to put the item that's being sold, the quantity and the total, and that'll be enough
to get you started.
So let's go down to populating the table.
So this time I'm going to say PDF set x two fifty eight mm.
And PDF set Y two ninety three.
Mm.
And again, I did that using a ruler.
That's all that I did.
And I'll paste another cell format, get rid of this and this time I want it to be apposition.
One fifty five.
And eight is fine, and I want order product.
So what that's going to do is put the product name right here.
OK, now I want to change my X coordinates to move over to the right further.
So PDF set X and this time it's one hundred and sixty six again.
Just got that using your ruler and I'll print in this again and make a copy this, paste it here and
just modify it.
So this time I want 20 as the leading number eight is fine and I want to put the order quantity in there.
Now if I try this it's not going to work because that needs to be in the form of a string.
So instead I'll just say format at this point, 12 percent s order quantity and close up parentheses.
Now it's a string, OK?
And now I want the price.
And again, we have to do a little bit of magic here.
So let me just copy this.
Let's put it in this way, the last thing I'm going to fill in is the price PDF set X and that's going
to be apposition one eighty five hundred and eighty five miles.
Mm.
And I'll copy this.
And pasted in here, and I don't want the quantity this time, I want the price, but remember, we're
getting the price or the amount sold as an integer.
So we have to put in instead formatter as print f.
And we want our format string to be dollar sign percent, dot to F, so two decimal places.
It should be to not announce that one percent dot to F.
And then we just convert our entry into a slope 30 to float thirty two, and we want order amount divided
by one hundred point zero.
And quantity, I want it in the center of the column.
So I'm going to change this to a C and this I want to be right justified in case there's more items
in the future.
That way the decimal points will all line up nicely.
OK, so we have that.
The next thing we do, my PDF is done for my purposes and as I can leave the bottom part where you have
the total and so forth as an exercise for you and you get to play with a ruler for a while and it's
really not difficult.
And I want to export this as a PDF, but I need to put it somewhere.
So what I'm going to do is assume that there's a folder at the root level of my application called invoices.
So I'll say invoice path.
Invoice path is assign the value of format or s print F and I'm going to put it in dot slash invoices
slash and I'm going to name my invoice whatever the order number is.
So percent d pdf and I'll substitute order ID for the present D in the format string.
And now creating the invoice is as simple as this error is, assign the value of PDF output file and
close so we don't have to worry about things being left open in memory leaks.
So it closes it automatically.
And I'm going to write to Invoice Path and we'll check for an error if error is not equal to nil.
When we return the error otherwise return nil.
So order quantity.
This should be a present D..
I knew there was something staring me in the face.
That's an integer, not a string.
So this is the correct way to do that.
OK, so there's our function that will actually write the PDF to disk for us.
Now you notice that I said I'll assume there's a folder at the root level of the application called
invoices, but I don't actually have to assume that what I'm gonna do next is just go to my helper file
in micro invoice and I'm going to write a little function here, really simple one, which I'll call
func with a receiver of appointed application and I'll call this create Dürer if not exist, OK?
And it takes one argument path, which would be a strength and it potentially returns an error and we'll
just create a folder.
So const mode, I want this folder to be have permissions equal to zero seven five five and I'll create
a folder if and I'll ignore the first return value, but I will check for an error.
They are assigning the value of from the OS package dot stat path which we received as a parameter to
this function.
OS dot is not exist error.
And down here, we simply say there is a sign of the value of our stock market here and we want to make
clear path and mode, and so now we've got an extra set of parentheses in there.
We check for an error.
If error is not equal to nil, then I love there after error, love print line error and I'll return
the error.
Otherwise down here, I'll return.
Now that I have this function, let's go back to the root entry point for this application, which is
invoice.
Don't go down here.
Right before I served the application, I'll simply call I don't make this or create dear if not exist
and hand it invoices and I believe that's what I call it in my invoice handlers over here.
Invoices.
Yes.
So now when our application starts, I don't have to worry about whether or not I remembered to create
that folder where I'm going to store the invoices.
It happens automatically, the checks to see if it exists.
If it does, it ignores it.
Otherwise it creates it for me.
And on we go, OK.
Now this structure is getting pretty long.
So in the next lecture, what we'll do is we'll come back here to this handler and we'll comment about
this stuff that reads Jason will manually populate the order variable with data and then we'll call
this function manually from a Web browser and see what happens.