method/export.js

/**
 * @module method/export
 *
 * @requires method/generate
 */

const functions = require('firebase-functions');
const admin = require('firebase-admin');
const puppeteer = require('puppeteer');
const streamifier = require('streamifier');
const {version} = require('../package');

const generate = require('./generate');

const bucket = admin.storage().bucket();

/**
 * Export the contract pdf to Firebase storage
 *
 * @param  {borrower} borrower - Borrower-related data from Loandisk.
 * @param  {loan} loan - Loan-related data from Loandisk.
 * @param  {loanSchedules} loanSchedules - Original loan schedule of the loan
 * with only repayment and maturity.
 *
 * @return {string} URL to the saved contract.
 */
const pdfExport = (borrower, loan, loanSchedule) => {
  // Assign
  const uid = borrower.custom_field_3012;

  // Assign reference to cloud storage
  const storageRef = bucket.file(`contracts/${uid}/${loan.loan_application_id}_${Date.now()}.pdf`);

  // Use Puppeteer to generate a pdf buffer promise
  const pdf = async () => {
    let buffer = null;
    let browser = null;

    try {
      browser = await puppeteer.launch({
        args: ['--no-sandbox'],
        headless: true,
      });

      // Create a page
      const page = await browser.newPage();

      // Set HTML output to page
      await page.setContent(generate(borrower, loan, loanSchedule, true));

      // Generate pdf buffer
      buffer = await page.pdf({
        format: 'A4',
        margin: {
          top: '2cm',
          right: '2cm',
          bottom: '3.75cm',
          left: '2cm',
        },
        displayHeaderFooter: true,
        headerTemplate: `
          <p style="font-family:'Times New Roman', serif; text-align: right; width: 100%; margin: 0 2cm; font-size: 10px">
            v${version}
          </p>
        `,
        footerTemplate: `
          <p style="font-family:'Times New Roman', serif; text-align: center; width: 100%; font-size: 10px">
            Warning: You have to repay your loans<br>
            Do not pay any intermediaries<br>
            Information hotline: 9847 4943
          </p>
        `,
      });
    } catch (err) {
      throw new functions.https.HttpsError(err);
    } finally {
      if (browser !== null) {
        // Close the browser
        await browser.close();
      }
    }

    // Finally return the pdf buffer
    return Promise.resolve(buffer);
  }

  // Get the buffer out of the promise
  return pdf().then((buffer) => {
    return new Promise((resolve, reject) => {
      // Create an upload stream to cloud storage
      const uploadStream = streamifier.createReadStream(buffer)
          .pipe(storageRef.createWriteStream({
            metadata: {
              contentType: 'application/pdf',
            }
          }));

      // If uploadStream comes back finished
      uploadStream.on('finish', resolve);

      // If uploadStream comes back with an error
      uploadStream.on('error', (err) => {
        reject(new Error('Failed to upload contract: ' + err));
      })
    })
  }).then(() => {
    return storageRef.makePublic();
  }).then((result) => {
    const {bucket, object} = result[0];
    return `https://storage.googleapis.com/${bucket}/${object}`;
  }).catch((err) => {
    throw new functions.https.HttpsError(err);
  });
};

module.exports = pdfExport;