Add Canadian Wholesale Vendor Reference Guide to CRTC binder
New DOCX generator with 8 recommended upstream providers: Fibernetics, Iristel, Flowroute, VoIP.ms, Telnyx, SkySwitch, Distributel, Allstream. Each with services, website, and notes. Wired into CRTC handler Step 6a (generates before eSign pause) and added to binder compiler default sections. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
7aec5b23cb
commit
32c1e57c5c
3 changed files with 253 additions and 0 deletions
238
scripts/document_gen/templates/crtc_vendor_guide_generator.py
Normal file
238
scripts/document_gen/templates/crtc_vendor_guide_generator.py
Normal file
|
|
@ -0,0 +1,238 @@
|
|||
"""
|
||||
Generate a Canadian Wholesale Vendor Reference Guide for CRTC corporate binders.
|
||||
|
||||
Lists recommended upstream voice, data, DID, and UCaaS providers for
|
||||
Canadian telecom resellers. Included in the "Miscellaneous" section of
|
||||
the corporate binder delivered to CRTC carrier package clients.
|
||||
|
||||
Usage:
|
||||
from scripts.document_gen.templates.crtc_vendor_guide_generator import generate_vendor_guide
|
||||
path = generate_vendor_guide(
|
||||
entity_name="1234567 B.C. Ltd.",
|
||||
output_path="/tmp/vendor_guide.docx",
|
||||
)
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
LOG = logging.getLogger("document_gen.crtc_vendor_guide")
|
||||
|
||||
try:
|
||||
from docx import Document
|
||||
from docx.shared import Pt, Inches, RGBColor
|
||||
from docx.enum.text import WD_ALIGN_PARAGRAPH
|
||||
except ImportError:
|
||||
LOG.warning("python-docx not installed — vendor guide generation unavailable")
|
||||
Document = None
|
||||
|
||||
NAVY = RGBColor(0x1A, 0x27, 0x44) if RGBColor else None
|
||||
GRAY = RGBColor(0x64, 0x74, 0x8B) if RGBColor else None
|
||||
GREEN = RGBColor(0x05, 0x96, 0x69) if RGBColor else None
|
||||
|
||||
VENDORS = [
|
||||
{
|
||||
"name": "Fibernetics",
|
||||
"location": "Cambridge, ON",
|
||||
"services": "Wholesale SIP trunking, hosted PBX white-label, DID origination (Canada & US), "
|
||||
"wholesale voice termination, fax-over-IP. Full API for provisioning.",
|
||||
"website": "fibernetics.ca",
|
||||
"notes": "Popular choice for Canadian resellers. Offers white-label UCaaS platform. "
|
||||
"Competitive wholesale voice rates. Canadian-owned and operated.",
|
||||
},
|
||||
{
|
||||
"name": "Iristel",
|
||||
"location": "Markham, ON",
|
||||
"services": "Wholesale voice termination (70+ countries), international DID numbers, "
|
||||
"MVNO solutions, SIP trunking, SMS/MMS, STIR/SHAKEN attestation services.",
|
||||
"website": "iristel.com",
|
||||
"notes": "One of Canada's largest independent carriers. Operates in 70+ countries. "
|
||||
"Has US operations and participates in the FCC RMD. Good for international voice.",
|
||||
},
|
||||
{
|
||||
"name": "Flowroute (Intrado)",
|
||||
"location": "Seattle, WA (serves Canada)",
|
||||
"services": "US and Canadian DID provisioning (number-level API), SIP trunking, "
|
||||
"SMS/MMS API, E911, CNAM. Per-minute and per-channel pricing.",
|
||||
"website": "flowroute.com",
|
||||
"notes": "Performance West's default DID provider for CRTC packages. Excellent API. "
|
||||
"Canadian numbers available in BC, ON, AB, QC area codes. US-based but serves "
|
||||
"Canadian carriers seamlessly under the shared +1 numbering plan.",
|
||||
},
|
||||
{
|
||||
"name": "VoIP.ms",
|
||||
"location": "Montreal, QC",
|
||||
"services": "Canadian and US DIDs, SIP trunking, pay-per-minute voice, toll-free numbers, "
|
||||
"SMS, fax, E911. Self-serve portal with instant provisioning.",
|
||||
"website": "voip.ms",
|
||||
"notes": "Developer-friendly with extensive API. Very competitive per-minute rates. "
|
||||
"Popular with small-to-mid carriers and UCaaS resellers. Canadian-owned.",
|
||||
},
|
||||
{
|
||||
"name": "Telnyx",
|
||||
"location": "Chicago, IL (global network)",
|
||||
"services": "Global SIP trunking, DID provisioning (40+ countries), SMS/MMS API, "
|
||||
"wireless (eSIM), storage, identity verification. Mission control portal.",
|
||||
"website": "telnyx.com",
|
||||
"notes": "Full-stack communications platform. Private global network with PoPs in "
|
||||
"Toronto and Vancouver. Strong API-first approach. Good for carriers building "
|
||||
"programmable voice/messaging products.",
|
||||
},
|
||||
{
|
||||
"name": "SkySwitch (Sangoma)",
|
||||
"location": "Huntsville, AL / Toronto, ON",
|
||||
"services": "White-label UCaaS platform, hosted PBX, contact center, SIP trunking, "
|
||||
"SD-WAN. Complete reseller portal with billing integration.",
|
||||
"website": "skyswitch.com",
|
||||
"notes": "Full white-label UC platform — you sell under your brand, they handle the "
|
||||
"infrastructure. Popular with ISPs and MSPs adding voice services. "
|
||||
"Owned by Sangoma (Canadian company, TSX:STC).",
|
||||
},
|
||||
{
|
||||
"name": "Distributel",
|
||||
"location": "Toronto, ON",
|
||||
"services": "Wholesale internet (DSL, cable, fibre), wholesale voice, SIP trunking. "
|
||||
"CLEC with TPIA access to incumbent networks.",
|
||||
"website": "distributel.ca",
|
||||
"notes": "One of Canada's original competitive carriers. Strong wholesale internet "
|
||||
"offering. Good option if your Canadian entity needs to resell broadband "
|
||||
"in addition to voice.",
|
||||
},
|
||||
{
|
||||
"name": "Allstream (Zayo Canada)",
|
||||
"location": "Toronto, ON",
|
||||
"services": "Enterprise SIP trunking, MPLS, dedicated internet, SD-WAN, "
|
||||
"unified communications. Fibre network across major Canadian cities.",
|
||||
"website": "allstream.com",
|
||||
"notes": "Enterprise-grade wholesale provider. Extensive Canadian fibre network. "
|
||||
"Better suited for larger carriers or those needing dedicated circuits. "
|
||||
"Owned by Zayo Group.",
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def generate_vendor_guide(
|
||||
entity_name: str,
|
||||
output_path: str,
|
||||
) -> str | None:
|
||||
"""Generate the vendor reference guide DOCX."""
|
||||
if Document is None:
|
||||
LOG.error("python-docx not installed")
|
||||
return None
|
||||
|
||||
doc = Document()
|
||||
|
||||
# Page setup
|
||||
for section in doc.sections:
|
||||
section.top_margin = Inches(1)
|
||||
section.bottom_margin = Inches(1)
|
||||
section.left_margin = Inches(1)
|
||||
section.right_margin = Inches(1)
|
||||
|
||||
# Title
|
||||
title = doc.add_paragraph()
|
||||
title.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
||||
run = title.add_run("Canadian Wholesale Vendor Reference Guide")
|
||||
run.font.size = Pt(18)
|
||||
run.font.color.rgb = NAVY
|
||||
run.font.bold = True
|
||||
|
||||
# Subtitle
|
||||
sub = doc.add_paragraph()
|
||||
sub.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
||||
sr = sub.add_run(f"Prepared for {entity_name}")
|
||||
sr.font.size = Pt(11)
|
||||
sr.font.color.rgb = GRAY
|
||||
|
||||
date_p = doc.add_paragraph()
|
||||
date_p.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
||||
dr = date_p.add_run(datetime.now().strftime("%B %Y"))
|
||||
dr.font.size = Pt(10)
|
||||
dr.font.color.rgb = GRAY
|
||||
|
||||
# Intro
|
||||
doc.add_paragraph()
|
||||
intro = doc.add_paragraph()
|
||||
ir = intro.add_run(
|
||||
"As a newly registered Canadian telecommunications service provider, you will need "
|
||||
"upstream wholesale partners to provide voice termination, DID numbers, SIP trunking, "
|
||||
"and potentially white-label UCaaS or broadband services. This guide lists vendors "
|
||||
"commonly used by Canadian telecom resellers."
|
||||
)
|
||||
ir.font.size = Pt(10)
|
||||
ir.font.color.rgb = RGBColor(0x37, 0x41, 0x51)
|
||||
|
||||
intro2 = doc.add_paragraph()
|
||||
ir2 = intro2.add_run(
|
||||
"Performance West does not endorse or guarantee any of these vendors. This list is "
|
||||
"provided for reference only. You should evaluate each provider based on your specific "
|
||||
"business requirements, traffic volume, geographic coverage needs, and pricing."
|
||||
)
|
||||
ir2.font.size = Pt(9)
|
||||
ir2.font.color.rgb = GRAY
|
||||
ir2.font.italic = True
|
||||
|
||||
# Vendors
|
||||
for vendor in VENDORS:
|
||||
doc.add_paragraph()
|
||||
|
||||
# Vendor name
|
||||
name_p = doc.add_paragraph()
|
||||
nr = name_p.add_run(vendor["name"])
|
||||
nr.font.size = Pt(13)
|
||||
nr.font.color.rgb = NAVY
|
||||
nr.font.bold = True
|
||||
|
||||
loc_r = name_p.add_run(f" — {vendor['location']}")
|
||||
loc_r.font.size = Pt(10)
|
||||
loc_r.font.color.rgb = GRAY
|
||||
|
||||
# Website
|
||||
web_p = doc.add_paragraph()
|
||||
wr = web_p.add_run(vendor["website"])
|
||||
wr.font.size = Pt(9)
|
||||
wr.font.color.rgb = RGBColor(0x1E, 0x40, 0xAF)
|
||||
wr.font.underline = True
|
||||
|
||||
# Services
|
||||
svc_label = doc.add_paragraph()
|
||||
sl = svc_label.add_run("Services: ")
|
||||
sl.font.size = Pt(9)
|
||||
sl.font.bold = True
|
||||
sl.font.color.rgb = RGBColor(0x37, 0x41, 0x51)
|
||||
sv = svc_label.add_run(vendor["services"])
|
||||
sv.font.size = Pt(9)
|
||||
sv.font.color.rgb = RGBColor(0x37, 0x41, 0x51)
|
||||
|
||||
# Notes
|
||||
notes_p = doc.add_paragraph()
|
||||
nl = notes_p.add_run("Notes: ")
|
||||
nl.font.size = Pt(9)
|
||||
nl.font.bold = True
|
||||
nl.font.color.rgb = GRAY
|
||||
nn = notes_p.add_run(vendor["notes"])
|
||||
nn.font.size = Pt(9)
|
||||
nn.font.color.rgb = GRAY
|
||||
|
||||
# Footer disclaimer
|
||||
doc.add_paragraph()
|
||||
doc.add_paragraph()
|
||||
disc = doc.add_paragraph()
|
||||
disc_r = disc.add_run(
|
||||
"Document prepared by Performance West Inc., a regulatory compliance consulting firm. "
|
||||
"Performance West Inc. is not a law firm and this document does not constitute legal advice "
|
||||
"or legal representation. Vendor information is current as of the date shown above and "
|
||||
"may change without notice."
|
||||
)
|
||||
disc_r.font.size = Pt(7)
|
||||
disc_r.font.color.rgb = RGBColor(0x99, 0x99, 0x99)
|
||||
disc_r.font.italic = True
|
||||
|
||||
# Save
|
||||
out = Path(output_path)
|
||||
out.parent.mkdir(parents=True, exist_ok=True)
|
||||
doc.save(str(out))
|
||||
LOG.info("Vendor guide generated: %s", out)
|
||||
return str(out)
|
||||
Loading…
Add table
Add a link
Reference in a new issue