I have been trying to generate an invoice pdf in a gcp function that receives the following input:
end_client_invoices15jjltjkq38p {'oldValue': {}, 'updateMask': {}, 'value': {'createTime': '2023-04-10T13:05:38.934111Z', 'fields': {'buyerDetails': {'mapValue': {'fields': {'buyer_address_city_postal_code_country': {'stringValue': 'Town A AB500 Country'}, 'buyer_address_street': {'stringValue': 'Street 12 '}, 'buyer_email': {'stringValue': '[email protected]'}, 'buyer_id': {'stringValue': 'tqNPjTbvbQQxAUwjp6uVqnrybLh1'}, 'buyer_name': {'stringValue': 'William Surname'}, 'buyer_phone': {'stringValue': '+34 666 111 222'}}}}, 'invoice_number': {'integerValue': '4'}, 'product': {'mapValue': {'fields': {'VAT': {'doubleValue': 0.16}, 'amount': {'doubleValue': 2.0}, 'description': {'stringValue': 'description'}, 'price_per_unit_without_VAT': {'doubleValue': 3.5}, 'quantity': {'doubleValue': 1.0}}}}, 'sellerDetails': {'mapValue': {'fields': {'seller_address_city_postal_code_country': {'stringValue': 'Town AD123 Andorra'}, 'seller_address_street': {'stringValue': '30 Street'}, 'seller_email': {'stringValue': '[email protected]'}, 'seller_name': {'stringValue': 'Name'}, 'seller_phone': {'stringValue': '+376 125 142'}, 'store_uid': {'stringValue': 'Kz7gUu2kokgKdmwTXcSB'}}}}}, 'name': 'projects/project-prod/databases/(default)/documents/invoices_end_client/3CCievchkZHsIVDGQ5oR', 'updateTime': '2023-04-10T13:05:38.934111Z'}}
from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout
from borb.pdf.canvas.layout.page_layout.page_layout import PageLayout
from borb.pdf.canvas.layout.text.paragraph import Paragraph
from borb.pdf.document.document import Document
from borb.pdf.page.page import Page
from borb.pdf.pdf import PDF
from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout
from decimal import Decimal
from borb.pdf.canvas.layout.table.fixed_column_width_table import (
FixedColumnWidthTable as Table,
)
from borb.pdf.canvas.layout.layout_element import Alignment
from borb.pdf.canvas.layout.image.image import Image
from borb.pdf.page.page_size import PageSize
from datetime import datetime
import random
from borb.pdf.pdf import PDF
from borb.pdf.canvas.color.color import HexColor, X11Color
from borb.pdf.canvas.layout.table.fixed_column_width_table import (
FixedColumnWidthTable as Table,
)
from borb.pdf.canvas.layout.table.table import TableCell
from borb.pdf import Page
import json
from google.cloud import storage
from datetime import datetime
import firebase_admin
from firebase_admin import credentials
from firebase_admin import firestore
from pprint import pformat
import logging
import re
import pandas as pd
# Global Variables
export_time = datetime.now().strftime("%d_%m_%Y")
invoice_date_month = datetime.now().strftime("%m_%Y")
logging.basicConfig(format='%(message)s')
# Function
def generate_pdf_invoice(data, context):
""" Triggered by a change to a Firestore document.
Args:
data (dict): The event payload.
context (google.cloud.functions.Context): Metadata for the event.
"""
logging.warning(list(data["value"]["fields"]["product"]["mapValue"]["fields"]["amount"].values())[0])
logging.warning(data)
# Build Table
table_001 = Table(number_of_rows=4, number_of_columns=4)
table_001.add(
Paragraph(
"Raó Social", font="Helvetica-Bold", horizontal_alignment=Alignment.LEFT
)
)
table_001.add(
Paragraph(
"Company, SL", font="Helvetica-Bold"
)
)
table_001.add(
Paragraph("Data", font="Helvetica-Bold", horizontal_alignment=Alignment.RIGHT)
)
now = datetime.now()
table_001.add(Paragraph("%d/%d/%d" % (now.day, now.month, now.year)))
table_001.add(
Paragraph("Carrer", font="Helvetica-Bold", horizontal_alignment=Alignment.LEFT)
)
table_001.add(
Paragraph("Street A,Bloc X")
)
table_001.add(
Paragraph(
"Factura #", font="Helvetica-Bold", horizontal_alignment=Alignment.RIGHT,
)
)
table_001.add(
Paragraph(str(data["value"]["fields"]["invoice_number"]["integerValue"]))
)
table_001.add(
Paragraph(
"Població", font="Helvetica-Bold", horizontal_alignment=Alignment.LEFT
)
)
table_001.add(
Paragraph("Town")
)
table_001.add(
Paragraph(
"Venciment", font="Helvetica-Bold", horizontal_alignment=Alignment.LEFT
)
)
table_001.add(Paragraph("%d/%d/%d" % (now.day, now.month, now.year)))
table_001.add(
Paragraph("Email", font="Helvetica-Bold", horizontal_alignment=Alignment.RIGHT)
)
table_001.add(
Paragraph(
"[email protected]"
)
)
table_001.set_padding_on_all_cells(Decimal(2), Decimal(2), Decimal(2), Decimal(2))
table_001.no_borders()
#Billing and shipping information
table_002 = Table(number_of_columns=1, number_of_rows=6)
table_002.add(
Paragraph(
"Facturat a",
background_color=HexColor("263238"),
font_color=X11Color("White"),
)
)
# BILLING
table_002.add(
Paragraph(remove_emoji(data["value"]["fields"]["buyerDetails"]["mapValue"]["fields"]["buyer_name"]["stringValue"]))
) # BILLING
table_002.add(
Paragraph(data["value"]["fields"]["buyerDetails"]["mapValue"]["fields"]["buyer_address_street"]["stringValue"])
) # BILLING
table_002.add(
Paragraph(
data["value"]["fields"]["buyerDetails"]["mapValue"]["fields"]["buyer_address_city_postal_code_country"]["stringValue"]
)
) # BILLING
table_002.add(
Paragraph(data["value"]["fields"]["buyerDetails"]["mapValue"]["fields"]["buyer_phone"]["stringValue"])
) # BILLING
table_002.add(
Paragraph(data["value"]["fields"]["buyerDetails"]["mapValue"]["fields"]["buyer_email"]["stringValue"])
) # BILLING
table_002.set_padding_on_all_cells(Decimal(2), Decimal(2), Decimal(2), Decimal(2))
table_002.no_borders()
# Build_itemized_description_table
table_003 = Table(number_of_rows=7, number_of_columns=4)
for h in ["Descripció", "Quantitat", "Preu per unitat", "Import"]:
table_003.add(
TableCell(
Paragraph(h, font_color=X11Color("White")),
background_color=HexColor("000000"),
)
)
odd_color = HexColor("BBBBBB")
even_color = HexColor("FFFFFF")
for row_number, item in enumerate(
[
(
data["value"]["fields"]["product"]["mapValue"]["fields"]["description"]["stringValue"],
data["value"]["fields"]["product"]["mapValue"]["fields"]["quantity"]["doubleValue"],
list(data["value"]["fields"]["product"]["mapValue"]["fields"]["price_per_unit_without_VAT"].values())[0],
list(data["value"]["fields"]["product"]["mapValue"]["fields"]["price_per_unit_without_VAT"].values())[0]*data["value"]["fields"]["product"]["mapValue"]["fields"]["quantity"]["doubleValue"]
),
]
):
c = even_color if row_number % 2 == 0 else odd_color
table_003.add(TableCell(Paragraph(item[0]), background_color=c))
table_003.add(TableCell(Paragraph(str(item[1])), background_color=c))
table_003.add(TableCell(Paragraph("$ " + str(item[2])), background_color=c))
table_003.add(TableCell(Paragraph("$ " + str(item[3])), background_color=c))
# Optionally add some empty rows to have a fixed number of rows for styling purposes
for row_number in range(3, 5):
c = even_color if row_number % 2 == 0 else odd_color
for _ in range(0, 4):
table_003.add(TableCell(Paragraph(" "), background_color=c))
table_003.add(
TableCell(
Paragraph(
"Subtotal", font="Helvetica-Bold", horizontal_alignment=Alignment.RIGHT,
),
col_span=3,
)
)
table_003.add(
TableCell(
Paragraph(
float(data["value"]["fields"]["product"]["mapValue"]["fields"]["price_per_unit_without_VAT"]["doubleValue"])*float(data["value"]["fields"]["product"]["mapValue"]["fields"]["quantity"]["doubleValue"])
)
)
)
table_003.add(
TableCell(
Paragraph(
"IGI", font="Helvetica-Bold", horizontal_alignment=Alignment.RIGHT
),
col_span=3,
)
)
table_003.add(
TableCell(
Paragraph(
"{0:.2f}".format(
float(data["value"]["fields"]["product"]["mapValue"]["fields"]["price_per_unit_without_VAT"]["doubleValue"]) * float(data["value"]["fields"]["product"]["mapValue"]["fields"]["quantity"]["doubleValue"]) * 4.5 / 100
)
)
)
)
table_003.add(
TableCell(
Paragraph(
"Total", font="Helvetica-Bold", horizontal_alignment=Alignment.RIGHT
),
col_span=3,
)
)
table_003.add(
TableCell(
Paragraph(
"{0:.2f}".format(
float(data["value"]["fields"]["product"]["mapValue"]["fields"]["price_per_unit_without_VAT"]["doubleValue"])*float(data["value"]["fields"]["product"]["mapValue"]["fields"]["quantity"]["doubleValue"]) * (1 + 4.5 / 100)
)
)
)
)
table_003.set_padding_on_all_cells(Decimal(2), Decimal(2), Decimal(2), Decimal(2))
table_003.no_borders()
# Create document
pdf = Document()
# Add page
page = Page()
pdf.add_page(page)
page_layout = SingleColumnLayout(page)
page_layout.vertical_margin = page.get_page_info().get_height() * Decimal(0.02)
page_layout.add(
Image(
"https://firebasestorage.googleapis.com/v0/b/mes-k-bo-dev.appspot.com/o/stores%2F2322e310-1743-11ed-87c2-9f7ebec4c7dc?alt=media&token=71ebb1be-a9ae-4f49-b3e1-b46619cdfb4a",
width=Decimal(128),
height=Decimal(128),
)
)
# Invoice information table
page_layout.add(table_001)
# Empty paragraph for spacing
page_layout.add(Paragraph(" "))
# Billing and shipping information table
page_layout.add(table_002)
# Empty paragraph for spacing
page_layout.add(Paragraph(" "))
# Itemized description
page_layout.add(table_003)
And I am getting this error which I can't figure out how to solve:
File "/workspace/main.py", line 260, in generate_pdf_invoice
page_layout.add(table_003)
File "/layers/google.python.pip/pip/lib/python3.9/site-packages/borb/pdf/canvas/layout/page_layout/multi_column_layout.py", line 201, in add
layout_rect = layout_element.layout(
File "/layers/google.python.pip/pip/lib/python3.9/site-packages/borb/pdf/canvas/layout/layout_element.py", line 307, in layout
return self.calculate_layout_box_and_do_layout(page, bounding_box)
File "/layers/google.python.pip/pip/lib/python3.9/site-packages/borb/pdf/canvas/layout/layout_element.py", line 320, in calculate_layout_box_and_do_layout
layout_box = self._calculate_layout_box(page, bounding_box)
File "/layers/google.python.pip/pip/lib/python3.9/site-packages/borb/pdf/canvas/layout/layout_element.py", line 230, in _calculate_layout_box
returned_layout_box = self._calculate_layout_box_without_padding(
File "/layers/google.python.pip/pip/lib/python3.9/site-packages/borb/pdf/canvas/layout/layout_element.py", line 258, in _calculate_layout_box_without_padding
layout_rect = self._do_layout_without_padding(page, bounding_box)
File "/layers/google.python.pip/pip/lib/python3.9/site-packages/borb/pdf/canvas/layout/table/fixed_column_width_table.py", line 131, in _do_layout_without_padding
t.layout(page, Rectangle(x, y, w, h))
File "/layers/google.python.pip/pip/lib/python3.9/site-packages/borb/pdf/canvas/layout/table/table.py", line 151, in layout
returned_layout_box: Rectangle = self._layout_element.layout(
File "/layers/google.python.pip/pip/lib/python3.9/site-packages/borb/pdf/canvas/layout/layout_element.py", line 307, in layout
return self.calculate_layout_box_and_do_layout(page, bounding_box)
File "/layers/google.python.pip/pip/lib/python3.9/site-packages/borb/pdf/canvas/layout/layout_element.py", line 320, in calculate_layout_box_and_do_layout
layout_box = self._calculate_layout_box(page, bounding_box)
File "/layers/google.python.pip/pip/lib/python3.9/site-packages/borb/pdf/canvas/layout/layout_element.py", line 230, in _calculate_layout_box
returned_layout_box = self._calculate_layout_box_without_padding(
File "/layers/google.python.pip/pip/lib/python3.9/site-packages/borb/pdf/canvas/layout/layout_element.py", line 258, in _calculate_layout_box_without_padding
layout_rect = self._do_layout_without_padding(page, bounding_box)
File "/layers/google.python.pip/pip/lib/python3.9/site-packages/borb/pdf/canvas/layout/text/paragraph.py", line 230, in _do_layout_without_padding
if len(self._text) == 0:
TypeError: object of type 'float' has no len()
Could anyone help me? Thousand thanks!
Several variations of the code but could not get it to work, mainly trying more configuration of the paragraph without success
disclaimer: I am the author of
borbOne of your
Paragraphobjects is being constructed with afloatrather than astr. At some point, theParagraphattempts to perform layout, for which it needs to determine its width.And thus it calls
lenon what it expects to bestr, but is in factfloat.This is where it goes wrong:
You are explicitly constructing
Paragraphwith afloatthere.