PDF Invoice Generator

INTRO

Simply, in your app, provide customer details, and then a list of items with prices and quantities. Send this off to a google apps script, which in turn will populate a google sheet, build the invoice, convert it to a pdf.  Back in your app, the pdf invoice is downloaded and displayed.

I used a couple of extensions: CompCreator (credits @ Kevinkun) and ViewPDF, but the aia project could be re-worked to operate extension free.

This is a demo, not a complete turn-key solution, intended to show the steps required, and the basic frameworks for google apps script and google sheets. It also provides a stepping stone for further development, inclusion in a larger app, etc. 

BLOCKS

(scroll over to see more blocks)

SCRIPT (Google Apps Script Web App)

(as you will see, I had fun handling the item/price/quantities elements ;) )

var folderId = 'YOUR "Public" FOLDER ID HERE';

var newFileId = '';

var invNo = '';


function doPost(e) {

 var ss = SpreadsheetApp.getActive();

 var shd = ss.getSheetByName("Data");

 var data = JSON.parse(e.postData.contents);

 var newData = data.slice(0,9);

 var content = data.slice(9, data.length);

 for (var i=0;i < content.length; i++) {

    newData.push(JSON.stringify(content[i]));

 }

 shd.appendRow(newData);

 SpreadsheetApp.flush();

 return ContentService.createTextOutput(setInvoice());

}


function setInvoice() {

//sets variables and gets ranges/values for the last entry in the data sheet

var ss = SpreadsheetApp.getActive();

var shd = ss.getSheetByName("Data");

var shi = ss.getSheetByName("Invoice");

var lr = shd.getLastRow();

var rng = shd.getRange("A" + lr + ":J" + lr).getDisplayValues();

var itm = shd.getRange("K" + lr + ":AD" + lr).getDisplayValues();

invNo = shd.getRange("G" + lr).getDisplayValue();


//sets cell values on the Invoice from the last entry in the Data sheet

shi.getRange("B9").setValue(rng[0][0]);

shi.getRange("B10").setValue(rng[0][1]);

shi.getRange("B11").setValue(rng[0][2]);

shi.getRange("B12").setValue(rng[0][3] + " " + rng[0][4] + " " + rng[0][5]);

shi.getRange("G9").setValue(rng[0][6]);

shi.getRange("F4").setValue(rng[0][7]);

shi.getRange("G12").setValue(rng[0][8]);

shi.getRange("B32").setValue(rng[0][9]);

//handles the json array data for each item, and applies it to the invoice

for (var i = 0; i < itm[0].length; i++) {

 if (itm[0][i] != "") {

   var item = JSON.parse(itm[0][i]);

   shi.getRange("B" + (16 + i)).setValue(item[0]);

   shi.getRange("E" + (16 + i)).setValue(item[1]);

   shi.getRange("F" + (16 + i)).setValue(item[2]);

 }

}

SpreadsheetApp.flush();


//create pdf and return the invoice number and fileId for the naming of the pdf to be downloaded

return InvoiceSheetToPDF(invNo);


}



 //create pdf of invoice sheet.

 //ref: https://stackoverflow.com/questions/39690232/using-google-apps-script-to-save-a-single-sheet-from-a-spreadsheet-as-pdf-in-a-s

function InvoiceSheetToPDF(invNo) {

var sheetName = "Invoice";

var folderID = folderId; // Folder id to save in a folder.

var pdfName = "Invoice-" + invNo + ".pdf";


var sourceSpreadsheet = SpreadsheetApp.getActive();

var sourceSheet = sourceSpreadsheet.getSheetByName(sheetName);

var folder = DriveApp.getFolderById(folderID);


//copy whole spreadsheet

var destSpreadsheet = SpreadsheetApp.open(DriveApp.getFileById(sourceSpreadsheet.getId()).makeCopy("tmp_convert_to_pdf", folder))


//delete redundant sheets

var sheets = destSpreadsheet.getSheets();

for (i = 0; i < sheets.length; i++) {

if (sheets[i].getSheetName() != sheetName){

destSpreadsheet.deleteSheet(sheets[i]);

}

}


var destSheet = destSpreadsheet.getSheets()[0];

//replace cell values with text (to avoid broken references)

var sourceRange = sourceSheet.getRange(1,1,sourceSheet.getMaxRows(),sourceSheet.getMaxColumns());

var sourcevalues = sourceRange.getValues();

var destRange = destSheet.getRange(1, 1, destSheet.getMaxRows(), destSheet.getMaxColumns());

destRange.setValues(sourcevalues);


//save to pdf

var theBlob = destSpreadsheet.getBlob().getAs('application/pdf').setName(pdfName);

newFileId = folder.createFile(theBlob).getId();


//Delete the temporary sheet

DriveApp.getFileById(destSpreadsheet.getId()).setTrashed(true);


clearRanges();


return invNo + ',' + newFileId;


}


function clearRanges() {

var ss = SpreadsheetApp.getActive();

var shd = ss.getSheetByName("Invoice");


shd.getRange("B9:B12").clearContent();

shd.getRange("F4").clearContent();

shd.getRange("G9").clearContent();

shd.getRange("G12").clearContent();

shd.getRange("B16:F30").clearContent();

shd.getRange("B32").clearContent();

SpreadsheetApp.flush();


}

SHEET

number formats for Invoice Number (00000) and DateDue (26/03/2023)

array formulas for InvoiceNumber and DateDue:

={"InvoiceNumber";arrayformula(IFERROR(sequence(MATCH(2,1/(A:A<>""),1)-1),""))}

={"DateDue";arrayformula(if(LEN(H2:H),H2:H+30,))}

SCREENS


AIA and FILES

Blank AIA Project (just add your script url)