import json import datetime from reportlab.lib.pagesizes import letter from reportlab.lib import colors from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, PageBreak, Image from reportlab.platypus import Frame, PageTemplate, NextPageTemplate from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.lib.enums import TA_CENTER, TA_JUSTIFY, TA_LEFT, TA_RIGHT from reportlab.lib.units import inch, cm from reportlab.pdfgen import canvas def header_footer(canvas, doc): """Add the header and footer to each page""" canvas.saveState() # Header header_text = "Standard Operating Procedures" canvas.setFont('Helvetica-Bold', 10) canvas.drawString(72, letter[1] - 40, header_text) # Add a line below the header canvas.setStrokeColor(colors.lightgrey) canvas.line(72, letter[1] - 50, letter[0] - 72, letter[1] - 50) # Footer with page number and date current_date = datetime.datetime.now().strftime("%B %d, %Y") page_num = f"Page {doc.page} | {current_date}" canvas.setFont('Helvetica', 8) canvas.drawString(letter[0] - 150, 40, page_num) # Add a line above the footer canvas.line(72, 50, letter[0] - 72, 50) canvas.restoreState() def convert_sop_to_pdf(sop_data, output_pdf="sop_document.pdf", company_name="Company Name"): """ Convert SOP data to a well-formatted PDF document Args: sop_data (dict or str): SOP data in dictionary format or JSON string output_pdf (str): Output PDF filename company_name (str): Name of the company to display on the cover page """ # Parse JSON string if needed if isinstance(sop_data, str): sop_data = json.loads(sop_data) # Extract SOP details sop_details = sop_data.get("sop_details", []) # Create PDF document doc = SimpleDocTemplate(output_pdf, pagesize=letter, rightMargin=72, leftMargin=72, topMargin=90, bottomMargin=72) # Container for PDF elements elements = [] # Get styles styles = getSampleStyleSheet() # Define custom styles title_style = ParagraphStyle( 'TitleStyle', parent=styles['Heading1'], fontSize=24, alignment=TA_CENTER, spaceAfter=12, fontName='Helvetica-Bold', textColor=colors.darkblue ) subtitle_style = ParagraphStyle( 'SubtitleStyle', parent=styles['Heading2'], fontSize=16, alignment=TA_CENTER, spaceAfter=36, fontName='Helvetica-Bold', textColor=colors.darkblue ) heading2_style = ParagraphStyle( 'Heading2Style', parent=styles['Heading2'], fontSize=16, spaceBefore=12, spaceAfter=6, fontName='Helvetica-Bold', textColor=colors.darkblue, borderWidth=0, borderColor=colors.lightgrey, borderPadding=5, borderRadius=5 ) heading3_style = ParagraphStyle( 'Heading3Style', parent=styles['Heading3'], fontSize=12, spaceBefore=6, spaceAfter=3, fontName='Helvetica-Bold', textColor=colors.darkslategray ) normal_style = ParagraphStyle( 'NormalStyle', parent=styles['Normal'], fontSize=10, alignment=TA_JUSTIFY, leading=14, fontName='Helvetica' ) bullet_style = ParagraphStyle( 'BulletStyle', parent=normal_style, leftIndent=20, firstLineIndent=-15, spaceBefore=2, spaceAfter=2 ) # Create cover page elements.append(Spacer(1, 2*inch)) elements.append(Paragraph("Standard Operating Procedures", title_style)) elements.append(Spacer(1, 0.5*inch)) #elements.append(Paragraph(company_name, subtitle_style)) elements.append(Spacer(1, 2*inch)) # Add current date current_date = datetime.datetime.now().strftime("%B %d, %Y") date_style = ParagraphStyle( 'DateStyle', parent=styles['Normal'], fontSize=12, alignment=TA_CENTER, fontName='Helvetica' ) elements.append(Paragraph(f"Generated on: {current_date}", date_style)) # Add a page break after the cover page elements.append(PageBreak()) # Process each role for role_data in sop_details: role_name = role_data.get("role", "Unnamed Role") sops = role_data.get("sops", {}) narrative = role_data.get("narrative") # Add role header with decorative element elements.append(Paragraph(role_name, heading2_style)) # Add horizontal rule after heading elements.append(Spacer(1, 0.05*inch)) # Add narrative if available if narrative and narrative != "Narrative" and narrative is not None: elements.append(Paragraph("Narrative:", heading3_style)) elements.append(Paragraph(narrative, normal_style)) elements.append(Spacer(1, 0.2*inch)) # Process SOPs for sop_type in ["must", "shall", "will"]: sop_items = sops.get(sop_type, []) if sop_items: # Capitalize the first letter of SOP type and make it bold sop_type_title = sop_type.capitalize() elements.append(Paragraph(f"{sop_type_title}:", heading3_style)) # Create bullet points for each SOP item with better formatting for item in sop_items: elements.append(Paragraph(f"• {item}", bullet_style)) elements.append(Spacer(1, 0.15*inch)) # Add a page break between roles for cleaner separation elements.append(PageBreak()) # Build the PDF document with header and footer doc.build(elements, onFirstPage=header_footer, onLaterPages=header_footer) return output_pdf def main(): # Example usage sop_json = """ { "sop_details": [ { "role": "Sales Manager", "role_id": 140, "sops": { "must": [], "shall": [ "Shall develop and implement sales strategies to achieve company targets.", "Shall conduct regular performance reviews with the sales team to ensure targets are met.", "Shall provide training and support to sales staff to enhance their skills and performance.", "Shall analyze market trends and adjust sales strategies accordingly.", "Shall maintain accurate records of sales activities and customer interactions." ], "will": [ "Will lead the sales team to achieve monthly and quarterly sales goals.", "Will collaborate with marketing to align sales strategies with promotional campaigns.", "Will report sales performance to upper management on a regular basis.", "Will identify potential new markets and customer segments for growth.", "Will foster a positive team environment to motivate sales staff." ] }, "areas": [], "narrative": "The Sales Manager is responsible for leading and developing the sales team to achieve business targets and growth objectives. They will implement effective sales strategies, provide coaching to team members, and maintain strong customer relationships while ensuring all sales activities align with the company's overall goals." }, { "role": "Campaign Manager", "role_id": 141, "sops": { "must": [], "shall": [], "will": [ "Will develop and execute marketing campaigns to promote products and services.", "Will analyze campaign performance metrics to optimize future campaigns.", "Will collaborate with cross-functional teams to ensure campaign alignment with business objectives.", "Will manage campaign budgets and ensure effective allocation of resources.", "Will stay updated on industry trends to inform campaign strategies." ] }, "areas": [], "narrative": "The Campaign Manager oversees the planning, execution, and analysis of marketing campaigns across various channels to drive brand awareness and customer acquisition. They work closely with creative teams, external vendors, and stakeholders to ensure campaigns are effective, on-brand, and deliver measurable results." } ] } """ # You can replace the company name with your own output_file = convert_sop_to_pdf(sop_json, company_name="Strategic Business Solutions, Inc.") print(f"PDF successfully generated: {output_file}") if __name__ == "__main__": main()