WEBVTT 00:01.460 --> 00:05.090 So let's get started creating an invoice in the form of a PDF. 00:05.300 --> 00:10.490 Now, as I'm sure a quick Google search will tell you, there are lots of different ways to create PDF, 00:10.850 --> 00:14.530 either Engo or using a darker image or many different ways. 00:14.930 --> 00:20.540 But if you actually search for PDF and go or go langue, you're almost certainly going to get return 00:20.540 --> 00:21.710 to this repository. 00:21.740 --> 00:23.960 Let's have a look at it over here. 00:24.950 --> 00:28.130 Jegue Inkheart ago for PDF. 00:28.550 --> 00:33.070 And the first thing you'll notice is that the repository has been archived, which is never a good sign. 00:33.380 --> 00:39.630 And if you scroll down to the README and actually says we are closed, the repository will not be maintained. 00:39.650 --> 00:44.750 And when I saw that must have been about a year ago now, I was a little disheartened because I use 00:44.750 --> 00:46.160 this package all the time. 00:46.160 --> 00:47.230 It works really well. 00:47.990 --> 00:50.540 So I decided I'd fork it and maintain it myself. 00:50.540 --> 00:52.660 But it turns out somebody had already done that. 00:52.670 --> 00:57.320 And this is the one we're going to use, as you can see here, has been forked from the repository I 00:57.320 --> 00:58.100 just looked at. 00:58.490 --> 01:01.090 But it's actually maintained and it's maintained reasonably well. 01:01.400 --> 01:02.430 So let's go get that. 01:02.450 --> 01:08.780 So, first of all, let's go back to our idea and open our terminal and we'll type go get and the USL 01:08.780 --> 01:18.430 is GitHub dot com slash p hp Dave one one slash go f f, which I usually mistype. 01:18.440 --> 01:19.280 So I hope I got it right. 01:20.820 --> 01:25.890 And there it is, and now I'm going to get a second package, go get in this one, I copied and pasted 01:25.890 --> 01:28.220 because I will miss type typing that one. 01:28.650 --> 01:37.170 It's GitHub dotcom slash Dave 11 slash go f pdf slash contribute, go f P.D.A. 01:37.530 --> 01:38.460 So let's go get that. 01:39.870 --> 01:46.760 And that's now available to us and these are the packages we're going to use now when I create a PDF, 01:46.800 --> 01:53.280 I could if I wanted to write the code to create every single part of that PDF, write from scratch and 01:53.280 --> 01:54.180 it's quite achievable. 01:54.180 --> 01:54.720 You could do it. 01:54.720 --> 01:56.610 You can embed images, you can do whatever you want. 01:57.360 --> 02:02.460 But I like to start with a PDF that I've created beforehand and then right on top of that, and that 02:02.460 --> 02:08.820 was the reason I imported that second package, which is go for PDI from the Cantrip directory of that 02:08.820 --> 02:09.590 repository. 02:10.440 --> 02:15.150 And if you look at the course resources for this lecture, you'll see a PDF you can download. 02:15.190 --> 02:16.230 I'll show you what it looks like. 02:16.330 --> 02:19.460 It's not very pretty because I didn't put much effort into making it pretty. 02:19.620 --> 02:23.520 It's a blank invoice and it has terms on receipt balance. 02:23.520 --> 02:28.290 Do we're going to populate this part and we're going to populate this part and we're going to leave 02:28.290 --> 02:33.490 this one as an exercise for you because it's simply working with a ruler you'll see momentarily. 02:33.960 --> 02:35.960 So let's get straight back over to our code. 02:38.190 --> 02:42.990 What I have done is I've downloaded that PDF or you should download that PDF. 02:42.990 --> 02:49.560 And at the root level of your project, in other words, at the same level as the CMD folder, create 02:49.560 --> 02:52.320 a folder called PDF dash templates. 02:52.430 --> 02:58.980 Inside of that, put the file you downloaded called invoice PDF and make sure it's at the root level 02:58.980 --> 03:03.720 of your project at the same level as CMD and Internal and Migration's and so on and so forth. 03:03.720 --> 03:08.370 So that needs to be there or what we're about to do just won't work. 03:09.120 --> 03:14.050 So let's go over to invoice handlers again and get started. 03:14.400 --> 03:26.490 So if you remember over in CMD Micro Invoice invoice routes, we change this to a post last time around, 03:26.490 --> 03:27.900 change it back to a get for now. 03:27.930 --> 03:32.820 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. 03:32.820 --> 03:34.560 And we're at this step right here. 03:34.560 --> 03:36.350 Generate a PDF invoice. 03:36.900 --> 03:41.250 Now, I could put everything right here in this handler, but chances are I'm going to want to do this 03:41.250 --> 03:42.150 from other places. 03:42.150 --> 03:46.400 And also, it's it's always better practice to have one function, do one thing. 03:46.980 --> 03:52.530 So here I'll create another function, which I'm going to call func with the receiver of appointer to 03:52.530 --> 03:53.280 application. 03:54.180 --> 03:57.000 I'll call it create invoice PDF. 03:57.120 --> 04:02.340 And it will take one argument, which will be order of type order, which is defined right at the top 04:02.340 --> 04:02.970 of this file. 04:03.270 --> 04:05.040 And potentially it returns an error. 04:05.820 --> 04:06.120 OK. 04:07.450 --> 04:12.430 And the first thing I'm going to do is take advantage of that go PDF package we just imported, so a 04:12.670 --> 04:19.590 variable called PDF and that's a sign the value of from go f pdaf right there. 04:19.600 --> 04:20.290 Not that one. 04:20.440 --> 04:21.070 This one. 04:21.760 --> 04:22.240 That again. 04:22.690 --> 04:23.980 Right there, Dave. 04:23.980 --> 04:27.480 11, as you can see, I had the other one imported and available to me. 04:27.970 --> 04:32.440 But we want GitHub dot com Dave 11 Shūgo of PDF. 04:32.470 --> 04:38.820 We want that and we want to create a new PDF and it requires a few parameters, as you can see here. 04:39.400 --> 04:44.680 So the orientation, the unit, the size, the font door, those sort of things. 04:44.720 --> 04:46.410 OK, so the first thing is the orientation. 04:46.420 --> 04:49.840 And in my case it's Porter and my units of measurement. 04:49.840 --> 04:53.320 I'm in Canada, so I'm going to use MMS and they're really easy to work with. 04:53.800 --> 04:57.670 My paper size is a letter and I'm going to leave the last one. 04:57.670 --> 05:00.310 The font, dear empty because I'm not going to use custom fonts. 05:00.310 --> 05:03.700 But if you read the documentation for this package, you'll see you can if you want to. 05:05.200 --> 05:14.680 Then I'll set my mergence PDF set margins and I'm going to set them to 10, 13 and 10, all of which 05:14.680 --> 05:16.360 are in MMS in my case. 05:16.420 --> 05:23.890 OK, and now I'll say PDF set, auto page break, which doesn't really matter for our case, but it's 05:23.890 --> 05:24.730 good practice. 05:25.210 --> 05:27.790 I'm going to such a true and zero hour. 05:27.820 --> 05:31.660 Our invoices will all be one page long, so you don't actually have to do that. 05:31.660 --> 05:34.940 But I like to be consistent and do the things you're supposed to do. 05:35.590 --> 05:39.940 Now I want to create an importer that will allow me to import the PDF. 05:39.940 --> 05:41.640 I want to write on that way. 05:41.680 --> 05:44.170 I only have to put a few things in there programmatically. 05:44.350 --> 05:50.080 So let's create a variable which I'll call importer and that's going to be assigned the value of from 05:50.080 --> 05:51.640 go f PDI. 05:52.720 --> 05:54.940 Sometimes this has problems getting in there. 05:55.240 --> 05:58.300 Go Phaedo not John Kirt that one. 05:59.380 --> 05:59.980 Dave Oliver. 06:00.910 --> 06:06.130 So go FPI dot new importer and that takes no arguments. 06:06.340 --> 06:13.660 OK, and we have an error here that says undeclared name application compiler lets you save it and see 06:13.660 --> 06:14.350 what happens. 06:15.220 --> 06:15.580 Yeah. 06:15.610 --> 06:16.600 You get confused again. 06:16.600 --> 06:23.430 So we'll go back up here to Dave 11 and put Cantrip ago. 06:23.530 --> 06:24.490 FP the. 06:26.100 --> 06:32.820 And this over here should be an F and hopefully that will solve the problem and it did. 06:32.850 --> 06:34.200 I don't know why it gets confused. 06:34.200 --> 06:38.520 I think it's because in the past, I've imported the old Joan Kirt version. 06:38.790 --> 06:43.020 And that may not happen to you, but if it does, just make sure that you have these two lines in your 06:43.020 --> 06:45.470 import statement and all will be well. 06:45.870 --> 06:51.570 So baktun in our create invoice PDF function, I've created this importer and I don't want to use it. 06:51.930 --> 06:53.940 So carried a variable penalty for template. 06:54.090 --> 06:58.320 And that's a sign the value of importer dot import page. 06:59.550 --> 07:00.780 And it takes a few arguments. 07:00.780 --> 07:03.150 First of all, what PDF do you want to import it to? 07:03.150 --> 07:05.010 And our variable is called PDF. 07:05.310 --> 07:07.620 And then where does the template exist? 07:07.980 --> 07:13.080 And in our case, because it's the root level of our application and that's where our application is 07:13.080 --> 07:15.900 started from, which is why it has to be at the root level. 07:15.900 --> 07:19.110 Make starts for me at the root level of my folder. 07:19.680 --> 07:29.910 So I say start wherever you started dot pdf dash templates, dot invoice dot pdf, not dot invoice, 07:29.910 --> 07:33.490 slash invoice, slash invoice. 07:33.510 --> 07:35.220 So that's a second order argument. 07:36.060 --> 07:39.240 The third one is just the number one and that's page number. 07:39.390 --> 07:44.160 OK, and the last one is something specific to this particular package. 07:44.340 --> 07:49.110 Media box need the box and it's case sensitive. 07:49.110 --> 07:51.090 So make sure you enter it exactly like that. 07:52.170 --> 07:58.110 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 07:59.220 --> 08:00.720 so it actually adds a page for me. 08:00.930 --> 08:06.660 OK, and now I say I want to use the imported template I just created. 08:06.660 --> 08:15.060 So Importer don't use imported template and it requires pdf the template I want to use which is T and 08:15.060 --> 08:20.550 the rest of them are just measurements which I'm going to set to zero zero to one five point nine which 08:20.550 --> 08:20.940 is again and. 08:20.970 --> 08:21.630 Mm. 08:21.630 --> 08:24.530 And zero and hopefully that's all right. 08:24.660 --> 08:25.480 Looks good so far. 08:26.100 --> 08:32.850 Now I've done all of the work with an eight and a half by 11 sheet of paper and a ruler measuring exactly 08:32.850 --> 08:34.140 where things should go. 08:34.140 --> 08:34.890 And that's why I use. 08:34.890 --> 08:35.460 Mm. 08:35.460 --> 08:37.320 Because they're easy to work with. 08:37.320 --> 08:38.150 Everything is based. 08:39.600 --> 08:40.780 Now let's go a little bit further. 08:41.310 --> 08:46.290 First thing I'm going to do is say I want to write on this template, but I need to tell it where I 08:46.290 --> 08:46.830 want to write. 08:46.830 --> 08:53.760 So I'm going to set on the Y axis thinking about an x y axis where X goes horizontally and Y goes up 08:53.760 --> 08:56.250 and down at position 20. 08:56.250 --> 08:56.850 Mm. 08:57.810 --> 09:00.960 And I'll say write info. 09:01.320 --> 09:05.550 And the only information I need to write here right now if you go back to the template. 09:06.880 --> 09:10.740 I want to right things right here, Bill, too. 09:10.870 --> 09:14.770 OK, so let's try this will say. 09:17.920 --> 09:19.420 Should I should be 50, not 20? 09:22.540 --> 09:31.480 I'm going to move this down here so everything is clear and I have a typo, I should be setting PDF 09:31.780 --> 09:34.380 set, why two fifty? 09:34.630 --> 09:36.040 So I'm moving down 50 miles. 09:36.340 --> 09:36.970 Mm. 09:37.690 --> 09:44.370 And then PDF set X, move it over ten millimeters. 09:44.890 --> 09:46.810 And now I say, what font do you want to use. 09:46.870 --> 09:48.310 PDF dot set font. 09:48.910 --> 09:53.410 And I'm going to choose times and I'll use times with no modifications. 09:53.410 --> 09:59.290 So not boulder italics or leave an empty string for my second parameter and I'll say my size will be 09:59.290 --> 09:59.650 eleven. 09:59.830 --> 10:01.600 That's the font size I want to use. 10:03.500 --> 10:14.180 Now I'm going to write a cell with a particular format, so PDF, not cell format, and it has a lot 10:14.180 --> 10:14.850 of parameters. 10:15.050 --> 10:17.780 So the first one is width. 10:17.870 --> 10:22.730 I'll make it ninety seven millimeters wide and the next one is the height. 10:22.850 --> 10:27.080 I'll make that eight millimeters tall and then I'm going to print the text I want. 10:27.110 --> 10:31.380 So I'll say format or print f it needs to be in the form of a string. 10:31.850 --> 10:41.660 I'll say attention column space placenta's percent s and in here I'll substitute ordered a first name 10:42.500 --> 10:43.950 and order last name. 10:44.420 --> 10:47.590 So now I have my text and we're not finished yet. 10:48.990 --> 10:53.280 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 10:53.280 --> 11:00.750 an empty string then for L.N., I can just put a zero in there and it will work perfectly fine then 11:00.750 --> 11:01.470 alignment. 11:01.560 --> 11:04.410 I want it to be left, then faults. 11:04.410 --> 11:06.090 Don't fill this, don't shade it. 11:06.090 --> 11:06.810 In other words. 11:06.810 --> 11:08.600 And the last two are zero. 11:08.640 --> 11:16.440 There's no link and link string which is an empty string and that will actually write a tension. 11:16.590 --> 11:18.930 First name, last name apposition. 11:18.930 --> 11:27.570 Fifty ten or ten fifty prefer x y using the font times size 11 with no modifications to the font. 11:27.570 --> 11:29.930 So it's not bold or underline for example. 11:30.780 --> 11:34.710 So that's a lot of writing to get the first name and last name there. 11:35.340 --> 11:37.510 And after I've written that line I want a blank line. 11:37.560 --> 11:42.870 So PDF Ellan and I'll just put the number five in there which will give me a line height five to space 11:42.870 --> 11:51.600 it down and I will write the person's email, which is again PDF cell format, and I'm going to go again 11:51.600 --> 11:53.790 with ninety seven and eight. 11:53.790 --> 12:01.710 So it starts at exactly the same location just down one line and I'll put the email order to email and 12:01.710 --> 12:09.210 again I want nothing and zero and left justified and false and zero and nothing because there's no links 12:09.210 --> 12:09.560 anywhere. 12:10.200 --> 12:16.080 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 12:16.080 --> 12:17.530 to print the order date underneath. 12:18.120 --> 12:18.870 So print that. 12:20.190 --> 12:27.480 And this time it's border dot created at DOT format and I'll use two zero zero six zero one zero two, 12:28.140 --> 12:32.120 which will give me your month date in the format that I like. 12:32.130 --> 12:34.370 And of course you can use whatever format you want there. 12:35.760 --> 12:36.810 So I've done that. 12:37.230 --> 12:40.490 The next thing to do is actually to print things in the table. 12:40.500 --> 12:47.160 So what we've done so far back to the PDF is put the name, email address and the date up here. 12:47.310 --> 12:51.960 And now I want to put the item that's being sold, the quantity and the total, and that'll be enough 12:51.960 --> 12:52.620 to get you started. 12:53.910 --> 12:56.460 So let's go down to populating the table. 12:56.700 --> 13:03.690 So this time I'm going to say PDF set x two fifty eight mm. 13:04.620 --> 13:07.980 And PDF set Y two ninety three. 13:07.980 --> 13:08.510 Mm. 13:08.520 --> 13:10.560 And again, I did that using a ruler. 13:10.560 --> 13:11.640 That's all that I did. 13:12.540 --> 13:19.380 And I'll paste another cell format, get rid of this and this time I want it to be apposition. 13:19.380 --> 13:20.310 One fifty five. 13:22.710 --> 13:26.010 And eight is fine, and I want order product. 13:28.000 --> 13:32.150 So what that's going to do is put the product name right here. 13:33.580 --> 13:40.990 OK, now I want to change my X coordinates to move over to the right further. 13:40.990 --> 13:47.290 So PDF set X and this time it's one hundred and sixty six again. 13:47.290 --> 13:53.830 Just got that using your ruler and I'll print in this again and make a copy this, paste it here and 13:53.830 --> 13:54.500 just modify it. 13:55.600 --> 14:02.760 So this time I want 20 as the leading number eight is fine and I want to put the order quantity in there. 14:02.830 --> 14:07.050 Now if I try this it's not going to work because that needs to be in the form of a string. 14:07.060 --> 14:16.190 So instead I'll just say format at this point, 12 percent s order quantity and close up parentheses. 14:16.570 --> 14:18.050 Now it's a string, OK? 14:19.450 --> 14:20.650 And now I want the price. 14:21.040 --> 14:23.170 And again, we have to do a little bit of magic here. 14:23.170 --> 14:25.840 So let me just copy this. 14:28.220 --> 14:36.650 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 14:36.650 --> 14:40.940 to be apposition one eighty five hundred and eighty five miles. 14:40.940 --> 14:41.510 Mm. 14:42.500 --> 14:44.090 And I'll copy this. 14:47.620 --> 14:53.290 And pasted in here, and I don't want the quantity this time, I want the price, but remember, we're 14:53.290 --> 14:57.250 getting the price or the amount sold as an integer. 14:57.310 --> 15:01.180 So we have to put in instead formatter as print f. 15:02.750 --> 15:11.360 And we want our format string to be dollar sign percent, dot to F, so two decimal places. 15:14.470 --> 15:20.860 It should be to not announce that one percent dot to F. 15:22.100 --> 15:32.630 And then we just convert our entry into a slope 30 to float thirty two, and we want order amount divided 15:32.630 --> 15:33.770 by one hundred point zero. 15:35.870 --> 15:38.670 And quantity, I want it in the center of the column. 15:38.690 --> 15:44.420 So I'm going to change this to a C and this I want to be right justified in case there's more items 15:44.420 --> 15:45.130 in the future. 15:45.140 --> 15:47.510 That way the decimal points will all line up nicely. 15:47.810 --> 15:49.910 OK, so we have that. 15:50.030 --> 15:55.760 The next thing we do, my PDF is done for my purposes and as I can leave the bottom part where you have 15:55.760 --> 16:00.020 the total and so forth as an exercise for you and you get to play with a ruler for a while and it's 16:00.020 --> 16:01.090 really not difficult. 16:01.910 --> 16:05.740 And I want to export this as a PDF, but I need to put it somewhere. 16:06.020 --> 16:11.510 So what I'm going to do is assume that there's a folder at the root level of my application called invoices. 16:11.990 --> 16:13.580 So I'll say invoice path. 16:14.090 --> 16:24.320 Invoice path is assign the value of format or s print F and I'm going to put it in dot slash invoices 16:24.320 --> 16:28.160 slash and I'm going to name my invoice whatever the order number is. 16:28.190 --> 16:36.790 So percent d pdf and I'll substitute order ID for the present D in the format string. 16:37.260 --> 16:44.750 And now creating the invoice is as simple as this error is, assign the value of PDF output file and 16:44.750 --> 16:49.230 close so we don't have to worry about things being left open in memory leaks. 16:49.310 --> 16:50.750 So it closes it automatically. 16:51.200 --> 16:58.490 And I'm going to write to Invoice Path and we'll check for an error if error is not equal to nil. 16:59.690 --> 17:06.500 When we return the error otherwise return nil. 17:09.950 --> 17:11.210 So order quantity. 17:11.210 --> 17:12.500 This should be a present D.. 17:12.980 --> 17:15.110 I knew there was something staring me in the face. 17:15.140 --> 17:16.970 That's an integer, not a string. 17:16.970 --> 17:18.590 So this is the correct way to do that. 17:19.310 --> 17:24.450 OK, so there's our function that will actually write the PDF to disk for us. 17:25.370 --> 17:31.280 Now you notice that I said I'll assume there's a folder at the root level of the application called 17:31.280 --> 17:36.710 invoices, but I don't actually have to assume that what I'm gonna do next is just go to my helper file 17:37.100 --> 17:43.700 in micro invoice and I'm going to write a little function here, really simple one, which I'll call 17:43.700 --> 17:52.610 func with a receiver of appointed application and I'll call this create Dürer if not exist, OK? 17:54.190 --> 17:59.980 And it takes one argument path, which would be a strength and it potentially returns an error and we'll 17:59.980 --> 18:01.150 just create a folder. 18:01.150 --> 18:10.750 So const mode, I want this folder to be have permissions equal to zero seven five five and I'll create 18:10.750 --> 18:15.250 a folder if and I'll ignore the first return value, but I will check for an error. 18:16.000 --> 18:25.540 They are assigning the value of from the OS package dot stat path which we received as a parameter to 18:25.540 --> 18:26.170 this function. 18:26.470 --> 18:31.150 OS dot is not exist error. 18:34.040 --> 18:40.820 And down here, we simply say there is a sign of the value of our stock market here and we want to make 18:40.820 --> 18:47.440 clear path and mode, and so now we've got an extra set of parentheses in there. 18:50.160 --> 18:51.020 We check for an error. 18:51.770 --> 19:04.460 If error is not equal to nil, then I love there after error, love print line error and I'll return 19:04.460 --> 19:04.880 the error. 19:07.580 --> 19:11.330 Otherwise down here, I'll return. 19:13.970 --> 19:19.670 Now that I have this function, let's go back to the root entry point for this application, which is 19:19.670 --> 19:20.150 invoice. 19:20.150 --> 19:23.210 Don't go down here. 19:24.960 --> 19:34.200 Right before I served the application, I'll simply call I don't make this or create dear if not exist 19:34.200 --> 19:41.640 and hand it invoices and I believe that's what I call it in my invoice handlers over here. 19:41.670 --> 19:42.390 Invoices. 19:42.410 --> 19:42.800 Yes. 19:44.010 --> 19:49.260 So now when our application starts, I don't have to worry about whether or not I remembered to create 19:49.260 --> 19:51.330 that folder where I'm going to store the invoices. 19:51.760 --> 19:54.450 It happens automatically, the checks to see if it exists. 19:54.450 --> 19:55.590 If it does, it ignores it. 19:55.590 --> 19:57.020 Otherwise it creates it for me. 19:57.030 --> 19:59.870 And on we go, OK. 20:00.000 --> 20:01.610 Now this structure is getting pretty long. 20:01.800 --> 20:09.630 So in the next lecture, what we'll do is we'll come back here to this handler and we'll comment about 20:09.630 --> 20:16.410 this stuff that reads Jason will manually populate the order variable with data and then we'll call 20:16.620 --> 20:20.190 this function manually from a Web browser and see what happens.