diff --git a/AstuteClient2/src/app/invoice-gen/invoice-gen.component.ts b/AstuteClient2/src/app/invoice-gen/invoice-gen.component.ts
index 9d141d9..26ad451 100644
--- a/AstuteClient2/src/app/invoice-gen/invoice-gen.component.ts
+++ b/AstuteClient2/src/app/invoice-gen/invoice-gen.component.ts
@@ -59,7 +59,7 @@ export class InvoiceGenComponent implements OnInit {
this.gridY[j] = y;
y += 10;
}
- this.astuteClientService.getInvoiceGen('MDO-01_DRAFT_720').then((data) => {
+ this.astuteClientService.getInvoiceGen('MDO-01_DRAFT_157').then((data) => {
this.name = data.customer.customerName;
this.email = data.customer.email;
this.address = data.customer.add1 + ' ' + data.customer.add2 + ' ' +
diff --git a/AstuteClient2/src/app/invoice/invoice.component.html b/AstuteClient2/src/app/invoice/invoice.component.html
index 2bb50f2..c444ad8 100644
--- a/AstuteClient2/src/app/invoice/invoice.component.html
+++ b/AstuteClient2/src/app/invoice/invoice.component.html
@@ -48,7 +48,7 @@
-
diff --git a/AstuteClient2/src/app/invoice/invoice.component.ts b/AstuteClient2/src/app/invoice/invoice.component.ts
index 04482e0..8cdb3cc 100644
--- a/AstuteClient2/src/app/invoice/invoice.component.ts
+++ b/AstuteClient2/src/app/invoice/invoice.component.ts
@@ -1,7 +1,7 @@
import {Component, OnInit, ViewChild} from '@angular/core';
import {AstuteClientService} from '../services/astute-client-service';
import {formatCurrency} from "@angular/common";
-import {log} from "util";
+import {PrintInvoiceService} from '../services/print-invoice.service';
declare var $: any;
@@ -91,7 +91,7 @@ export class InvoiceComponent implements OnInit {
}
}
- constructor(protected astuteClientService: AstuteClientService) {
+ constructor(protected astuteClientService: AstuteClientService, protected printService: PrintInvoiceService) {
}
customerDropdownChange(index) {
@@ -231,6 +231,10 @@ export class InvoiceComponent implements OnInit {
window.open('/invoice-gen');
}
+ printInvoice() {
+ this.printService.printPDF (this.chosenInv.invoiceNumber);
+ }
+
getSelectedRows() {
const selectedNodes = this.agGrid.api.getSelectedNodes();
if (selectedNodes.length) {
diff --git a/AstuteClient2/src/app/services/print-invoice.service.spec.ts b/AstuteClient2/src/app/services/print-invoice.service.spec.ts
new file mode 100644
index 0000000..e9bb36d
--- /dev/null
+++ b/AstuteClient2/src/app/services/print-invoice.service.spec.ts
@@ -0,0 +1,15 @@
+import { TestBed, inject } from '@angular/core/testing';
+
+import { PrintInvoiceService } from './print-invoice.service';
+
+describe('PrintInvoiceService', () => {
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ providers: [PrintInvoiceService]
+ });
+ });
+
+ it('should be created', inject([PrintInvoiceService], (service: PrintInvoiceService) => {
+ expect(service).toBeTruthy();
+ }));
+});
diff --git a/AstuteClient2/src/app/services/print-invoice.service.ts b/AstuteClient2/src/app/services/print-invoice.service.ts
new file mode 100644
index 0000000..acab82e
--- /dev/null
+++ b/AstuteClient2/src/app/services/print-invoice.service.ts
@@ -0,0 +1,333 @@
+import { Injectable } from '@angular/core';
+import {AstuteClientService} from '../services/astute-client-service';
+import {formatCurrency} from '@angular/common';
+
+declare var html2pdf: any;
+declare var html2canvas: any;
+declare var jsPDF: any;
+declare var $: any;
+
+@Injectable({
+ providedIn: 'root'
+})
+export class PrintInvoiceService {
+
+ gridX = []; // these are the layout grid STARTING
+ gridY = []; // from the 1 inch border (x: 25; y:23)
+
+ name: string;
+ email: string;
+ address: string;
+
+ poNum;
+ coNum;
+ inNum;
+ inDate;
+
+ inDetails; // :[{lineNum:number, desc:string, rate:string, hrs:number, amount:number}];
+
+ ogCoAmt;
+ netChanges = 0;
+ totCoAmt = 0;
+ prevBill;
+ inAmt;
+ balToBeBill;
+ subTotal; // =inAmt
+ milage = 0;
+ otherExp = 0;
+ outOf = 0;
+ finTot; // = inAmt;
+
+ notes;
+ cert;
+
+ constructor(protected astuteClientService: AstuteClientService) {
+ let x = 28.5;
+ let y = 25;
+ for (let i = 0; i < 17; i++) { //
+ this.gridX[i] = x;
+ x += 10;
+ }
+ for (let j = 0; j < 24; j++) {
+ this.gridY[j] = y;
+ y += 10;
+ }
+ }
+
+ printPDF(invoice: string) {
+ this.astuteClientService.getInvoiceGen(invoice).then((data) => {
+ this.name = data.customer.customerName;
+ this.email = data.customer.email;
+ this.address = data.customer.add1 + ' ' + data.customer.add2 + ' ' +
+ data.customer.city + ', ' + data.customer.state.toUpperCase() + ', ' +
+ data.customer.zip + '-' + data.customer.ziplast4;
+
+ this.poNum = data.po.ponum;
+ this.coNum = data.po.contractNum;
+ this.inNum = data.invoice.invoiceNumber;
+ this.inDate = data.invoice.invoiceDate;
+
+ this.inDetails = data.invoiceDetail;
+
+ this.ogCoAmt = data.po.contractAmt;
+ this.netChanges = 0;
+ this.totCoAmt = data.po.contractAmt;
+ this.prevBill = data.po.previouslyBilledAmount;
+ this.balToBeBill = data.balanceToBeBilled;
+ this.finTot = data.invoice.billAmt;
+
+ this.notes = data.invoice.specialNotes;
+ this.cert = data.invoice.certification;
+
+ this.testjsPDF(invoice);
+ });
+ }
+
+ private testjsPDF(invoice: string) {
+ const doc = jsPDF('p', 'mm', 'letter');
+ console.log(doc.getFontList());
+ // this.printGrid(doc);
+ this.printHeader(doc);
+ let len = this.inDetails.length;
+ if (len <= 6) {
+ this.printTable(doc, 7, 13, this.inDetails);
+ } else if (len > 6 && len <= 28) {
+ this.printTable(doc, 7, 22, this.inDetails.slice(0, 15));
+ doc.addPage('letter', 'p');
+ this.printTable(doc, 0, 13, this.inDetails.slice(15, 28));
+ } else {
+ this.printTable(doc, 7, 22, this.inDetails.slice(0, 15));
+ len -= 15;
+ let i = 0;
+ while (len > 13) {
+ doc.addPage('letter', 'p');
+ this.printTable(doc, 0, 22, this.inDetails.slice(15 + (22 * i), 37 + (22 * i)));
+ i++;
+ }
+ doc.addPage('letter', 'p');
+ this.printTable(doc, 0, 13, this.inDetails.slice(37 + (22 * (i - 1))));
+ }
+ this.printFooter(doc);
+ doc.save(invoice + '.pdf');
+ }
+
+ private printHeader (doc) {
+ if (!doc) {
+ doc = jsPDF('p', 'mm', 'letter');
+ }
+ ///////////////////// Header //////////
+ // Logo and INVOICE
+ doc.setFontSize(35);
+ doc.text('INVOICE', this.gridX[10] + 5, this.gridY[2] - 5);
+ doc.addImage('assets/img/AstuteLogo.png', 'png', this.gridX[0], this.gridY[0], 50, 22.04);
+
+ // To, customer
+ doc.setFontSize(12);
+ doc.text('To,', this.gridX[0], this.gridY[3]);
+ const nameSplit = doc.splitTextToSize(this.name, 65);
+ nameSplit.forEach((text, i) => {
+ doc.text(text, this.gridX[0] + 5, this.gridY[3] + (5 * (i + 1)));
+ });
+ doc.setTextColor(66, 144, 255);
+ const emailSplit = doc.splitTextToSize(this.email, 65);
+ emailSplit.forEach((text, i) => {
+ doc.text(text, this.gridX[0] + 5, this.gridY[4] + (5 * (i + 1)));
+ });
+ doc.setTextColor(0);
+ const addressSplit = doc.splitTextToSize(this.address, 65);
+ addressSplit.forEach((text, i) => {
+ doc.text(text, this.gridX[0] + 5, this.gridY[5] + (5 * (i + 1)));
+ });
+
+ // Invoice Information
+ doc.text('Purchase Order #:', this.gridX[11], this.gridY[3], {'align': 'right'});
+ const poNumSplit = doc.splitTextToSize(' ' + this.poNum, 50);
+ poNumSplit.forEach((text, i) => {
+ doc.text(text, this.gridX[11], this.gridY[3] + (5 * i));
+ });
+
+ doc.text('Contract #:', this.gridX[11], this.gridY[4], {'align': 'right'});
+ const coNumSplit = doc.splitTextToSize(' ' + this.coNum, 50);
+ coNumSplit.forEach((text, i) => {
+ doc.text(text, this.gridX[11], this.gridY[4] + (5 * i));
+ });
+
+ doc.text('Invoice #:', this.gridX[11], this.gridY[5], {'align': 'right'});
+ const inNumSplit = doc.splitTextToSize(' ' + this.inNum, 50);
+ inNumSplit.forEach((text, i) => {
+ doc.text(text, this.gridX[11], this.gridY[5] + (5 * i));
+ });
+
+ doc.text('Invoice Date:', this.gridX[11], this.gridY[6], {'align': 'right'});
+ const inDateSplit = doc.splitTextToSize(' ' + this.inDate, 50);
+ inDateSplit.forEach((text, i) => {
+ doc.text(text, this.gridX[11], this.gridY[6] + (5 * i));
+ });
+ ///////////////////////////////////////
+ if (!doc) {
+ doc.autoPrint({variant: 'non-conform'});
+ doc.save('grid.pdf');
+ }
+ }
+
+ private printTable (doc, start, end, details) {
+ if (!doc) {
+ doc = jsPDF('p', 'mm', 'letter');
+ }
+ ///////////////////// Table ///////////
+ doc.setLineWidth(.25);
+ doc.setDrawColor(170);
+
+ // Number Column (header and rows)
+ doc.setFillColor(225);
+ doc.rect(this.gridX[0], this.gridY[start], 10, 10, 'FD');
+ doc.text('#', this.gridX[0] + 5, this.gridY[start + 1] - 3.5, {'align': 'center'});
+ for (let i = start + 1; i <= end; i++) {
+ doc.rect(this.gridX[0], this.gridY[i], 10, 10);
+ }
+
+ // Description Column (header and rows)
+ doc.setFillColor(225);
+ doc.rect(this.gridX[1], this.gridY[start], 70, 10, 'FD');
+ doc.text('Description', this.gridX[4] + 5, this.gridY[start + 1] - 3.5, {'align': 'center'});
+ for (let i = start + 1; i <= end; i++) {
+ doc.rect(this.gridX[1], this.gridY[i], 70, 10);
+ }
+
+ // Fee Column (header and rows)
+ doc.setFillColor(225);
+ doc.rect(this.gridX[8], this.gridY[start], 30, 10, 'FD');
+ doc.text('Fee', this.gridX[9] + 5, this.gridY[start + 1] - 3.5, {'align': 'center'});
+ for (let i = start + 1; i <= end; i++) {
+ doc.rect(this.gridX[8], this.gridY[i], 30, 10);
+ }
+
+ // Quantity Column (header and rows)
+ doc.setFillColor(225);
+ doc.rect(this.gridX[11], this.gridY[start], 20, 10, 'FD');
+ doc.text('Qty.', this.gridX[12], this.gridY[start + 1] - 3.5, {'align': 'center'});
+ for (let i = start + 1; i <= end; i++) {
+ doc.rect(this.gridX[11], this.gridY[i], 20, 10);
+ }
+
+ // Amount Column (header and rows)
+ doc.setFillColor(225);
+ doc.rect(this.gridX[13], this.gridY[start], 30, 10, 'FD');
+ doc.text('Amount', this.gridX[14] + 5, this.gridY[start + 1] - 3.5, {'align': 'center'});
+ for (let i = start + 1; i <= end; i++) {
+ doc.rect(this.gridX[13], this.gridY[i], 30, 10);
+ }
+
+ // Filling Data
+ doc.setFontSize(12);
+ details.forEach((inDet, i) => {
+ doc.text(inDet.lineItemNum.toString(), this.gridX[0] + 5, this.gridY[start + 2 + i] - 3.5, {'align': 'center'});
+
+ doc.setFontSize(11);
+ const descSplit = doc.splitTextToSize(inDet.desc, 66);
+ descSplit.forEach((text, j) => {
+ doc.text(text, this.gridX[1] + 2, this.gridY[start + 1 + i] + (4 * (j + 1)));
+ });
+
+ doc.setFontSize(12);
+ const fee = formatCurrency(inDet.fee, 'en-US', '$', 'USD').split('.')[0] + ((inDet.feeTypeId === 2) ? '/hr' : '');
+ doc.text(fee, this.gridX[11] - 3.5, this.gridY[start + 2 + i] - 3.5, {'align': 'right'});
+
+ doc.text(inDet.qty.toString(), this.gridX[13] - 3.5, this.gridY[start + 2 + i] - 3.5, {'align': 'right'});
+
+ const amt = formatCurrency(inDet.fee * inDet.qty, 'en-US', '$', 'USD');
+ doc.text(amt, this.gridX[16] - 3.5, this.gridY[start + 2 + i] - 3.5, {'align': 'right'});
+ });
+ ///////////////////////////////////////
+ if (!doc) {
+ doc.autoPrint({variant: 'non-conform'});
+ doc.save('table.pdf');
+ }
+ }
+
+ private printFooter (doc) {
+ if (!doc) {
+ doc = jsPDF('p', 'mm', 'letter');
+ }
+ ///////////////////// Footer //////////
+ doc.setFontSize(12);
+
+ // Invoice Bill Info Section
+ doc.setLineWidth(.25);
+ doc.setDrawColor(170);
+ doc.rect(this.gridX[0], this.gridY[15], 160, 50);
+ doc.text('Original Contract Amt.', this.gridX[5] - 3.5, this.gridY[16] - 3.5, {align: 'right'});
+ doc.text('Net Changes by CO\'s', this.gridX[5] - 3.5, this.gridY[17] - 3.5, {align: 'right'});
+ doc.text('Total Contract Amt.', this.gridX[5] - 3.5, this.gridY[18] - 3.5, {align: 'right'});
+ doc.text('Previously Billed', this.gridX[5] - 3.5, this.gridY[19] - 3.5, {align: 'right'});
+ doc.text('Balance to be Billed', this.gridX[5] - 3.5, this.gridY[20] - 3.5, {align: 'right'});
+ for (let i = 15; i <= 19; i++) {
+ doc.setFillColor(225);
+ doc.rect(this.gridX[5], this.gridY[i], 30, 10, 'FD');
+ }
+ doc.setFont('helvetica', 'bold');
+ doc.text('Total Due this Invoice', this.gridX[13] - 3.5, this.gridY[16] - 3.5, {align: 'right'});
+ doc.setFont('helvetica', 'normal');
+ doc.setFillColor(225);
+ doc.rect(this.gridX[13], this.gridY[15], 30, 10, 'FD');
+
+ // Fill Data
+ const ogCoAmt = formatCurrency(this.ogCoAmt, 'en-US', '$', 'USD');
+ doc.text(ogCoAmt, this.gridX[8] - 3.5, this.gridY[16] - 3.5, {align: 'right'});
+
+ const netChanges = formatCurrency(this.netChanges, 'en-US', '$', 'USD');
+ doc.text(netChanges, this.gridX[8] - 3.5, this.gridY[17] - 3.5, {align: 'right'});
+
+ const totCoAmt = formatCurrency(this.totCoAmt, 'en-US', '$', 'USD');
+ doc.text(totCoAmt, this.gridX[8] - 3.5, this.gridY[18] - 3.5, {align: 'right'});
+
+ const prevBill = formatCurrency(this.prevBill, 'en-US', '$', 'USD');
+ doc.text(prevBill, this.gridX[8] - 3.5, this.gridY[19] - 3.5, {align: 'right'});
+
+ const toBeBilled = formatCurrency(this.totCoAmt - this.prevBill - this.finTot, 'en-US', '$', 'USD');
+ doc.text(toBeBilled, this.gridX[8] - 3.5, this.gridY[20] - 3.5, {align: 'right'});
+
+ const finTot = formatCurrency(this.finTot, 'en-US', '$', 'USD');
+ doc.setFont('helvetica', 'bold');
+ doc.text(finTot, this.gridX[16] - 3.5, this.gridY[16] - 3.5, {align: 'right'});
+ doc.setFont('helvetica', 'normal');
+
+ // Notes and Certification
+ doc.text('Notes:', this.gridX[0], this.gridY[20] + 5);
+ const noteSplit = doc.splitTextToSize(this.notes, 145);
+ noteSplit.forEach((text, i) => {
+ doc.text(text, this.gridX[1] + 5, this.gridY[20] + (5 * (i + 1)));
+ });
+ const certSplit = doc.splitTextToSize(this.cert, 160);
+ certSplit.forEach((text, i) => {
+ doc.text(text, this.gridX[0], this.gridY[22] + (5 * i));
+ });
+ doc.line(this.gridX[11], this.gridY[23], this.gridX[16], this.gridY[23]);
+ ///////////////////////////////////////
+ if (!doc) {
+ doc.autoPrint({variant: 'non-conform'});
+ doc.save('footer.pdf');
+ }
+ }
+
+ private printGrid (doc) {
+ if (!doc) {
+ doc = jsPDF('p', 'mm', 'letter');
+ } else {
+ doc.setDrawColor(225);
+ }
+ this.gridX.forEach((x) => {
+ doc.line(x, this.gridY[0], x, this.gridY[this.gridY.length - 1]);
+ // doc.text(x.toString(), x, this.gridY[0]);
+ });
+ this.gridY.forEach((y) => {
+ doc.line(this.gridX[0], y, this.gridX[this.gridX.length - 1], y);
+ // doc.text(y.toString(), this.gridX[0], y);
+ });
+ doc.setDrawColor(0);
+ if (!doc) {
+ doc.autoPrint({variant: 'non-conform'});
+ doc.save('grid.pdf');
+ }
+ }
+}