Files
invoice_generator/v1a/plotting.js
2024-04-07 16:12:40 +01:00

602 lines
24 KiB
JavaScript

// import { PDFDocument } from "pdf-lib";
var n_pages = 0;
var ha4 = 1123;
var wa4 = 794;
var border = 75; // page border / margins
var margin = 50; // drawing margins
var slabel = margin - 20; // spacing for dimension labels - ~ 10 < margin
var hline = 25;
var canvases = [document.getElementById("canvas_1")];
var ctxs = [canvases[0].getContext("2d")];
var myfont = 'arial'; // ToDo
// var url_logo = 'https://github.com/Teddy-1024/Neural_Network/blob/master/Logo.png'; // direct html execution
var url_logo = './Logo.png';
// positioning
var h_my_b = 180;
var h_issue = 325;
var h_bank = 420;
var h_billtosite = 560;
var h_tablehead = 800;
var h_row_max = 1050; // update this !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
var max_rows = round_down((h_row_max - h_tablehead) / hline);
// table columns
var w_tc1 = 120;
var w_tc2 = 420;
var w_tc3 = 520;
var w_tc4 = 620;
// file storage
let fnm; // = namefile();
// // console.log(fnm);
// document.getElementById('filename').value = fnm;
process_localstorage();
Storage.prototype.setObj = function(key, obj) {
return this.setItem(key, JSON.stringify(obj))
}
Storage.prototype.getObj = function(key) {
return JSON.parse(this.getItem(key))
}
function my_LS_get_obj(key) {
return JSON.parse(localStorage.getItem(key));
}
// Template page layout
function plot_page_layout(page_n, form_type) {
// let h0 = (page_n - 1) * ha4;
let i = page_n - 1;
// canvas elements
ctxs[i].beginPath();
ctxs[i].font = '20px ' + myfont;
ctxs[i].fillText(form_type, border, 100);
// ctxs[i].fillText('ESTIMATE', border, 100);
ctxs[i].font = 'bold 12px ' + myfont;
ctxs[i].fillText('BANK NAME:', border, h_bank);
ctxs[i].fillText('ACCOUNT NAME:', border, h_bank + hline);
ctxs[i].fillText('ACCOUNT NUMBER:', border, h_bank + hline * 2);
ctxs[i].fillText('SORT CODE:', border, h_bank + hline * 3);
ctxs[i].font = 'bold 12px ' + myfont;
ctxs[i].fillText('ISSUE DATE:', wa4 / 2 + margin, h_issue);
ctxs[i].fillText('DUE DATE:', wa4 / 2 + margin, h_issue + hline);
ctxs[i].fillText('REFERENCE:', wa4 / 2 + margin, h_issue + hline * 2);
ctxs[i].font = 'bold 12px ' + myfont;
ctxs[i].fillText('BILL TO:', border, h_billtosite);
ctxs[i].fillText('SITE / LOCATION:', wa4 / 2 + margin, h_billtosite);
ctxs[i].stroke();
}
function plot_page_interpersonal(page_n, date_due, my_ref) {
// let h0 = (page_n - 1) * ha4;
let i = page_n - 1;
ctxs[i].font = '14px ' + myfont;
ctxs[i].fillText(localStorage.my_b_name, border, h_my_b );
ctxs[i].font = '12px ' + myfont;
ctxs[i].fillText(localStorage.my_b_address1, border, h_my_b+hline*1);
ctxs[i].fillText(localStorage.my_b_address2, border, h_my_b+hline*2);
ctxs[i].fillText(localStorage.my_b_address3, border, h_my_b+hline*3);
ctxs[i].fillText(localStorage.my_b_address4, border, h_my_b+hline*4);
ctxs[i].fillText(localStorage.my_b_address5, border, h_my_b+hline*5);
ctxs[i].fillText(localStorage.my_b_email, border, h_my_b+hline*6);
ctxs[i].fillText(localStorage.my_b_number, border, h_my_b+hline*7);
// logo
var img = new Image();
img.crossOrigin = "anonymous";
CORS_ALLOW_ALL_ORIGINS = true;
img.style.border = 'none';
img.src = url_logo; // "https://raw.githubusercontent.com/Teddy-1024/Neural_Network/master/Deane_logo.png";
sz_img = 200;
img.onload = function() {
ctxs[i].drawImage(img, wa4 - border * 3 / 2 -sz_img, border, sz_img, sz_img); // , 0, 0, 0, 0, border + 25, border + 2, sz_img, sz_img);
ctxs[i].stroke();
}
ctxs[i].font = '12px ' + myfont;
ctxs[i].fillText(localStorage.bank_name, border + 150, h_bank);
ctxs[i].fillText(localStorage.bank_AC_name, border + 150, h_bank + hline);
ctxs[i].fillText(localStorage.bank_AC_no, border + 150, h_bank + hline * 2);
ctxs[i].fillText(localStorage.bank_SC, border + 150, h_bank + hline * 3);
ctxs[i].font = '12px ' + myfont;
ctxs[i].fillText(localStorage.date, wa4 / 2 + margin + 120, h_issue);
ctxs[i].fillText(date_due, wa4 / 2 + margin + 120, h_issue + hline);
ctxs[i].fillText(my_ref, wa4 / 2 + margin + 120, h_issue + hline * 2);
ctxs[i].font = '12px ' + myfont;
ctxs[i].fillText(localStorage.to_b_name, border, h_billtosite+hline*1);
ctxs[i].fillText(localStorage.to_b_address1, border, h_billtosite+hline*2);
ctxs[i].fillText(localStorage.to_b_address2, border, h_billtosite+hline*3);
ctxs[i].fillText(localStorage.to_b_address3, border, h_billtosite+hline*4);
ctxs[i].fillText(localStorage.to_b_address4, border, h_billtosite+hline*5);
ctxs[i].fillText(localStorage.to_b_address5, border, h_billtosite+hline*6);
ctxs[i].fillText(localStorage.to_b_email, border, h_billtosite+hline*7);
ctxs[i].fillText(localStorage.to_b_phone, border, h_billtosite+hline*8);
ctxs[i].fillText(localStorage.client_contact, wa4/2 + margin, h_billtosite+hline*1);
ctxs[i].fillText(localStorage.client_name, wa4/2 + margin, h_billtosite+hline*2);
ctxs[i].fillText(localStorage.client_address1, wa4/2 + margin, h_billtosite+hline*3);
ctxs[i].fillText(localStorage.client_address2, wa4/2 + margin, h_billtosite+hline*4);
ctxs[i].fillText(localStorage.client_address3, wa4/2 + margin, h_billtosite+hline*5);
ctxs[i].fillText(localStorage.client_address4, wa4/2 + margin, h_billtosite+hline*6);
ctxs[i].stroke();
}
function round_down(quotient) {
let temp = quotient % 1;
return quotient - temp;
}
function round_up(quotient) {
let temp = quotient % 1;
if (temp == 0) {
return quotient;
}
return 1 + quotient - temp;
}
function plot_line_gs(description, quantity, rate, subtotal, h, page_i) {
let i = page_i - 1;
ctxs[i].font = '12px ' + myfont;
ctxs[i].fillText(description, w_tc1, h);
ctxs[i].fillText(quantity, w_tc2, h);
ctxs[i].fillText(rate, w_tc3, h);
ctxs[i].fillText(subtotal, w_tc4, h);
}
function plot_line_pp(description, date, value, h, page_i) {
let i = page_i - 1;
ctxs[i].font = '12px ' + myfont;
ctxs[i].fillText(description, w_tc1, h);
ctxs[i].fillText(date, (w_tc2 + w_tc3) / 2, h);
ctxs[i].fillText(value, w_tc4, h);
}
function plot_table_headings_payplan(h, page_i) {
let i = page_i - 1;
let currency = localStorage.getItem('currency');
ctxs[i].font = 'bold 12px ' + myfont;
ctxs[i].fillText('DESCRIPTION', w_tc1 + 20, h);
ctxs[i].fillText('DATE', (w_tc2 + w_tc3 + 25) / 2, h);
ctxs[i].fillText('VALUE [' + currency + ']', w_tc4 - 16, h);
// latinum conversion rates
// 500 .bars, 10,000 .strips, 1,000,000 .slips
}
function plot_table_headings_invest(ratedisc, h, page_i) {
let i = page_i - 1;
let currency = localStorage.getItem('currency');
ctxs[i].font = 'bold 12px ' + myfont;
ctxs[i].fillText('DESCRIPTION', w_tc1 + 30, h);
if (ratedisc[0] == 'Unit cost') {
ctxs[i].fillText('QUANTITY', w_tc2 - 20, h);
ctxs[i].fillText('UNIT COST [' + currency + ']', w_tc3 - 12, h);
} else {
ctxs[i].fillText(currency + ' / ' + ratedisc[0], w_tc3 - 12, h);
ctxs[i].fillText('# ' + ratedisc[1], w_tc2 - 20, h);
}
ctxs[i].fillText('SUBTOTAL', w_tc4-10, h);
}
function plot_subtotal(tot, h, page_i) {
let i = page_i - 1;
ctxs[i].font = '12px ' + myfont;
ctxs[i].fillText('£ ' + tot.toFixed(2), w_tc4 - 10, h);
ctxs[i].font = 'bold 12px ' + myfont;
ctxs[i].fillText('TOTAL:', w_tc4 - border - 10, h);
}
function plot_invest(form_type, do_goods, rows_g, n_goods, do_services, rows_s, n_services, n_subs, ratedisc, date_due, my_ref) {
let txt_base_border = 0.5 * hline;
let min_table_delta = 2 * hline + txt_base_border;
let max_table_height = 1000;
// // ctx.beginPath();
// ctx.font = '20px ' + myfont;
// ctx.fillText(form_type, border, 100);
let n_plotted = 0;
let page_i = 0;
// let h0 = (page_i - 1) * ha4;
let h1 = 0;
// ctx.font = '12px ' + myfont;
let subtotal;
// goods
if (do_goods) {
subtotal = 0;
for (let row_i = 0; row_i < n_goods; row_i++) {
h1 = h_tablehead + (row_i - n_plotted) * hline;
if (row_i % max_rows == 0) {
page_i++;
n_plotted = row_i - 1;
// h0 = (page_i - 1) * ha4;
// plot new page
// ctxs[page_i - 1].font = '20px ' + myfont;
// ctxs[page_i - 1].fillText(form_type, border, 100);
ctxs[page_i - 1].font = '12px ' + myfont;
plot_page_layout(page_i, form_type);
plot_page_interpersonal(page_i, date_due, my_ref);
plot_table_headings_invest(['Unit cost'], h_tablehead, page_i);
}
h1 = h_tablehead + (row_i - n_plotted) * hline;
plot_line_gs(rows_g[row_i][0], rows_g[row_i][1], rows_g[row_i][2], rows_g[row_i][3], h1, page_i);
subtotal += Number( rows_g[row_i][3]);
}
// output subtotal
h1 += hline;
plot_subtotal(subtotal, h1, page_i);
}
// services
if (do_services) {
if (!do_goods) {
page_i++;
h1 = h_tablehead;
ctxs[0].font = '12px ' + myfont;
plot_page_layout(page_i, form_type);
plot_page_interpersonal(page_i, date_due, my_ref);
}
for (let i = 0; i < n_services; i++) {
subtotal = 0;
if (max_table_height - min_table_delta < h1) {
// new page, reset start height
page_i++;
// h0 = (page_i - 1) * ha4;
h1 = h_tablehead;
// plot new page
// ctxs[page_i - 1].font = '20px ' + myfont;
// ctxs[page_i - 1].fillText(form_type, border, 100);
ctxs[page_i - 1].font = '12px ' + myfont;
plot_page_layout(page_i, form_type);
plot_page_interpersonal(page_i, date_due, my_ref);
} else {
h1 += hline * 1.2;
}
// plot table headings
plot_table_headings_invest(ratedisc[i], h1, page_i);
// plot rows
for (let j = 0; j < n_subs[i]; j++) {
h1 += hline;
if (max_table_height - txt_base_border < h1) {
// new page, reset start height
page_i++;
// h0 = (page_i - 1) * ha4;
h1 = h_tablehead;
// plot new page
plot_page_layout(page_i, form_type);
plot_page_interpersonal(page_i, date_due, my_ref);
plot_table_headings_invest(ratedisc[i], h1, page_i);
h1 += hline;
}
// plot row
plot_line_gs(rows_s[i][j][0], rows_s[i][j][1], rows_s[i][j][2], rows_s[i][j][3], h1, page_i);
subtotal += Number(rows_s[i][j][3]);
}
// output subtotal
h1 += hline;
plot_subtotal(subtotal, h1, page_i);
}
}
if (page_i < n_pages) {
let canvas_container = document.getElementById('parent_canvases');
for (let i = page_i + 1; i <= n_pages; i++) {
canvas_container.removeChild(document.getElementById('canvas_' + i));
}
n_pages = page_i;
}
}
function plot_payplan(rows_p, n_pay, my_ref) {
let txt_base_border = 0.5 * hline;
let min_table_delta = 1 * hline + txt_base_border;
let max_table_height = 1000;
// ctx.beginPath();
// ctx.font = '20px ' + myfont;
// ctx.fillText('PAYMENT-PLAN', border, 100);
let n_plotted = 0;
let page_i = 0;
// let h0 = (page_i - 1) * ha4;
let h1;
// ctx.font = '12px ' + myfont;
let subtotal = 0;
// goods
if (n_pay >= 1) {
for (let row_i = 0; row_i < n_pay; row_i++) {
h1 = h_tablehead + (row_i - n_plotted) * hline;
if (row_i % max_rows == 0) {
page_i++;
// h0 = (page_i - 1) * ha4;
n_plotted = row_i - 1;
// plot new page
plot_page_layout(page_i, 'PAYMENT-PLAN');
plot_page_interpersonal(page_i, rows_p[n_pay - 1][1], my_ref);
plot_table_headings_payplan(h_tablehead, page_i);
}
h1 = h_tablehead + (row_i - n_plotted) * hline;
plot_line_pp(rows_p[row_i][0], rows_p[row_i][1], rows_p[row_i][2], h1, page_i);
subtotal += Number(rows_p[row_i][2]);
}
// output subtotal
h1 += hline;
plot_subtotal(subtotal, h1, page_i);
}
// ctx.stroke();
}
// borders
// ctx.strokeStyle = "blue";
// ctx.fillRect(margin, margin, wa4 - 2 * (border - margin - 5), border - margin - 5);
// ctx.fillRect(margin, ha4 - margin, wa4 - 2 * (border - margin - 5), border - margin - 5);
// ctx.stroke();
function create_canvases(quantity) {
if (quantity > 1) {
let div_parent = document.getElementById('parent_canvases');
for (let i = 2; i <= quantity; i++) {
let new_canvas = document.createElement('canvas');
new_canvas.id = 'canvas_' + i.toString();
new_canvas.width = wa4;
new_canvas.height = ha4;
new_canvas.style.border = 'none';
new_canvas.style.margin = 'auto';
new_canvas.innerText = 'Your browser does not support the HTML5 canvas tag.';
div_parent.appendChild(new_canvas);
canvases.push(new_canvas);
ctxs.push(canvases[i - 1].getContext('2d'));
}
}
}
function namefile(form_type, my_ref, date_due = '') {
let svname;
switch (form_type) {
case 'PAYMENT-PLAN':
svname = 'Payment-Plan_' + my_ref + '_' + date_due;
break;
default:
// let endweek = Number(localStorage.week1) + Number(localStorage.nweeks - 1);
// svname = 'Invoice_Contechs_00-J55589_' + localStorage.date.substr(2, 2) + '_wks_';
// svname = svname.concat(localStorage.week1);
// svname = svname.concat('-');
// svname = svname.concat(endweek);
// Chassis Business Process Analyst 00-J55589
// svname = form_type.charAt(0) + form_type.substring(1, form_type.length).toLowerCase() + '_Contechs_00-J55589_' + my_ref;
// RADs Software Engineer 00-J56557
// svname = form_type.charAt(0) + form_type.substring(1, form_type.length).toLowerCase() + '_Contechs_00-J56557_' + my_ref;
svname = "file_reference"
break;
}
document.getElementById('filename').value = svname;
return svname;
}
function imgclick(canvas_i) { // download file!
const {
jsPDF
} = window.jspdf;
const pdf = new jsPDF();
const imgData = canvases[canvas_i].toDataURL("image/png", 1.0);
pdf.addImage(imgData, 'PNG', 0, 0);
pdf.save(document.getElementById('filename').value + '_' + (canvas_i + 1).toString());
// mailsend(pdf);
}
function download_pdfs(download_type = 'separate') {
// download type = 'together' (default) or 'separate'
// switch (download_type) {
// case 'separate':
for (let i = 0; i < n_pages; i++) {
imgclick(i);
}
// break;
// default:
// const {
// jsPDF
// } = window.jspdf;
// const doc = new jsPDF();
// const arrayBuffer = doc.output('arraybuffer');
// let pdf_list = [];
// for (let canvas_i = 0; canvas_i < n_pages; canvas_i++) {
// const pdf = new jsPDF();
// const imgData = canvases[canvas_i].toDataURL("image/png", 1.0);
// pdf.addImage(imgData, 'PNG', 0, 0);
// }
// let merged_pdf = mergePdfs(pdf_list);
// merged_pdf.save(document.getElementById('filename').value);
// break;
// }
}
// async function mergePdfs(pdfsToMerges) { // : ArrayBuffer[]
// const mergedPdf = await PDFDocument.create();
// const actions = pdfsToMerges.map(async pdfBuffer => {
// const pdf = await PDFDocument.load(pdfBuffer);
// const copiedPages = await mergedPdf.copyPages(pdf, pdf.getPageIndices());
// copiedPages.forEach((page) => {
// // console.log('page', page.getWidth(), page.getHeight());
// // page.setWidth(210);
// mergedPdf.addPage(page);
// });
// });
// await Promise.all(actions);
// const mergedPdfFile = await mergedPdf.save();
// return mergedPdfFile;
// }
function gen_inv_ID(companycode, week1, weekn, date) {
let year = date.substr(2, 2);// date.getFullYear();
let name = year + "_wks_" + week1 + "-" + weekn;
return name;
}
function gen_date_due(date0) {
let date_0 = new Date(date0);
let y0 = date_0.getFullYear();
let m0 = date_0.getMonth();
// let d0 = date0.getDate();
// let month = Number(date.substr(5, 2));
// let year = Number(date.substr(0, 4));
let date_1 = new Date(y0, m0 + 2, 1);
// if (month >= 11) {
// year = year + 1;
// month = month - 10;
// } else {
// month = month + 2;
// }
let n_working_days = 1;
let n_days_total = 4;
let date_temp = date_1;
for (let i = 1; i < 6; i++) {
date_temp.setDate(date_temp.getDate() + 1);
let billday = date_temp.getDay();
if (!(billday == 0 || billday == 6)) {
n_working_days++;
}
if (n_working_days == n_days_total) {
break;
}
}
let date_2 = date_temp;
return date2str(date_2);
// for (let i = 0; i < 6; i++) {
// billday = i + 1;
// let tempbilldate = new Date(year.toString() + '-' + month.toString().padStart(2, '0') + '-' + billday.toString().padStart(2, '0'));
// let tempbillday = tempbilldate.getDay(); // {Sunday - Saturday = 0 - 6}
// if (!(tempbillday == 0 || tempbillday == 6)) {
// n_working_days++;
// }
// if (n_working_days == n_days_total) {
// break;
// }
// }
// return year.toString() + '-' + month.toString().padStart(2, '0') + '-' + billday.toString().padStart(2, '0');
}
function date2str(date_in) {
return date_in.getFullYear().toString() + '-' + (date_in.getMonth() + 1).toString().padStart(2, '0') + '-' + date_in.getDate().toString().padStart(2, '0');
}
function process_localstorage() {
// find form type and get rows
let form_type = localStorage.getItem('form_type');
console.log('form type = ' + form_type);
switch (form_type) {
case 'PAYMENT-PLAN':
let n_pay = Number(localStorage.getItem('payments_n'));
let paytype = localStorage.getItem('paytype');
let values = [];
let dates = [];
let rows_p = [];
switch (paytype) {
case 'linear':
values.push(localStorage.getItem('pay_value_unit'));
if (n_pay > 1) {
for (let i = 1; i < n_pay; i++) {
values.push(values[0]);
}
}
break;
case 'multiplier':
let value_0 = Number(localStorage.getItem('pay_value_unit'));
let multipliers = my_LS_get_obj('multiplier');
if (n_pay > 1) {
for (let i = 0; i < n_pay; i++) {
values.push((value_0 * multipliers[i]).toString());
}
}
break;
case 'random':
let randoms = my_LS_get_obj('value');
if (n_pay > 1) {
for (let i = 0; i < n_pay; i++) {
values.push(randoms[i]);
}
}
break;
}
let description = localStorage.getItem('description');
// let discretisation = localStorage.getItem('discretisation');
// let payscheme = localStorage.getItem('payscheme');
let dates_in = my_LS_get_obj('dates');
// let disc_quantity = Number(localStorage.getItem('disc_quantity'));
for (let i = 0; i < n_pay; i++) {
dates.push(date2str(new Date(dates_in[i])));
}
for (let i = 0; i < n_pay; i++) {
rows_p.push([description, dates[i], values[i]]);
}
n_pages = round_up(n_pay / max_rows)
// canvas.height = ha4 * n_pages;
fnm = namefile(form_type, localStorage.week1, dates[0]);
create_canvases(n_pages);
plot_payplan(rows_p, n_pay, localStorage.week1);
break;
default: // case 'INVOICE' || 'ESTIMATE':
let inv_ref = gen_inv_ID(localStorage.to_b_code, localStorage.week1, String(Number(localStorage.week1) + Number(localStorage.subservice_quantities.substring(2, localStorage.subservice_quantities.substring(2).indexOf('"') + 2)) - 1), localStorage.date);
let date_due = gen_date_due(localStorage.date);
let rows_g = [];
let nrows_g = 0;
let goods_n = 0;
let rows_s = [];
// let n_services = 0;
let services_n;
let n_subs = [];
// let durnrates = [];
let do_goods = localStorage.getItem('bool_goods') == 'true';
if (do_goods) {
goods_n = Number(localStorage.getItem('goods_n'));
let mygoods_n = my_LS_get_obj('mygoods_n');
let mygoods_q = my_LS_get_obj('mygoods_q');
let mygoods_v = my_LS_get_obj('mygoods_v');
for (let i = 1; i <= goods_n; i++) {
nrows_g++;
rows_g.push([mygoods_n[i - 1], mygoods_q[i - 1], mygoods_v[i - 1], (Number(mygoods_v[i - 1]) * Number(mygoods_q[i - 1])).toFixed(2)]);
}
n_pages = round_up(goods_n / max_rows);
}
let do_services = localStorage.getItem('bool_services') == 'true';
let ratediscs;
// let durndiscs;
if (do_services) {
// n_services = 1;
services_n = Number(localStorage.getItem('services_n'));
ratediscs = my_LS_get_obj('ratediscs');
// durndiscs = my_LS_get_obj('durndiscs');
let rates = my_LS_get_obj('rates');
// let durn_disc_qs = my_LS_get_obj('durn_disc_qs');
let description = my_LS_get_obj('descriptions');
let quantities = my_LS_get_obj('quantities');
let subservice_quantities = my_LS_get_obj('subservice_quantities');
for (let i = 1; i <= services_n; i++) {
// let my_serve = -1;
// for (let j = 0; j < n_subs[i - 1]; j++) {
// if (durnrates[j][0] == durndiscs[i - 1] && durnrates[j][1] == ratediscs[i - 1]) {
// my_serve = j;
// break;
// }
// }
// if (my_serve == -1) {
// my_serve = n_services - 1;
n_subs.push(0);
// durnrates.push([durndiscs[i - 1], ratediscs[i - 1]]);
rows_s.push([]);
// n_services++;
// }
for (let j = 1; j <= Number(subservice_quantities[i - 1]); j++) {
n_subs[i - 1]++;
rows_s[i - 1].push([description[i - 1][j - 1], quantities[i - 1][j - 1], rates[i - 1], (Number(quantities[i - 1][j - 1]) * Number(rates[i - 1])).toFixed(2)]);
}
n_pages += round_up(n_subs[i - 1] / max_rows);
}
}
// canvas.height = ha4 * n_pages;
fnm = namefile(form_type, inv_ref);
create_canvases(n_pages);
plot_invest(form_type, do_goods, rows_g, goods_n, do_services, rows_s, services_n, n_subs, ratediscs, date_due, inv_ref);
break;
}
}