rpa-bot-handoff: email To the developer with their manager in CC, and hand ops a PDF
- Section 5 of the SOP now names a real "To" (the developer) and "CC" (the developer's manager, not the operator's), and the email block to copy starts with To: and CC: lines. The skill asks for both addresses. - to_docx.py --pdf also writes the PDF (Word through PowerShell on Windows, LibreOffice elsewhere) and prints the real page count against MAX_PAGES. The PDF is what ops gets. - Tebra reference and README updated; new test for the To/CC lines. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
717f2c40c5
commit
0188de7403
6 files changed
+62
-22
No files matched your search
@@ -1,6 +1,6 @@
|
||||
# {{PROJECT_NAME}} Handover SOP
|
||||
|
||||
Version {{VERSION}} · {{DATE}} · Problems: email {{EMAIL_GROUP}} (section 5)
|
||||
Version {{VERSION}} · {{DATE}} · Problems: email {{DEV_EMAIL}}, CC {{MANAGER_EMAIL}} (section 5)
|
||||
|
||||
{{ONE_LINE: what the bot does, from which app or portal, and what it produces}}
|
||||
|
||||
@@ -58,9 +58,11 @@ Version {{VERSION}} · {{DATE}} · Problems: email {{EMAIL_GROUP}} (section 5)
|
||||
|
||||
## 5. Email us
|
||||
|
||||
Email **{{EMAIL_GROUP}}** when section 4 says "email us", or when the same error comes back after one re-run. Answer: {{RESPONSE_TIME}}.
|
||||
Email **{{DEV_EMAIL}}** with **{{MANAGER_NAME}}** ({{MANAGER_EMAIL}}) in CC when section 4 says "email us", or when the same error comes back after one re-run. Answer: {{RESPONSE_TIME}}.
|
||||
|
||||
```
|
||||
To: {{DEV_EMAIL}}
|
||||
CC: {{MANAGER_EMAIL}}
|
||||
Subject: {{PROJECT_NAME}} - E<number> - <date>
|
||||
|
||||
Run started: <time from the screen>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# Worked example: Tebra Auto Post (v2.5.3), scrubbed
|
||||
|
||||
What the SOP looks like for a real bot: about 2.5 pages. Client names, IDs, amounts, credentials and server addresses are removed, and the email address is an example. **Copy the length and the plain wording, not the content.**
|
||||
What the SOP looks like for a real bot: about 2.5 pages. Client names, IDs, amounts, credentials and server addresses are removed, and the email addresses are examples. **Copy the length and the plain wording, not the content.**
|
||||
|
||||
---
|
||||
|
||||
# Tebra Auto Post Handover SOP
|
||||
|
||||
Version 2.5.3 · 28 Oct 2026 · Problems: email rpa-support@example.com (section 5)
|
||||
Version 2.5.3 · 28 Oct 2026 · Problems: email dev@example.com, CC manager@example.com (section 5)
|
||||
|
||||
Posts insurance ERA payments into the Tebra desktop app, company by company and practice by practice, from the input Excel, then turns each ERA into a PDF.
|
||||
|
||||
@@ -83,9 +83,11 @@ Posts insurance ERA payments into the Tebra desktop app, company by company and
|
||||
|
||||
## 5. Email us
|
||||
|
||||
Email **rpa-support@example.com** when section 4 says "email us", or when the same error comes back after one Resume. Answer: same working day.
|
||||
Email **dev@example.com** with **the RPA manager** (manager@example.com) in CC when section 4 says "email us", or when the same error comes back after one Resume. Answer: same working day.
|
||||
|
||||
```
|
||||
To: dev@example.com
|
||||
CC: manager@example.com
|
||||
Subject: Tebra Auto Post - E<number> - <date>
|
||||
|
||||
Batch ID: <from the Dashboard>
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
"""Turn the Handover SOP (HANDOVER-SOP.md) into a Word document ops can open, print and pass around.
|
||||
"""Turn the Handover SOP (HANDOVER-SOP.md) into a Word document, and a PDF, ops can open, print and pass around.
|
||||
|
||||
python to_docx.py HANDOVER-SOP.md # writes HANDOVER-SOP.docx next to it
|
||||
python to_docx.py HANDOVER-SOP.md -o "<Project Name> Handover SOP.docx"
|
||||
python to_docx.py HANDOVER-SOP.md -o "<Project Name> Handover SOP.docx" --pdf # + the .pdf next to it
|
||||
python to_docx.py --selfcheck
|
||||
|
||||
Prints the word count: the SOP must stay at or under MAX_WORDS (about 4 pages).
|
||||
Prints the word count (at most MAX_WORDS) and, with --pdf, the real page count (at most MAX_PAGES).
|
||||
The PDF is made by Word on Windows (through PowerShell) or by LibreOffice (soffice) elsewhere.
|
||||
|
||||
Handles what the template uses: # headings, paragraphs, - bullets, - [ ] checkboxes, 1. steps,
|
||||
| tables |, ``` blocks, **bold**, *italic* and `code`. Needs python-docx (pip install python-docx).
|
||||
"""
|
||||
import argparse
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
@@ -19,6 +21,7 @@ from docx import Document
|
||||
from docx.shared import Cm, Pt
|
||||
|
||||
MAX_WORDS = 1400 # about 4 pages with the margins and table font below
|
||||
MAX_PAGES = 4
|
||||
INLINE = re.compile(r"(\*\*[^*]+\*\*|\*[^*\s][^*]*\*|`[^`]+`)")
|
||||
|
||||
|
||||
@@ -96,6 +99,26 @@ def words(md_text):
|
||||
return len(re.findall(r"[A-Za-z0-9][\w'’.-]*", re.sub(r"^\|[\s:|-]+\|\s*$", "", md_text, flags=re.M)))
|
||||
|
||||
|
||||
def to_pdf(docx_path):
|
||||
"""Write the PDF next to the docx. Returns (pdf path, page count or None); pdf path is None on failure."""
|
||||
docx_path = Path(docx_path).resolve()
|
||||
pdf = docx_path.with_suffix(".pdf")
|
||||
pages = None
|
||||
if sys.platform == "win32":
|
||||
q = lambda p: str(p).replace("'", "''") # PowerShell single-quote escape
|
||||
ps = (f"$w = New-Object -ComObject Word.Application; $w.Visible = $false; "
|
||||
f"$d = $w.Documents.Open('{q(docx_path)}', $false, $true); "
|
||||
f"Write-Output ('pages=' + $d.ComputeStatistics(2)); $d.SaveAs2('{q(pdf)}', 17); "
|
||||
f"try {{ $d.Close(0) }} catch {{}}; try {{ $w.Quit() }} catch {{}}")
|
||||
r = subprocess.run(["powershell", "-NoProfile", "-Command", ps], capture_output=True, text=True)
|
||||
if m := re.search(r"pages=(\d+)", r.stdout):
|
||||
pages = int(m[1])
|
||||
else:
|
||||
subprocess.run(["soffice", "--headless", "--convert-to", "pdf", "--outdir", str(pdf.parent), str(docx_path)],
|
||||
capture_output=True)
|
||||
return (pdf if pdf.exists() else None), pages
|
||||
|
||||
|
||||
def selfcheck():
|
||||
example = Path(__file__).parent / "reference" / "tebra-auto-post.md"
|
||||
sop = "# " + example.read_text(encoding="utf-8").split("\n---\n", 1)[1].split("\n# ", 1)[1]
|
||||
@@ -116,6 +139,7 @@ if __name__ == "__main__":
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("md", nargs="?")
|
||||
ap.add_argument("-o", "--out")
|
||||
ap.add_argument("--pdf", action="store_true", help="also write the PDF next to the docx")
|
||||
ap.add_argument("--selfcheck", action="store_true")
|
||||
a = ap.parse_args()
|
||||
if a.selfcheck:
|
||||
@@ -129,3 +153,9 @@ if __name__ == "__main__":
|
||||
convert(text, out)
|
||||
n = words(text)
|
||||
print(f"wrote {out} ({n} words{'' if n <= MAX_WORDS else f', OVER the {MAX_WORDS}-word limit: cut it'})")
|
||||
if a.pdf:
|
||||
pdf, pages = to_pdf(out)
|
||||
if not pdf:
|
||||
sys.exit("no PDF: needs Word (Windows) or LibreOffice (soffice). Hand over the docx instead.")
|
||||
over = pages and pages > MAX_PAGES
|
||||
print(f"wrote {pdf} ({pages or '?'} pages{f', OVER the {MAX_PAGES}-page limit: cut it' if over else ''})")
|
||||
Reference in new issue
Block a user