Includes: API (Express/TypeScript), Astro site, Python workers, document generators, FCC compliance tools, Canada CRTC formation, Ansible infrastructure, and deployment scripts. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
252 lines
9 KiB
Python
252 lines
9 KiB
Python
"""
|
|
Generate the CRTC Registration Notification Letter as a DOCX file.
|
|
|
|
This produces a formal letter addressed to the Secretary General of the CRTC
|
|
notifying them that a new telecommunications service provider has been
|
|
established under a BC corporation and wishes to register as a:
|
|
- Voice, Data & Wireless Reseller (domestic)
|
|
- Basic International Telecommunications Service (BITS) provider (if applicable)
|
|
|
|
The letter follows the format specified at:
|
|
https://crtc.gc.ca/eng/comm/telecom/registr4.htm
|
|
|
|
Usage:
|
|
from scripts.document_gen.templates.crtc_letter_generator import generate_crtc_letter
|
|
pdf_path = generate_crtc_letter(
|
|
entity_name="1234567 B.C. Ltd.",
|
|
incorporation_number="1234567",
|
|
registered_office="329 Howe St, Vancouver, BC V6C 3N2",
|
|
services_description="Resale of voice, data, and wireless services...",
|
|
geographic_coverage="BC and Worldwide",
|
|
include_bits=True,
|
|
regulatory_contact_name="Regulatory Director",
|
|
regulatory_contact_email="regulatory@example.ca",
|
|
regulatory_contact_phone="+16045551234",
|
|
director_name="John Doe",
|
|
output_path="/tmp/crtc_letter.docx",
|
|
)
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
import os
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
|
|
LOG = logging.getLogger("document_gen.crtc_letter")
|
|
|
|
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 — CRTC letter generation unavailable")
|
|
Document = None
|
|
|
|
|
|
def generate_crtc_letter(
|
|
entity_name: str,
|
|
incorporation_number: str,
|
|
registered_office: str,
|
|
services_description: str,
|
|
geographic_coverage: str = "Canada-wide",
|
|
include_bits: bool = True,
|
|
regulatory_contact_name: str = "Regulatory Director",
|
|
regulatory_contact_email: str = "",
|
|
regulatory_contact_phone: str = "",
|
|
director_name: str = "",
|
|
ca_domain: str = "",
|
|
output_path: str = "/tmp/crtc_notification_letter.docx",
|
|
) -> Optional[str]:
|
|
"""
|
|
Generate a CRTC Registration Notification Letter as a DOCX file.
|
|
|
|
Returns the output file path on success, None on failure.
|
|
"""
|
|
if Document is None:
|
|
LOG.error("python-docx not installed")
|
|
return None
|
|
|
|
doc = Document()
|
|
|
|
# Page margins
|
|
for section in doc.sections:
|
|
section.top_margin = Inches(1)
|
|
section.bottom_margin = Inches(1)
|
|
section.left_margin = Inches(1.25)
|
|
section.right_margin = Inches(1.25)
|
|
|
|
# ── Sender block ──────────────────────────────────────────
|
|
today = datetime.now().strftime("%B %d, %Y")
|
|
|
|
sender = doc.add_paragraph()
|
|
sender.alignment = WD_ALIGN_PARAGRAPH.LEFT
|
|
sender_run = sender.add_run(
|
|
f"{entity_name}\n"
|
|
f"Incorporation No. {incorporation_number}\n"
|
|
f"{registered_office}\n"
|
|
)
|
|
sender_run.font.size = Pt(10)
|
|
if regulatory_contact_phone:
|
|
sender.add_run(f"Tel: {regulatory_contact_phone}\n").font.size = Pt(10)
|
|
if regulatory_contact_email:
|
|
sender.add_run(f"Email: {regulatory_contact_email}\n").font.size = Pt(10)
|
|
if ca_domain:
|
|
sender.add_run(f"Web: https://{ca_domain}\n").font.size = Pt(10)
|
|
|
|
# Date
|
|
date_para = doc.add_paragraph()
|
|
date_para.alignment = WD_ALIGN_PARAGRAPH.LEFT
|
|
date_run = date_para.add_run(today)
|
|
date_run.font.size = Pt(10)
|
|
|
|
# ── Addressee ─────────────────────────────────────────────
|
|
doc.add_paragraph()
|
|
addressee = doc.add_paragraph()
|
|
addressee_run = addressee.add_run(
|
|
"Secretary General\n"
|
|
"Canadian Radio-television and\n"
|
|
"Telecommunications Commission (CRTC)\n"
|
|
"Ottawa, Ontario\n"
|
|
"K1A 0N2"
|
|
)
|
|
addressee_run.font.size = Pt(10)
|
|
|
|
# ── Subject line ──────────────────────────────────────────
|
|
doc.add_paragraph()
|
|
subject = doc.add_paragraph()
|
|
subject_run = subject.add_run(
|
|
f"Re: Registration as a Telecommunications Service Provider — {entity_name}"
|
|
)
|
|
subject_run.font.size = Pt(10)
|
|
subject_run.bold = True
|
|
|
|
# ── Body ──────────────────────────────────────────────────
|
|
doc.add_paragraph()
|
|
|
|
# Introduction
|
|
intro = doc.add_paragraph()
|
|
intro_run = intro.add_run(
|
|
f"Dear Secretary General,\n\n"
|
|
f"Pursuant to the Telecommunications Act, S.C. 1993, c. 38, and the "
|
|
f"Canadian Radio-television and Telecommunications Commission's registration "
|
|
f"requirements for telecommunications service providers, {entity_name} "
|
|
f"(Incorporation No. {incorporation_number}) hereby notifies the Commission of its "
|
|
f"intention to provide telecommunications services in Canada."
|
|
)
|
|
intro_run.font.size = Pt(10)
|
|
|
|
# Company information section
|
|
doc.add_paragraph()
|
|
info_heading = doc.add_paragraph()
|
|
info_heading_run = info_heading.add_run("1. Company Information")
|
|
info_heading_run.font.size = Pt(10)
|
|
info_heading_run.bold = True
|
|
|
|
info = doc.add_paragraph()
|
|
info.style.font.size = Pt(10)
|
|
info_text = (
|
|
f"Legal Name: {entity_name}\n"
|
|
f"Incorporation Number: {incorporation_number}\n"
|
|
f"Mailing Address: {registered_office}\n"
|
|
f"Telephone: {regulatory_contact_phone}\n"
|
|
f"Email: {regulatory_contact_email}\n"
|
|
)
|
|
info.add_run(info_text).font.size = Pt(10)
|
|
|
|
# Services section
|
|
doc.add_paragraph()
|
|
svc_heading = doc.add_paragraph()
|
|
svc_heading_run = svc_heading.add_run("2. Description of Services")
|
|
svc_heading_run.font.size = Pt(10)
|
|
svc_heading_run.bold = True
|
|
|
|
svc = doc.add_paragraph()
|
|
svc.add_run(
|
|
f"{entity_name} intends to operate as a reseller of voice, data, and wireless "
|
|
f"telecommunications services. Specifically:\n\n"
|
|
f"{services_description}\n\n"
|
|
f"Geographic Coverage: {geographic_coverage}"
|
|
).font.size = Pt(10)
|
|
|
|
# Registration type
|
|
doc.add_paragraph()
|
|
reg_heading = doc.add_paragraph()
|
|
reg_heading_run = reg_heading.add_run("3. Registration Category")
|
|
reg_heading_run.font.size = Pt(10)
|
|
reg_heading_run.bold = True
|
|
|
|
reg = doc.add_paragraph()
|
|
reg_text = f"{entity_name} registers as a Voice, Data & Wireless Reseller."
|
|
if include_bits:
|
|
reg_text += (
|
|
f"\n\n{entity_name} also intends to provide Basic International "
|
|
f"Telecommunications Services (BITS) and will file a separate notification "
|
|
f"with the Commission pursuant to CRTC Telecom Decision 98-17."
|
|
)
|
|
reg.add_run(reg_text).font.size = Pt(10)
|
|
|
|
# Response Manager
|
|
doc.add_paragraph()
|
|
rm_heading = doc.add_paragraph()
|
|
rm_heading_run = rm_heading.add_run("4. Response Manager for Regulatory Matters")
|
|
rm_heading_run.font.size = Pt(10)
|
|
rm_heading_run.bold = True
|
|
|
|
rm = doc.add_paragraph()
|
|
rm.add_run(
|
|
f"Name: {regulatory_contact_name}\n"
|
|
f"Title: Regulatory Director\n"
|
|
f"Organization: {entity_name}\n"
|
|
f"Address: {registered_office}\n"
|
|
f"Telephone: {regulatory_contact_phone}\n"
|
|
f"Email: {regulatory_contact_email}"
|
|
).font.size = Pt(10)
|
|
|
|
# Compliance commitment
|
|
doc.add_paragraph()
|
|
compliance_heading = doc.add_paragraph()
|
|
compliance_heading_run = compliance_heading.add_run("5. Compliance")
|
|
compliance_heading_run.font.size = Pt(10)
|
|
compliance_heading_run.bold = True
|
|
|
|
compliance = doc.add_paragraph()
|
|
compliance.add_run(
|
|
f"{entity_name} confirms that it will comply with all applicable provisions of "
|
|
f"the Telecommunications Act, CRTC regulations, and conditions of service, "
|
|
f"including participation in the Commission for Complaints for "
|
|
f"Telecom-Television Services (CCTS)."
|
|
).font.size = Pt(10)
|
|
|
|
# Closing
|
|
doc.add_paragraph()
|
|
doc.add_paragraph()
|
|
closing = doc.add_paragraph()
|
|
closing.add_run("Respectfully submitted,").font.size = Pt(10)
|
|
|
|
# Signature block (space for eSign)
|
|
doc.add_paragraph()
|
|
doc.add_paragraph() # Space for signature
|
|
doc.add_paragraph()
|
|
|
|
sig_line = doc.add_paragraph()
|
|
sig_line.add_run("_" * 40).font.size = Pt(10)
|
|
|
|
sig_name = doc.add_paragraph()
|
|
sig_name_run = sig_name.add_run(director_name or regulatory_contact_name)
|
|
sig_name_run.font.size = Pt(10)
|
|
sig_name_run.bold = True
|
|
|
|
sig_title = doc.add_paragraph()
|
|
sig_title.add_run(f"Director, {entity_name}").font.size = Pt(10)
|
|
|
|
sig_date = doc.add_paragraph()
|
|
sig_date.add_run(f"Date: {today}").font.size = Pt(10)
|
|
|
|
# Save
|
|
output = Path(output_path)
|
|
output.parent.mkdir(parents=True, exist_ok=True)
|
|
doc.save(str(output))
|
|
LOG.info("CRTC letter generated: %s", output)
|
|
return str(output)
|