Click here to load reader
Upload
bruce-mcpherson
View
2.783
Download
0
Embed Size (px)
DESCRIPTION
quick 5 minute tutorial. join multiple databases and create personalized email invoices with google apps script
Citation preview
do something useful with Apps Script in 5 minutes
3.Simple invoicing appBruce McPhersonwww.mcpher.com
Snippet objectives● Use the lessons learned in ‘using a spreadsheet as a
database’● Gets transactions and master data from database. I’m
using sheets as the database here. ● Calculates and generates personalized invoice emails
Libraries used● database abstraction● driver sheet
Add libraries to script
create a scriptOpen resourcesAdd references to librariesMrckbr9_w7PCphJtOzhzA_Cz3TLx7pV4j
MHfCjPQlweartW45xYs6hFai_d-phDA33
Take a copy of the test data
Product and Customer datahttps://docs.google.com/spreadsheets/d/1EhgZ1-q9tP1u9BSEQPIQiSGozdfjsHn3zB1JfQGbftw/edit?usp=sharing
Transaction datahttps://docs.google.com/spreadsheets/d/1gmOEvILq0wygW3iN9exe4P0iu0x2wgwlX25D_QHgq10/edit?usp=sharing
layout what you are going to dofunction myFunction() {
// get customer handle
// get product handle
// get transactions handle
// get all the transaction data ready to be invoiced
// organize into customers/transactions
// now we have an array of customers and their associated transactions - join to masters
// produce and email invoice with multiple transactions per customer
}
create function for repeated patterns/**
* open a sheet as a database
* @param {string} sheetName the sheetName
* @param {string} sheetId the spreadsheet id
* @return {DbAbstraction} the handle
*/
function getHandle ( sheetName, sheetId) {
// open spreadsheet as database
var handler = new cDbAbstraction.DbAbstraction (cDriverSheet, {
siloid:sheetName,
dbid:sheetId,
});
if (!handler.isHappy()) throw 'unable to open sheet';
return handler;
}
We’ll call this function for each of the database tables we need to open
Get handlers for each table
// get customer handle
var customerHandle = getHandle ('customers' , '1EhgZ1-q9tP1u9BSEQPIQiSGozdfjsHn3zB1JfQGbftw');
// get product handle
var productHandle = getHandle ('products' , '1EhgZ1-q9tP1u9BSEQPIQiSGozdfjsHn3zB1JfQGbftw');
// get transactions handle
var transactionHandle = getHandle ('transactions' , '1gmOEvILq0wygW3iN9exe4P0iu0x2wgwlX25D_QHgq10');
Get the transaction data and sort it
// get all the transaction data ready to be invoiced
var transactionResult = transactionHandle.query ({status:'delivered'},{sort:'customer id'});
if (transactionResult.handleCode < 0) throw transactionResult.handleError;
Reduce transactions
// organize into customers/transactions - data is already sorted
var customerTransactions = transactionResult.data.reduce ( function (p,c) {
var t = p.length ? p[p.length-1] : null;
if (!t || c['customer id'] !== t.cid) {
// its a new customer
p.push( t = {cid:c['customer id'], transactions:[]} );
}
t.transactions.push(c);
return p;
},[]);
Reduce to one object per customer, so we can consolidate transactions to a single invoice
Join transactions to masters // now we have an array of customers and their associated transactions - join to masters
customerTransactions.forEach ( function (d) {
var result = customerHandle.query ({"customer id":d.cid});
// just fail if customer not found
if ( result.handleCode < 0 || result.data.length !== 1 ) throw JSON.stringify(result);
d.customer = result.data.slice()[0];
// get the product data
d.transactions.forEach (function (p){
var result = productHandle.query ({"product id":p['product id']});
if ( result.handleCode < 0 || result.data.length !== 1 ) throw JSON.stringify(result);
p.product = result.data.slice()[0];
});
});
Look up the master data from customers and product table and join to transactions
Function to create email content function getEmailContent (d) {
return '<div>'
+ d.customer.company + '<br>'
+ '<table><tbody><th>Product name</th><th>Quantity</th><th>Total</th>'
+ d.transactions.map(function(e) {
return '<tr><td>'+e.product['product name']
+'</td><td>'+e.quantity
+'</td><td>'+e.quantity*e.product['unit price']
+'</td></tr>';
}).join(‘’)
+ '<tr><td>Total</td><td></td><td>'
+ d.transactions.reduce(function(p,c) {
return p+c.quantity*c.product['unit price'];
},0)
+ '</td></tr>'
+ '</tbody></table>'
+ '</div>';
}
Very basic email invoice. You’d probably want to spruce up and use a proper template
Send email invoices
customerTransactions.forEach (function(d) {
MailApp.sendEmail({
to: d.customer.email,
subject: "Invoice from desktop liberation",
htmlBody: getEmailContent (d)
});
});
Very basic email invoice. You’d probably want to spruce up and use a proper template
Further homework
● Using what you learned in graduating to a database, why not migrate some of the test data to a database and redo.
● Incorporate a real email templating solution like Romain Vialard’s YAMM
● Improve error handling● Update database status when email is sent
Follow up materials
Take a copy of this scriptTake a copy of these slidesJoin me on G+, or the G+ communityMore on desktop liberationMore on database abstraction