# PDF Generation Utility for Shelf Scribe
import os
from datetime import datetime
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib import colors
from database import db_query
def generate_purchase_order_pdf(restock_items, supplier_name="Wholesale Supplier"):
"""
Generates a professional purchase order PDF for the restock items.
Returns the absolute path to the generated PDF.
"""
pdf_filename = "restock_order.pdf"
pdf_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), pdf_filename)
if not restock_items:
# Create a dummy pdf or return empty error
doc = SimpleDocTemplate(pdf_path, pagesize=letter)
styles = getSampleStyleSheet()
story: list = [
Paragraph("Shelf Scribe - Restock Order", styles["Heading1"]),
Spacer(1, 20),
Paragraph("No items need restocking today.", styles["Normal"]),
]
doc.build(story)
return pdf_path
try:
doc = SimpleDocTemplate(
pdf_path,
pagesize=letter,
rightMargin=36,
leftMargin=36,
topMargin=36,
bottomMargin=36,
)
story = []
styles = getSampleStyleSheet()
# Custom Title and Brand
title_style = ParagraphStyle(
"POTitle",
parent=styles["Heading1"],
fontName="Helvetica-Bold",
fontSize=22,
leading=26,
textColor=colors.HexColor("#10b981"), # Emerald Green
)
normal_style = styles["Normal"]
story.append(Paragraph("SHELF SCRIBE - RESTOCK PURCHASE ORDER", title_style))
story.append(Spacer(1, 10))
date_str = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
metadata_text = f"""
Date: {date_str}
Supplier Name: {supplier_name}
Status: Draft - Pending Confirmation
"""
story.append(Paragraph(metadata_text, normal_style))
story.append(Spacer(1, 20))
# Table of items: Product Name, Qty, Unit Cost, Pack Size, Total Cost
table_data = [
[
"#",
"Item Description",
"Qty Ordered",
"Pack Size",
"Supplier Unit Cost",
"Estimated Cost",
]
]
total_cost = 0.0
for idx, item in enumerate(restock_items, 1):
prod_id = item["product_id"]
suggested_qty = item.get("suggested_quantity", 0)
# Query details from database
prod = db_query(
"SELECT supplier_price, pack_size FROM products WHERE id = ?",
(prod_id,),
)
if prod:
price = prod[0]["supplier_price"]
pack_size = prod[0]["pack_size"]
else:
price = 0.0
pack_size = 1
cost = suggested_qty * price
total_cost += cost
packs = suggested_qty // pack_size
table_data.append(
[
str(idx),
item["product_name"],
f"{suggested_qty} units ({packs} packs)",
f"size {pack_size}",
f"${price:.2f}",
f"${cost:.2f}",
]
)
# Add total row
table_data.append(["", "", "", "", "Total Est. Cost:", f"${total_cost:.2f}"])
t = Table(table_data, colWidths=[25, 230, 110, 60, 110, 80])
t.setStyle(
TableStyle(
[
("BACKGROUND", (0, 0), (-1, 0), colors.HexColor("#f8fafc")),
("TEXTCOLOR", (0, 0), (-1, 0), colors.HexColor("#0f172a")),
("ALIGN", (0, 0), (-1, -1), "LEFT"),
("BOTTOMPADDING", (0, 0), (-1, 0), 8),
("TOPPADDING", (0, 0), (-1, 0), 8),
("GRID", (0, 0), (-1, -2), 0.5, colors.HexColor("#cbd5e1")),
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
("FONTNAME", (0, -1), (-1, -1), "Helvetica-Bold"),
("BACKGROUND", (0, -1), (-1, -1), colors.HexColor("#f1f5f9")),
("LINEABOVE", (0, -1), (-1, -1), 1.5, colors.HexColor("#10b981")),
("BOTTOMPADDING", (0, -1), (-1, -1), 10),
("TOPPADDING", (0, -1), (-1, -1), 10),
]
)
)
story.append(t)
story.append(Spacer(1, 30))
story.append(
Paragraph(
"Disclaimer: This document is an AI-assisted suggestion. The shop owner must confirm pricing and quantities before final order placement.",
normal_style,
)
)
doc.build(story)
return pdf_path
except Exception as e:
print(f"Error generating Purchase Order PDF: {e}")
return pdf_path
def generate_shelf_labels_pdf(products_list):
"""
Generates a print-ready sheet of shelf labels (A4/Letter size layout grid)
using ReportLab flowables.
"""
pdf_filename = "shelf_labels.pdf"
pdf_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), pdf_filename)
if not products_list:
doc = SimpleDocTemplate(pdf_path, pagesize=letter)
styles = getSampleStyleSheet()
story: list = [Paragraph("No labels to print.", styles["Heading1"])]
doc.build(story)
return pdf_path
try:
# A4 or Letter, small margins to fit maximum cards
doc = SimpleDocTemplate(
pdf_path,
pagesize=letter,
rightMargin=24,
leftMargin=24,
topMargin=24,
bottomMargin=24,
)
story = []
styles = getSampleStyleSheet()
# Grid layout: 2 columns of cards
grid_data = []
row = []
for idx, prod in enumerate(products_list):
category = prod.get("category", "General").upper()
name = prod.get("name", "Product")
price = prod.get("shelf_price", 0.0)
pack_size = prod.get("pack_size", 1)
# Simple card representation as nested ReportLab Table or Paragraph cells
card_content = [
Paragraph(
f"{category} | PACK: {pack_size}",
styles["Normal"],
),
Spacer(1, 4),
Paragraph(
f"{name}",
styles["Normal"],
),
Spacer(1, 10),
Table(
[
[
Paragraph(
f"${price:.2f}",
styles["Normal"],
),
Paragraph(
"|||| | ||| ||||
20000000",
styles["Normal"],
),
]
],
colWidths=[120, 100],
),
]
card_table = Table([[card_content]], colWidths=[240])
card_table.setStyle(
TableStyle(
[
("BOX", (0, 0), (-1, -1), 1.5, colors.HexColor("#475569")),
("TOPPADDING", (0, 0), (-1, -1), 8),
("BOTTOMPADDING", (0, 0), (-1, -1), 8),
("LEFTPADDING", (0, 0), (-1, -1), 10),
("RIGHTPADDING", (0, 0), (-1, -1), 10),
("BACKGROUND", (0, 0), (-1, -1), colors.white),
]
)
)
row.append(card_table)
# 2 columns per row
if len(row) == 2:
grid_data.append(row)
row = []
# Spacer row
grid_data.append([Spacer(1, 10), Spacer(1, 10)])
# Handle trailing odd item
if row:
row.append("") # empty cell
grid_data.append(row)
grid_table = Table(grid_data, colWidths=[260, 260])
grid_table.setStyle(
TableStyle(
[
("ALIGN", (0, 0), (-1, -1), "CENTER"),
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
]
)
)
story.append(
Paragraph("SHELF SCRIBE PRINTABLE LABELS SHEET", styles["Heading2"])
)
story.append(Spacer(1, 15))
story.append(grid_table)
doc.build(story)
return pdf_path
except Exception as e:
print(f"Error generating Shelf Labels PDF: {e}")
return pdf_path