History taking for STOMA in surgery
| Complication | Ask |
|---|---|
| Ischaemia/Necrosis | Was the stoma ever purple/black after surgery? |
| High output | Was there excess fluid loss requiring IV fluids? |
| Bleeding | Any blood from or around the stoma? |
| Dehydration | Admissions for rehydration or electrolyte imbalance? |
| Complication | Ask |
|---|---|
| Skin irritation / Parastomal dermatitis | Soreness, redness, rash around the stoma? |
| Parastomal hernia | Bulge around the stoma, especially on standing/coughing? Any discomfort? Any obstruction symptoms? |
| Prolapse | Has the stoma ever protruded outward / fallen out? |
| Retraction | Has the stoma sunk inwards? Trouble keeping the bag on? |
| Stenosis / Stricture | Narrow output, pellet-shaped stool, difficulty with bag application? |
| Bleeding | From trauma (appliance) vs luminal GI source |
| Fistulation | Any discharge from skin around the stoma? |
| Parastomal pyoderma gangrenosum | Painful ulceration around stoma? History of IBD? |
From Bailey & Love: Stoma complications include skin irritation, stenosis, prolapse, parastomal hernia, retraction, bleeding, ischaemia, and fistulation.
From Fischer's Mastery of Surgery: Parastomal hernia can be diagnosed by history and physical exam; patients complain of a bulge around the stoma and secondary fitting problems with appliances.
| Letter | Domain |
|---|---|
| S - Site & Type | Ileostomy / Colostomy / Urostomy; End / Loop; Temporary / Permanent |
| T - Time & Indication | When formed; Underlying disease (cancer, IBD, diverticular) |
| O - Output | Volume, consistency, colour, frequency |
| M - Management of appliance | Type of bag, leakage, skin care, stoma nurse involvement |
| A - Adverse effects / Complications | Hernia, prolapse, retraction, stenosis, skin problems |
| I - Impact | QoL, diet, sexual function, psychological, reversal plans |
Create a printable patient history form for stoma assessment
ls -la /tmp/workspace/ 2>/dev/null || mkdir -p /tmp/workspace && echo "workspace ready"
mkdir -p /tmp/workspace/stoma-form && python3 << 'PYEOF' from reportlab.lib.pagesizes import A4 from reportlab.lib import colors from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.lib.units import mm, cm from reportlab.platypus import (SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, HRFlowable, KeepTogether) from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_RIGHT from reportlab.pdfgen import canvas from reportlab.platypus.flowables import Flowable OUTPUT = "/tmp/workspace/stoma-form/Stoma_Patient_History_Form.pdf" # ── colours ────────────────────────────────────────────────────────────────── DARK_TEAL = colors.HexColor("#1B5E6E") MID_TEAL = colors.HexColor("#2A7F93") LIGHT_TEAL = colors.HexColor("#D4EEF4") PALE_TEAL = colors.HexColor("#EEF7FA") LIGHT_GREY = colors.HexColor("#F5F5F5") MID_GREY = colors.HexColor("#CCCCCC") DARK_GREY = colors.HexColor("#444444") WHITE = colors.white BOX_LINE = colors.HexColor("#AAAAAA") W, H = A4 # 595.27 x 841.89 pt # ── document ────────────────────────────────────────────────────────────────── doc = SimpleDocTemplate( OUTPUT, pagesize=A4, topMargin=18*mm, bottomMargin=14*mm, leftMargin=16*mm, rightMargin=16*mm ) styles = getSampleStyleSheet() def style(name, parent="Normal", **kw): s = ParagraphStyle(name, parent=styles[parent], **kw) return s S = { "title": style("title", fontSize=18, textColor=WHITE, leading=22, fontName="Helvetica-Bold", alignment=TA_CENTER), "subtitle": style("sub", fontSize=10, textColor=WHITE, leading=14, fontName="Helvetica", alignment=TA_CENTER), "sechead": style("sec", fontSize=9.5, textColor=WHITE, leading=13, fontName="Helvetica-Bold", alignment=TA_LEFT), "label": style("lbl", fontSize=8.5, textColor=DARK_GREY, leading=12, fontName="Helvetica-Bold"), "body": style("bod", fontSize=8, textColor=DARK_GREY, leading=11, fontName="Helvetica"), "small": style("sml", fontSize=7.5, textColor=DARK_GREY, leading=10, fontName="Helvetica"), "note": style("nte", fontSize=7, textColor=colors.HexColor("#777777"), leading=10, fontName="Helvetica-Oblique"), "footer": style("ftr", fontSize=7, textColor=colors.HexColor("#999999"), leading=9, fontName="Helvetica", alignment=TA_CENTER), } usable_w = W - 32*mm # 163mm # ── helpers ─────────────────────────────────────────────────────────────────── def spacer(h=3): return Spacer(1, h*mm) def line_field(label, w=None, lines=1): """A labelled underline field.""" fw = w or usable_w rows = [] rows.append(Paragraph(label, S["label"])) for _ in range(lines): rows.append(HRFlowable(width=fw, thickness=0.5, color=BOX_LINE, spaceAfter=2, spaceBefore=1)) return rows def section_header(text): """Coloured section banner.""" data = [[Paragraph(text, S["sechead"])]] t = Table(data, colWidths=[usable_w]) t.setStyle(TableStyle([ ("BACKGROUND", (0,0), (-1,-1), DARK_TEAL), ("TOPPADDING", (0,0), (-1,-1), 4), ("BOTTOMPADDING", (0,0), (-1,-1), 4), ("LEFTPADDING", (0,0), (-1,-1), 6), ("RIGHTPADDING", (0,0), (-1,-1), 6), ("ROWBACKGROUNDS", (0,0), (-1,-1), [DARK_TEAL]), ])) return t def checkbox_row(items, cols=None): """Row of labelled checkboxes.""" cols = cols or len(items) col_w = usable_w / cols row_data = [] for item in items: row_data.append(Paragraph(f"☐ {item}", S["body"])) # Pad to fill cols while len(row_data) < cols: row_data.append(Paragraph("", S["body"])) t = Table([row_data], colWidths=[col_w]*cols) t.setStyle(TableStyle([ ("TOPPADDING", (0,0), (-1,-1), 2), ("BOTTOMPADDING", (0,0), (-1,-1), 2), ("LEFTPADDING", (0,0), (-1,-1), 3), ("RIGHTPADDING", (0,0), (-1,-1), 3), ])) return t def info_grid(pairs, cols=2): """Grid of label: ________ fields.""" col_w = usable_w / cols rows = [] row = [] for i, (lbl, w_pct) in enumerate(pairs): inner_w = col_w * (w_pct or 1.0) cell = [Paragraph(lbl, S["label"]), HRFlowable(width=inner_w - 10, thickness=0.5, color=BOX_LINE, spaceBefore=1, spaceAfter=2)] row.append(cell) if len(row) == cols or i == len(pairs)-1: while len(row) < cols: row.append(Paragraph("", S["body"])) rows.append(row) row = [] t = Table(rows, colWidths=[col_w]*cols) t.setStyle(TableStyle([ ("TOPPADDING", (0,0), (-1,-1), 2), ("BOTTOMPADDING", (0,0), (-1,-1), 2), ("LEFTPADDING", (0,0), (-1,-1), 4), ("RIGHTPADDING", (0,0), (-1,-1), 4), ("VALIGN", (0,0), (-1,-1), "TOP"), ])) return t def shaded_box(content_rows, bg=PALE_TEAL, pad=4): """Wrap a list of flowables in a shaded box via a 1-cell Table.""" inner = [[r] for r in content_rows] # Flatten into single cell using nested Table trick t = Table([[content_rows]], colWidths=[usable_w]) t.setStyle(TableStyle([ ("BACKGROUND", (0,0), (-1,-1), bg), ("BOX", (0,0), (-1,-1), 0.5, BOX_LINE), ("TOPPADDING", (0,0), (-1,-1), pad), ("BOTTOMPADDING", (0,0), (-1,-1), pad), ("LEFTPADDING", (0,0), (-1,-1), pad+2), ("RIGHTPADDING", (0,0), (-1,-1), pad+2), ("VALIGN", (0,0), (-1,-1), "TOP"), ])) return t def notes_box(label="Notes / Additional comments:", lines=3, w=None): fw = w or usable_w items = [Paragraph(label, S["label"])] for _ in range(lines): items.append(HRFlowable(width=fw-8, thickness=0.5, color=BOX_LINE, spaceAfter=3, spaceBefore=1)) return shaded_box(items, bg=LIGHT_GREY) def complication_table(rows_data): """3-col table: Complication | Present | Details.""" header = [ Paragraph("Complication", S["label"]), Paragraph("Present?", S["label"]), Paragraph("Details / Duration", S["label"]), ] data = [header] for comp in rows_data: data.append([ Paragraph(comp, S["body"]), Paragraph("☐ Yes ☐ No ☐ ?", S["small"]), HRFlowable(width=60*mm, thickness=0.5, color=BOX_LINE), ]) cw = [70*mm, 28*mm, 65*mm] t = Table(data, colWidths=cw, repeatRows=1) t.setStyle(TableStyle([ ("BACKGROUND", (0,0), (2,0), MID_TEAL), ("TEXTCOLOR", (0,0), (2,0), WHITE), ("ROWBACKGROUNDS",(0,1), (-1,-1), [WHITE, LIGHT_TEAL]), ("BOX", (0,0), (-1,-1), 0.5, BOX_LINE), ("INNERGRID", (0,0), (-1,-1), 0.3, MID_GREY), ("TOPPADDING", (0,0), (-1,-1), 4), ("BOTTOMPADDING", (0,0), (-1,-1), 4), ("LEFTPADDING", (0,0), (-1,-1), 5), ("RIGHTPADDING", (0,0), (-1,-1), 5), ("VALIGN", (0,0), (-1,-1), "MIDDLE"), ])) return t # ═══════════════════════════════════════════════════════════════════════════════ # BUILD STORY # ═══════════════════════════════════════════════════════════════════════════════ story = [] # ── HEADER BANNER ───────────────────────────────────────────────────────────── header_data = [[ Paragraph("STOMA PATIENT HISTORY ASSESSMENT FORM", S["title"]), Paragraph("Surgical / Colorectal / Stoma Therapy Unit", S["subtitle"]), ]] header_t = Table( [[Paragraph("STOMA PATIENT HISTORY ASSESSMENT FORM", S["title"])], [Paragraph("Surgical · Colorectal · Stoma Therapy Unit", S["subtitle"])]], colWidths=[usable_w] ) header_t.setStyle(TableStyle([ ("BACKGROUND", (0,0), (-1,-1), DARK_TEAL), ("TOPPADDING", (0,0), (-1,-1), 8), ("BOTTOMPADDING", (0,0), (-1,-1), 8), ("LEFTPADDING", (0,0), (-1,-1), 10), ("RIGHTPADDING", (0,0), (-1,-1), 10), ])) story.append(header_t) story.append(spacer(3)) # ── PATIENT DEMOGRAPHICS ────────────────────────────────────────────────────── story.append(section_header("SECTION 1 — PATIENT DEMOGRAPHICS")) story.append(spacer(2)) demo_data = [ [ [Paragraph("Patient Name:", S["label"]), HRFlowable(width=75*mm, thickness=0.5, color=BOX_LINE, spaceAfter=1, spaceBefore=1)], [Paragraph("Date of Birth:", S["label"]), HRFlowable(width=36*mm, thickness=0.5, color=BOX_LINE, spaceAfter=1, spaceBefore=1)], [Paragraph("MRN / Hospital No.:", S["label"]), HRFlowable(width=36*mm, thickness=0.5, color=BOX_LINE, spaceAfter=1, spaceBefore=1)], ], [ [Paragraph("Clinician / Nurse:", S["label"]), HRFlowable(width=75*mm, thickness=0.5, color=BOX_LINE, spaceAfter=1, spaceBefore=1)], [Paragraph("Date of Assessment:", S["label"]), HRFlowable(width=36*mm, thickness=0.5, color=BOX_LINE, spaceAfter=1, spaceBefore=1)], [Paragraph("Ward / Clinic:", S["label"]), HRFlowable(width=36*mm, thickness=0.5, color=BOX_LINE, spaceAfter=1, spaceBefore=1)], ], ] demo_t = Table(demo_data, colWidths=[90*mm, 50*mm, 53*mm]) demo_t.setStyle(TableStyle([ ("BACKGROUND", (0,0), (-1,-1), PALE_TEAL), ("BOX", (0,0), (-1,-1), 0.5, BOX_LINE), ("INNERGRID", (0,0), (-1,-1), 0.3, MID_GREY), ("TOPPADDING", (0,0), (-1,-1), 4), ("BOTTOMPADDING", (0,0), (-1,-1), 5), ("LEFTPADDING", (0,0), (-1,-1), 6), ("RIGHTPADDING", (0,0), (-1,-1), 4), ("VALIGN", (0,0), (-1,-1), "TOP"), ])) story.append(demo_t) story.append(spacer(3)) # ── SECTION 2 — STOMA DETAILS ───────────────────────────────────────────────── story.append(section_header("SECTION 2 — STOMA DETAILS")) story.append(spacer(2)) # Type of stoma story.append(Paragraph("2.1 Type of Stoma:", S["label"])) story.append(spacer(1)) story.append(checkbox_row(["Ileostomy", "Colostomy (sigmoid)", "Colostomy (transverse)", "Urostomy / Ileal conduit", "Other:___________"], cols=3)) story.append(spacer(2)) story.append(Paragraph("2.2 Configuration:", S["label"])) story.append(spacer(1)) story.append(checkbox_row(["End (terminal)", "Loop", "Double-barrel", "End-loop", "Continent (reservoir)"], cols=3)) story.append(spacer(2)) story.append(Paragraph("2.3 Permanence:", S["label"])) story.append(spacer(1)) story.append(checkbox_row(["Temporary (diverting)", "Permanent", "Unknown at time of formation"], cols=3)) story.append(spacer(2)) # Dates and operation op_data = [ [ [Paragraph("Date stoma formed:", S["label"]), HRFlowable(width=38*mm, thickness=0.5, color=BOX_LINE, spaceAfter=1, spaceBefore=1)], [Paragraph("Duration (approx.):", S["label"]), HRFlowable(width=38*mm, thickness=0.5, color=BOX_LINE, spaceAfter=1, spaceBefore=1)], [Paragraph("Planned reversal date:", S["label"]), HRFlowable(width=38*mm, thickness=0.5, color=BOX_LINE, spaceAfter=1, spaceBefore=1)], ], [ [Paragraph("Operation performed:", S["label"]), HRFlowable(width=108*mm, thickness=0.5, color=BOX_LINE, spaceAfter=1, spaceBefore=1)], Paragraph("", S["body"]), [Paragraph("Surgeon:", S["label"]), HRFlowable(width=38*mm, thickness=0.5, color=BOX_LINE, spaceAfter=1, spaceBefore=1)], ], ] op_t = Table(op_data, colWidths=[58*mm, 53*mm, 52*mm]) op_t.setStyle(TableStyle([ ("BACKGROUND", (0,0), (-1,-1), LIGHT_GREY), ("BOX", (0,0), (-1,-1), 0.5, BOX_LINE), ("INNERGRID", (0,0), (-1,-1), 0.3, MID_GREY), ("TOPPADDING", (0,0), (-1,-1), 4), ("BOTTOMPADDING", (0,0), (-1,-1), 5), ("LEFTPADDING", (0,0), (-1,-1), 6), ("RIGHTPADDING", (0,0), (-1,-1), 4), ("VALIGN", (0,0), (-1,-1), "TOP"), ("SPAN", (0,1), (1,1)), ])) story.append(op_t) story.append(spacer(2)) story.append(Paragraph("2.4 Indication / Underlying Diagnosis:", S["label"])) story.append(spacer(1)) story.append(checkbox_row(["Colorectal cancer", "Rectal cancer (APR)", "Crohn's disease", "Ulcerative colitis"], cols=4)) story.append(checkbox_row(["Diverticular disease (Hartmann's)", "FAP / Polyposis", "Trauma / Emergency", "Bladder cancer (urostomy)"], cols=4)) story.append(checkbox_row(["Ischaemic colitis", "Volvulus / Obstruction", "Faecal incontinence", "Other:___________"], cols=4)) story.append(spacer(3)) # ── SECTION 3 — STOMA OUTPUT ────────────────────────────────────────────────── story.append(section_header("SECTION 3 — STOMA OUTPUT & FUNCTION")) story.append(spacer(2)) output_data = [ [ [Paragraph("Bag change frequency (per day):", S["label"]), HRFlowable(width=52*mm, thickness=0.5, color=BOX_LINE, spaceAfter=1, spaceBefore=1)], [Paragraph("Estimated output volume (mL/day):", S["label"]), HRFlowable(width=52*mm, thickness=0.5, color=BOX_LINE, spaceAfter=1, spaceBefore=1)], ], ] out_t = Table(output_data, colWidths=[83*mm, 80*mm]) out_t.setStyle(TableStyle([ ("BACKGROUND", (0,0), (-1,-1), PALE_TEAL), ("BOX", (0,0), (-1,-1), 0.5, BOX_LINE), ("INNERGRID", (0,0), (-1,-1), 0.3, MID_GREY), ("TOPPADDING", (0,0), (-1,-1), 4), ("BOTTOMPADDING", (0,0), (-1,-1), 5), ("LEFTPADDING", (0,0), (-1,-1), 6), ("RIGHTPADDING", (0,0), (-1,-1), 4), ("VALIGN", (0,0), (-1,-1), "TOP"), ])) story.append(out_t) story.append(spacer(2)) story.append(Paragraph("3.1 Output Consistency:", S["label"])) story.append(spacer(1)) story.append(checkbox_row(["Formed/solid", "Semi-formed / Soft", "Loose / Mushy", "Watery / Liquid", "Mucus only", "No output (nil)"], cols=3)) story.append(spacer(2)) story.append(Paragraph("3.2 Output Colour:", S["label"])) story.append(spacer(1)) story.append(checkbox_row(["Normal brown", "Yellow / Green (bile)", "Dark / Black", "Blood-stained (bright red)", "Offensive odour"], cols=3)) story.append(spacer(2)) story.append(Paragraph("3.3 High Output Ileostomy (>1500 mL/day)?", S["label"])) story.append(spacer(1)) story.append(checkbox_row(["Yes — currently", "Yes — previously (resolved)", "No", "On antimotility agents (loperamide/codeine)"], cols=4)) story.append(spacer(2)) story.append(Paragraph("3.4 Flatus / Wind:", S["label"])) story.append(spacer(1)) story.append(checkbox_row(["Minimal", "Moderate (bag balloons occasionally)", "Excessive / Problematic", "Filter in use"], cols=4)) story.append(spacer(3)) # ── SECTION 4 — APPLIANCE ───────────────────────────────────────────────────── story.append(section_header("SECTION 4 — APPLIANCE & SKIN MANAGEMENT")) story.append(spacer(2)) story.append(Paragraph("4.1 Appliance Type:", S["label"])) story.append(spacer(1)) story.append(checkbox_row(["1-piece closed bag", "1-piece drainable bag", "2-piece (flange + bag)", "Urostomy / Drainable"], cols=4)) story.append(spacer(2)) story.append(Paragraph("4.2 Appliance Fit & Leakage:", S["label"])) story.append(spacer(1)) story.append(checkbox_row(["Good seal — no leakage", "Occasional minor leakage", "Frequent leakage — major problem", "Cannot maintain seal (retraction/folds)"], cols=2)) story.append(spacer(2)) story.append(Paragraph("4.3 Peristomal Skin Condition:", S["label"])) story.append(spacer(1)) story.append(checkbox_row(["Healthy / Intact", "Mild erythema / Irritation", "Excoriation / Erosion", "Active ulceration"], cols=4)) story.append(checkbox_row(["Rash / Candidal infection", "Bleeding on contact", "Hyperplasia (thickened skin)", "Pyoderma gangrenosum"], cols=4)) story.append(spacer(2)) story.append(Paragraph("4.4 Who manages stoma care?", S["label"])) story.append(spacer(1)) story.append(checkbox_row(["Patient independently", "Family / Carer", "District nurse / Community stoma nurse", "Requires hospital-based assistance"], cols=2)) story.append(spacer(2)) story.append(notes_box("4.5 Appliance / Skin Notes:", lines=2)) story.append(spacer(3)) # ── SECTION 5 — COMPLICATIONS ───────────────────────────────────────────────── story.append(section_header("SECTION 5 — STOMA COMPLICATIONS")) story.append(spacer(2)) story.append(Paragraph( "Tick all that apply. Early = within 30 days; Late = >30 days post-op.", S["note"])) story.append(spacer(2)) comps = [ "Stoma ischaemia / Necrosis (early)", "Stoma retraction (sinks below skin level)", "Stoma prolapse (protrudes excessively)", "Stomal stenosis / Stricture (narrow output)", "Parastomal hernia (bulge around stoma)", "Peristomal skin irritation / Parastomal dermatitis", "Parastomal pyoderma gangrenosum", "Stoma bleeding (peristomal or intraluminal)", "Stoma fistula / Enterocutaneous fistula", "High output / Dehydration / Renal impairment", "Obstruction (food bolus / adhesional)", "Parastomal wound infection / Abscess", ] story.append(complication_table(comps)) story.append(spacer(3)) # ── SECTION 6 — UNDERLYING DISEASE REVIEW ──────────────────────────────────── story.append(section_header("SECTION 6 — UNDERLYING DISEASE REVIEW")) story.append(spacer(2)) story.append(Paragraph("6.1 Evidence of disease recurrence / activity?", S["label"])) story.append(spacer(1)) story.append(checkbox_row(["No signs of recurrence", "Suspected — investigation pending", "Confirmed recurrence / active IBD", "N/A"], cols=4)) story.append(spacer(2)) story.append(Paragraph("6.2 Symptoms in residual bowel / pelvis:", S["label"])) story.append(spacer(1)) story.append(checkbox_row(["PR bleeding / Mucus discharge", "Pelvic pain", "Significant weight loss", "Tenesmus"], cols=4)) story.append(spacer(2)) story.append(notes_box("Disease activity / Recent investigations:", lines=2)) story.append(spacer(3)) # ── SECTION 7 — PMH, MEDICATIONS, ALLERGIES ────────────────────────────────── story.append(section_header("SECTION 7 — PAST MEDICAL HISTORY, MEDICATIONS & ALLERGIES")) story.append(spacer(2)) story.append(Paragraph("7.1 Relevant Past Medical History:", S["label"])) story.append(spacer(1)) story.append(checkbox_row(["Inflammatory bowel disease", "Diabetes mellitus", "Renal impairment / CKD", "Pelvic irradiation"], cols=4)) story.append(checkbox_row(["Obesity (BMI >30)", "Previous abdominal surgery (adhesions)", "Cardiovascular disease", "Immunosuppressed"], cols=4)) story.append(spacer(2)) story.append(notes_box("Other significant PMH:", lines=2)) story.append(spacer(2)) story.append(Paragraph("7.2 Current Medications (stoma-relevant):", S["label"])) story.append(spacer(1)) story.append(checkbox_row(["Loperamide", "Codeine / Opioids", "Oral rehydration salts", "Omeprazole / PPI"], cols=4)) story.append(checkbox_row(["Octreotide", "Biologics (infliximab etc.)", "Steroids / Immunosuppressants", "Anticoagulants / Aspirin"], cols=4)) story.append(spacer(2)) story.append(notes_box("Other medications / Dosages:", lines=2)) story.append(spacer(2)) story.append(Paragraph("7.3 Known Allergies:", S["label"])) story.append(spacer(1)) allergy_t = Table( [[HRFlowable(width=usable_w-10, thickness=0.5, color=BOX_LINE, spaceAfter=1)]], colWidths=[usable_w] ) story.append(allergy_t) story.append(spacer(3)) # ── SECTION 8 — SOCIAL HISTORY & QoL ───────────────────────────────────────── story.append(section_header("SECTION 8 — SOCIAL HISTORY & QUALITY OF LIFE")) story.append(spacer(2)) qol_data = [ ["Domain", "Not a problem", "Mild concern", "Significant impact"], ["Body image / Self-esteem", "☐", "☐", "☐"], ["Sexual function / Intimacy", "☐", "☐", "☐"], ["Clothing / Physical appearance", "☐", "☐", "☐"], ["Diet restriction (blockage, odour)", "☐", "☐", "☐"], ["Physical activity / Exercise", "☐", "☐", "☐"], ["Social activities / Embarrassment", "☐", "☐", "☐"], ["Sleep disturbance (emptying at night)", "☐", "☐", "☐"], ["Return to work / Occupation", "☐", "☐", "☐"], ["Psychological distress / Depression", "☐", "☐", "☐"], ] qol_col_w = [85*mm, 30*mm, 30*mm, 38*mm] qol_t = Table(qol_data, colWidths=qol_col_w, repeatRows=1) qol_t.setStyle(TableStyle([ ("BACKGROUND", (0,0), (3,0), MID_TEAL), ("TEXTCOLOR", (0,0), (3,0), WHITE), ("FONTNAME", (0,0), (3,0), "Helvetica-Bold"), ("FONTSIZE", (0,0), (-1,-1), 8), ("ROWBACKGROUNDS",(0,1), (-1,-1), [WHITE, LIGHT_TEAL]), ("BOX", (0,0), (-1,-1), 0.5, BOX_LINE), ("INNERGRID", (0,0), (-1,-1), 0.3, MID_GREY), ("TOPPADDING", (0,0), (-1,-1), 4), ("BOTTOMPADDING", (0,0), (-1,-1), 4), ("LEFTPADDING", (0,0), (-1,-1), 5), ("RIGHTPADDING", (0,0), (-1,-1), 5), ("ALIGN", (1,0), (-1,-1), "CENTER"), ("VALIGN", (0,0), (-1,-1), "MIDDLE"), ])) story.append(qol_t) story.append(spacer(2)) story.append(Paragraph("8.1 Smoking:", S["label"])) story.append(spacer(1)) story.append(checkbox_row(["Non-smoker", "Ex-smoker", "Current smoker — _____ pack-years"], cols=3)) story.append(spacer(2)) story.append(Paragraph("8.2 Alcohol intake:", S["label"])) story.append(spacer(1)) story.append(checkbox_row(["None", "Occasional / Social", "Regular (specify units/week):__________"], cols=3)) story.append(spacer(3)) # ── SECTION 9 — REVERSAL PLANNING ──────────────────────────────────────────── story.append(section_header("SECTION 9 — STOMA REVERSAL / FUTURE SURGICAL PLANNING")) story.append(spacer(2)) story.append(checkbox_row(["Reversal planned", "Reversal discussed — decision pending", "Reversal NOT planned", "Already reversed"], cols=4)) story.append(spacer(2)) story.append(Paragraph("9.1 Pre-reversal checklist (if applicable):", S["label"])) story.append(spacer(1)) rev_checks = [ ("Anastomosis healed (imaging / contrast enema confirmed)", "☐"), ("Oncological treatment completed (chemo/radiotherapy)", "☐"), ("No active pelvic sepsis / fistula", "☐"), ("Anorectal function / continence assessed", "☐"), ("Sphincter function satisfactory (manometry / clinical exam)", "☐"), ("Patient medically fit for anaesthesia", "☐"), ("Nutritional status optimised", "☐"), ] rev_data = [[Paragraph(item, S["body"]), Paragraph(chk, S["body"])] for item, chk in rev_checks] rev_t = Table(rev_data, colWidths=[145*mm, 18*mm]) rev_t.setStyle(TableStyle([ ("ROWBACKGROUNDS", (0,0), (-1,-1), [WHITE, LIGHT_TEAL]), ("BOX", (0,0), (-1,-1), 0.5, BOX_LINE), ("INNERGRID", (0,0), (-1,-1), 0.3, MID_GREY), ("TOPPADDING", (0,0), (-1,-1), 3), ("BOTTOMPADDING", (0,0), (-1,-1), 3), ("LEFTPADDING", (0,0), (-1,-1), 6), ("RIGHTPADDING", (0,0), (-1,-1), 6), ("ALIGN", (1,0), (1,-1), "CENTER"), ("VALIGN", (0,0), (-1,-1), "MIDDLE"), ])) story.append(rev_t) story.append(spacer(3)) # ── SECTION 10 — CLINICIAN SUMMARY ─────────────────────────────────────────── story.append(section_header("SECTION 10 — CLINICIAN SUMMARY & PLAN")) story.append(spacer(2)) story.append(notes_box("Key findings and clinical impression:", lines=3)) story.append(spacer(2)) story.append(notes_box("Action plan / Referrals / Follow-up:", lines=3)) story.append(spacer(2)) sign_data = [ [ [Paragraph("Clinician Signature:", S["label"]), HRFlowable(width=55*mm, thickness=0.5, color=BOX_LINE, spaceAfter=1, spaceBefore=1)], [Paragraph("Print Name:", S["label"]), HRFlowable(width=55*mm, thickness=0.5, color=BOX_LINE, spaceAfter=1, spaceBefore=1)], [Paragraph("Date:", S["label"]), HRFlowable(width=30*mm, thickness=0.5, color=BOX_LINE, spaceAfter=1, spaceBefore=1)], ], ] sign_t = Table(sign_data, colWidths=[72*mm, 68*mm, 43*mm]) sign_t.setStyle(TableStyle([ ("BACKGROUND", (0,0), (-1,-1), LIGHT_GREY), ("BOX", (0,0), (-1,-1), 0.5, BOX_LINE), ("INNERGRID", (0,0), (-1,-1), 0.3, MID_GREY), ("TOPPADDING", (0,0), (-1,-1), 5), ("BOTTOMPADDING", (0,0), (-1,-1), 6), ("LEFTPADDING", (0,0), (-1,-1), 6), ("RIGHTPADDING", (0,0), (-1,-1), 4), ("VALIGN", (0,0), (-1,-1), "TOP"), ])) story.append(sign_t) story.append(spacer(2)) # ── FOOTER NOTE ─────────────────────────────────────────────────────────────── story.append(HRFlowable(width=usable_w, thickness=0.5, color=MID_TEAL)) story.append(spacer(1)) story.append(Paragraph( "This form is for clinical documentation only and should be filed in the patient medical record. " "All assessments should be reviewed by a qualified clinician or enterostomal therapy (ET/WOCN) nurse.", S["footer"] )) # ── BUILD PDF ───────────────────────────────────────────────────────────────── def add_page_numbers(canvas, doc): canvas.saveState() canvas.setFont("Helvetica", 7) canvas.setFillColor(colors.HexColor("#999999")) canvas.drawRightString(W - 16*mm, 8*mm, f"Page {doc.page} | Stoma Patient History Form | {doc.build.__module__}") canvas.drawString(16*mm, 8*mm, "CONFIDENTIAL — Patient Medical Record") canvas.restoreState() def add_page_footer(canvas, doc): canvas.saveState() canvas.setFont("Helvetica", 7) canvas.setFillColor(colors.HexColor("#999999")) canvas.drawRightString(W - 16*mm, 8*mm, f"Page {doc.page}") canvas.drawString(16*mm, 8*mm, "CONFIDENTIAL — Patient Medical Record") canvas.restoreState() doc.build(story, onFirstPage=add_page_footer, onLaterPages=add_page_footer) print("SUCCESS:", OUTPUT) PYEOF
python3 -c " import pdfplumber with pdfplumber.open('/tmp/workspace/stoma-form/Stoma_Patient_History_Form.pdf') as pdf: print(f'Pages: {len(pdf.pages)}') for i, page in enumerate(pdf.pages): txt = page.extract_text() print(f'--- Page {i+1} (first 200 chars) ---') print(txt[:200] if txt else '[no text layer]') "
ls -lh /tmp/workspace/stoma-form/Stoma_Patient_History_Form.pdf
Stoma Patient History Form
PDF Document · PDF
| Section | Contents |
|---|---|
| 1 - Demographics | Patient name, DOB, MRN, clinician, ward, date |
| 2 - Stoma Details | Type (ileostomy/colostomy/urostomy), configuration (end/loop/double-barrel), permanence, date formed, operation, indication with checkboxes (cancer, IBD, diverticular, trauma, FAP, etc.) |
| 3 - Output & Function | Bag change frequency, estimated volume, consistency, colour, high-output flag, flatus assessment |
| 4 - Appliance & Skin | Appliance type, seal/leakage grading, peristomal skin condition (incl. pyoderma gangrenosum), who manages care |
| 5 - Complications | Full table (12 complications) with Yes/No/? tick boxes and a details/duration field for each |
| 6 - Underlying Disease | Recurrence/activity check, residual bowel symptoms |
| 7 - PMH, Medications & Allergies | Relevant comorbidities, stoma-relevant drugs (loperamide, octreotide, biologics, anticoagulants) |
| 8 - Social History & QoL | 9-domain impact table (body image, sexual function, diet, sleep, occupation, etc.), smoking, alcohol |
| 9 - Reversal Planning | Reversal status + 7-item pre-reversal checklist |
| 10 - Clinician Summary | Free-text findings, action plan, signature block |
Types of stoma
| Feature | Detail |
|---|---|
| Position | Right iliac fossa |
| Output | Liquid to semi-liquid, 500-800 mL/day |
| Appearance | Spouted (2-4 cm protrusion) |
| Risk | Dehydration, electrolyte imbalances, renal failure |
| Odour | Less offensive than colostomy |

| Feature | Detail |
|---|---|
| Position | Left iliac fossa (sigmoid/descending); right flank (caecal/ascending); epigastric (transverse) |
| Output | Formed to semi-formed stool |
| Appearance | Flush with skin (no spout) |
| Risk | Constipation, obstruction, prolapse (esp. transverse) |
| Type | Site | Effluent | Notes |
|---|---|---|---|
| Ascending colostomy | Ascending colon | Liquid - semi-liquid | Rarely used; high output |
| Transverse colostomy | Transverse colon | Semi-formed | Avoided - prone to prolapse, sits at belt line |
| Descending colostomy | Descending colon | Semi-formed | Acceptable alternative |
| Sigmoid colostomy | Sigmoid colon | Formed | Most common; Hartmann's procedure |
Descending and left-sided colostomies are usually preferable because most of the colon remains in circuit, allowing more colonic water absorption, producing more formed effluent. - Sabiston Textbook of Surgery
Transverse loop colostomies should seldom be used because they are large and very prone to prolapse, and it can be difficult to maintain pouch adherence because they are frequently located around the patient's belt line. - Sabiston
A loop ileostomy is often used for defunctioning a low rectal anastomosis or an ileal pouch. A knuckle of ileum is exteriorised through a skin trephine in the right iliac fossa... This allows near-perfect defunctioning, but also the possibility of restoration of continuity. - Bailey & Love
| Type | Description | Example |
|---|---|---|
| Temporary (defunctioning) | Created to divert the faecal stream while a distal anastomosis heals or disease is treated; planned for reversal | Loop ileostomy after anterior resection |
| Permanent | No planned reversal; bowel continuity cannot or will not be restored | APR end colostomy, total proctocolectomy end ileostomy |
| Feature | Ileostomy | Colostomy | Urostomy |
|---|---|---|---|
| Bowel segment | Ileum | Colon (sigmoid/transverse/desc.) | Ileum (conduit) |
| Position | Right iliac fossa | Left iliac fossa (sigmoid) | Right iliac fossa |
| Appearance | Spouted (2-4 cm) | Flush | Spouted/flush |
| Output | Liquid, 500-1500 mL/day | Formed to semi-formed | Urine, continuous |
| Odour | Less | More | Urine |
| Skin risk | High (alkaline/enzyme-rich effluent) | Lower | High (urine) |
| Electrolyte risk | High (dehydration, Na/K loss) | Low | Low |
| Bag type | Drainable | Closed or drainable | Drainable (urostomy) |
| Reversal | Yes (loop) or No (end after TPC) | Yes (Hartmann's) or No (APR) | No (usually permanent) |