Custom print with js library

This is my print format which is created using JS library. I need this same format for sales invoice. If I am writing this same code in custom print format then it is not working.

How do I use this code in ERPNext.

const taxInvoice = () => {
  const doc = new jsPDF()
  const smallerWidth = 45
  const smallerHeight = 45
  // Add thumbnail image as full-size cover image on the first page
  const logoImg = '/icons/common/pdf/tax-invoice/houseit-simplified-indigo.png'
  const invoiceLogo = '/icons/common/pdf/tax-invoice/invoice.png'
  const commonSeal = '/icons/common/pdf/tax-invoice/houseit-common-seal.png'

  doc.addImage(logoImg, 'PNG', 150, 0, smallerWidth, smallerHeight)

  const invoiceTo = [
    {
      invoiceTo: 'customer name',
      toTRN: '00000000000000000',
      address: 'xyz addresss',
    },
  ]

  const invoiceFrom = [
    {
      invoiveFrom: 'company name ',
      reference: 'HI-00300',
      fromTRN: '000000000000000000',
      contact: {
        email: 'E : account@gmail.com',
        tel: 'M : 00000',
        mobile: 'M : 00000',
      },
    },
  ]

  let salePriceValue = 84197.0
  let commission = 7135.76
  const invoiceDetails = [
    {
      project: {
        project: 'Empire Estate',
        unit: '613',
      },
      size: '440 sq.Ft',
      startDate: '-',
      salePrice: `AED ${numeral(salePriceValue).format()}`,
      rate: '1%',
      commissionAmmountExlVAT: `AED ${numeral(commission).format()}`,
    },
  ]

  const houseitBankDetails = [
    {
      accountName: 'company name',
      bankName: 'EMIRATES NBD',
      accountNumber: '000000000000',
      ibanNumber: '000000000000000000000',
      branch: 'branch',
    },
  ]

  const invoiceDate = moment().format('Do MMM YYYY')
  const invoiceNo = 'Hi-009876'

  // Calculate the width of the text
  const textWidth =
    (doc.getStringUnitWidth('Tax Invoice') * doc.internal.getFontSize()) /
    doc.internal.scaleFactor

  // Calculate the X-coordinate for centering the text
  let centerX = (doc.internal.pageSize.width - textWidth) / 2

  let yPos = 29
  // Set the font size and text
  doc.setFontSize(16)
  doc.setFont('helvetica', 'bold')
  doc.text('Tax Invoice', centerX, 35)
  doc.addImage(invoiceLogo, 'PNG', 15, yPos, 25, 24)

  yPos = yPos + 30
  doc.setFontSize(10)
  doc.setFont('helvetica', 'normal')
  doc.text('Invoice Date :', 18, yPos - 2)
  doc.text(invoiceDate, 40, yPos - 2)

  doc.text('Invoice No :', 18, yPos + 3)
  doc.text(invoiceNo, 40, yPos + 3)

  // Display Invoice To details
  doc.text('Invoice To :', 18, yPos + 13)
  doc.text(invoiceTo[0].invoiceTo, 40, yPos + 13)

  doc.text('TRN :', 18, yPos + 19)
  doc.text(invoiceTo[0].toTRN, 40, yPos + 19)
  // Manually split the address into three lines
  const address = invoiceTo[0].address
  const addressLines = address.split(/\s+/)
  const maxLineLength = 45 // Maximum characters per line
  const addressLine1 = addressLines.slice(0, 5).join(' ') // First 6 words
  const addressLine2 = addressLines.slice(5, 9).join(' ') // Next 6 words
  const addressLine3 = addressLines.slice(9).join(' ') // Remaining words

  // Display each line of the address separately
  doc.text('Address :', 18, yPos + 25) // Address label
  doc.text(addressLine1, 40, yPos + 25) // First line of the address
  doc.text(addressLine2, 40, yPos + 31) // Second line of the address
  doc.text(addressLine3, 40, yPos + 37) // Third line of the address

  // Display Invoice From details to the right side
  doc.text('Invoice From :', 115, yPos + 13) // Adjust X-coordinate
  doc.text(invoiceFrom[0].invoiveFrom, 139, yPos + 13) // Adjust X-coordinate

  doc.text('Reference No :', 115, yPos + 19) // Adjust X-coordinate
  doc.text(invoiceFrom[0].reference, 139, yPos + 19) // Adjust X-coordinate

  doc.text('TRN :', 115, yPos + 25) // Adjust X-coordinate
  doc.text(invoiceFrom[0].fromTRN, 139, yPos + 25) // Adjust X-coordinate

  // Display contact details
  doc.text('Contact :', 115, yPos + 31) // Adjust X-coordinate
  doc.text(invoiceFrom[0].contact.email, 139, yPos + 31) // Adjust X-coordinate for email

  // Split mobile and telephone numbers into two lines
  const mobileAndTel = `${invoiceFrom[0].contact.mobile}, ${invoiceFrom[0].contact.tel}`
  doc.text(mobileAndTel, 139, yPos + 37) // Adju

  yPos = yPos + 45
  doc.setFontSize(10)
  doc.setFont('helvetica', 'bold')
  doc.setTextColor(80, 80, 80)
  doc.text(
    'Sub : Service Towards Agency Commission for Off-plan Sale in Empire Estate - Arjan Dubai.U.A.E',
    18,
    yPos + 5,
  )
  // Define table dimensions and cell padding
  const tableX = 18 // X-coordinate of the table
  const tableY = yPos + 13 // Y-coordinate of the table
  const cellWidths = [31, 25, 25, 27, 19, 49] // Widths of each cell
  const cellHeights = 18 // Height of each cell - Adjusted for header
  const numRows = invoiceDetails.length // Number of rows in the table
  const headerHeight = 20 // Adjusted height of the header row
  const vatAmount = (salePriceValue / 100) * 5 // VAT Amount
  const totalAmount = salePriceValue + commission + vatAmount // Total Amount Inc. VAT

  // Draw table background
  doc.setFillColor(240) // Light gray color
  doc.rect(
    tableX,
    tableY,
    cellWidths.reduce((a, b) => a + b, 0),
    headerHeight + numRows * cellHeights,
    'F',
  )

  // Draw table header
  doc.setDrawColor(0)
  doc.setFillColor(249, 249, 249)
  doc.setFontSize(10)
  doc.setFont('helvetica', 'bold')
  doc.rect(
    tableX,
    tableY,
    cellWidths.reduce((a, b) => a + b, 0),
    headerHeight,
    'F',
  )
  let currentX = tableX
  const headers = [
    'Project Details',
    'Size',
    `Sale / Rent\nDate`,
    'Sale Price',
    'Rate',
    'Commission Amount Excl VAT',
  ] // Adjusted headers without line break
  for (let i = 0; i < cellWidths.length; i++) {
    // Draw text with wrapping
    const textLines = doc.splitTextToSize(headers[i], cellWidths[i])
    doc.text(textLines, currentX + 2, tableY + headerHeight / 2) // Adjusted position
    currentX += cellWidths[i]
  }

  // Draw table rows
  let currentY = tableY + headerHeight
  for (let i = 0; i < numRows; i++) {
    // Alternate row colors
    if (i % 2 === 0) {
      doc.setFillColor(249)
    } else {
      doc.setFillColor(249)
    }

    // Draw row background
    doc.rect(
      tableX,
      currentY,
      cellWidths.reduce((a, b) => a + b, 0),
      cellHeights,
      'F',
    )

    // Draw row content
    currentX = tableX
    doc.setFont('helvetica', 'normal')
    const rowData = Object.values(invoiceDetails[i])
    // Adjusted rendering for the project object details
    doc.text(
      `${rowData[0].project}\n\nUnit: ${rowData[0].unit}`,
      currentX + 2,
      currentY + 5,
      { align: 'left', valign: 'middle' },
    )
    currentX += cellWidths[0]
    for (let j = 1; j < cellWidths.length; j++) {
      doc.text(String(rowData[j]), currentX + 2, currentY + 8, {
        align: 'left',
        valign: 'middle',
      })
      currentX += cellWidths[j]
    }
    // Draw bottom border for the row content
    doc.setDrawColor(0)
    doc.line(
      tableX,
      currentY + cellHeights,
      tableX + cellWidths.reduce((a, b) => a + b, 0),
      currentY + cellHeights,
    )

    // Move to the next row
    currentY += cellHeights
  }

  // Calculate the end X-coordinate of the upper table
  const upperTableEndX =
    tableX + cellWidths.slice(0, 5).reduce((a, b) => a + b, 0)
  const cellWidth = cellWidths[5] / 2 // Equally divide the width for two cells

  // Draw additional rows below the currentY position
  for (let i = 0; i < 2; i++) {
    const startY = currentY + i * cellHeights // Y-coordinate of the row

    // Draw cell for Key
    doc.setDrawColor(0)
    doc.setFillColor(249, 249, 249)
    const keyX = upperTableEndX
    doc.rect(keyX, startY, cellWidth, cellHeights, 'F')
    doc.setFontSize(9)
    doc.text(
      i === 0 ? 'VAT 5%\nAmount' : 'Total Amount\nInc.VAT',
      keyX + 2,
      startY + 8,
      { align: 'left', valign: 'middle' },
    )

    // Draw cell for Value
    doc.setDrawColor(0)
    doc.setFillColor(249, 249, 249)
    const valueX = keyX + cellWidth
    doc.rect(valueX, startY, cellWidth, cellHeights, 'F')
    doc.text(
      i === 0
        ? `AED ${numeral(vatAmount).format()}`
        : `AED ${numeral(totalAmount).format()}`,
      valueX + 20,
      startY + 8,
      {
        align: 'right',
        valign: 'middle',
      },
    )

    // Draw left, right, middle, and bottom borders
    doc.setDrawColor(0, 0, 0)
    doc.line(keyX, startY + cellHeights, keyX + cellWidth, startY + cellHeights) // Bottom border below Key cell
    doc.line(
      valueX,
      startY + cellHeights,
      valueX + cellWidth,
      startY + cellHeights,
    ) // Bottom border below Value cell
    doc.line(keyX, startY, keyX, startY + cellHeights) // Left border
    doc.line(
      valueX + cellWidth,
      startY,
      valueX + cellWidth,
      startY + cellHeights,
    ) // Right border
    doc.line(
      keyX + cellWidth,
      startY + cellHeights,
      valueX,
      startY + cellHeights - 18,
    ) // Bottom border
  }
  // Draw table borders including bottom and right border
  doc.setDrawColor(0)
  doc.setLineWidth(0.1)
  currentX = tableX
  currentY = tableY
  for (let i = 0; i <= cellWidths.length; i++) {
    doc.line(
      currentX,
      tableY,
      currentX,
      tableY + headerHeight + numRows * cellHeights,
    ) // Vertical border
    currentX += cellWidths[i]
  }
  for (let i = 0; i <= numRows; i++) {
    doc.line(
      tableX,
      currentY,
      tableX + cellWidths.reduce((a, b) => a + b, 0),
      currentY,
    ) // Horizontal border
    currentY += cellHeights
  }

  yPos = currentY + 10
  doc.setFontSize(10)
  doc.setFont('helvetica', 'bold')
  doc.text(
    `Total Amount in Words (AED) :\n${toWords.convert(numeral(totalAmount).format('0.00'))}`,
    18,
    yPos,
  )

  yPos = yPos + 15
  doc.text(`Company Bank Details :`, 18, yPos)

  // Draw bank details
  doc.setFontSize(10)
  doc.setFont('helvetica', 'normal')
  yPos += 8 // Move down slightly for the first line of bank details
  houseitBankDetails.forEach((bank, index) => {
    const startX = 18
    const startY = yPos + index * 25 + 3

    // Draw bank details
    doc.text(`Account Name :  ${bank.accountName}`, startX, startY)
    doc.text(`Bank Name :  ${bank.bankName}`, startX, startY + 7)
    doc.text(`Account Number :  ${bank.accountNumber}`, startX, startY + 14)
    doc.text(`IBAN Number :  ${bank.ibanNumber}`, startX, startY + 21)
    doc.text(`Branch :  ${bank.branch}`, startX, startY + 28)
  })
  yPos = yPos + 43
  doc.setFontSize(11)
  doc.text('for company ', 18, yPos)

  doc.addImage(commonSeal, 'PNG', 60, yPos + 1, 50, 32)

  doc.text('Authorised Signatory', 18, yPos + 30)

  doc.setFontSize(8)
  // Define the y-coordinate for the footer
  const footerY = yPos + 30

  // Set font size and alignment
  doc.setFontSize(10)
  doc.setTextColor(0, 0, 0) // Black color
  doc.setFont('helvetica', 'normal') // Set font and font style

  // Define the text for each line
  const line1 =
    'comapy details'
  const line2 =
    'company adddress'
  const line3 = 'company link.com'

  // Calculate the width of the page
  const pageWidth = doc.internal.pageSize.getWidth()

  // Center and draw each line of text
  centerText(doc, line1, footerY + 17)
  centerText(doc, line2, footerY + 22)
  doc.setFont('helvetica', 'bold')
  centerText(doc, line3, footerY + 32)

  // Function to center text horizontally
  function centerText(doc, text, y) {
    const textWidth = doc.getTextWidth(text) // Get the width of the text
    const x = (pageWidth - textWidth) / 2 // Calculate the x-coordinate to center the text
    doc.text(text, x, y) // Draw the text
  }
  doc.save('.conmpany-tax-invoice')
}

Output

I need this same format for sales invoice but how to use this code, I did this in print format doctype, but it does not work please guide me how to achieve this.

Hi @falah123:

Tried Print Designer?

:face_with_hand_over_mouth: