add submit_filing(): 3x web retry then fax fallback, fix success detection, shared attestation helper
This commit is contained in:
parent
4a4bbd048e
commit
b90d443667
2 changed files with 162 additions and 37 deletions
|
|
@ -174,6 +174,141 @@ async def poll_fax_status(log_id: str | int, timeout: int = 300, interval: int =
|
|||
}
|
||||
|
||||
|
||||
async def submit_filing(
|
||||
original_pdf_path: str,
|
||||
pdf_url: str = "",
|
||||
photo_id_path: str | None = None,
|
||||
order_number: str = "",
|
||||
dot_number: str = "",
|
||||
mc_number: str = "",
|
||||
entity_name: str = "",
|
||||
document_type: str = "MCS-150 Biennial Update",
|
||||
recipient_name: str = "Federal Motor Carrier Safety Administration (FMCSA)",
|
||||
web_retries: int = 3,
|
||||
web_retry_interval: int = 600,
|
||||
) -> dict:
|
||||
"""Submit a filing to FMCSA: try web submission first, fall back to fax.
|
||||
|
||||
Attempts electronic submission via ask.fmcsa.dot.gov up to `web_retries`
|
||||
times, waiting `web_retry_interval` seconds between attempts. If all
|
||||
web attempts fail, falls back to faxing to FMCSA at 202-366-3477.
|
||||
|
||||
After successful submission (either method), generates an attestation
|
||||
cover page with digital signature and prepends it to the original PDF.
|
||||
|
||||
Returns:
|
||||
dict with keys: success, method, attested_pdf, submitted_at,
|
||||
screenshot_path, fax_log_id, error
|
||||
"""
|
||||
from scripts.workers.services.fmcsa_web_submitter import submit_mcs150
|
||||
|
||||
# ── Phase 1: Try web submission (up to 3 attempts, 10 min apart) ──
|
||||
for attempt in range(1, web_retries + 1):
|
||||
LOG.info("[filing] Web submission attempt %d/%d for DOT %s",
|
||||
attempt, web_retries, dot_number)
|
||||
|
||||
web_result = await submit_mcs150(
|
||||
pdf_path=original_pdf_path,
|
||||
photo_id_path=photo_id_path,
|
||||
dot_number=dot_number,
|
||||
mc_number=mc_number,
|
||||
entity_name=entity_name,
|
||||
)
|
||||
|
||||
if web_result["success"]:
|
||||
LOG.info("[filing] Web submission succeeded for DOT %s on attempt %d",
|
||||
dot_number, attempt)
|
||||
# Generate attestation
|
||||
attested = await _generate_attestation(
|
||||
original_pdf_path=original_pdf_path,
|
||||
order_number=order_number,
|
||||
dot_number=dot_number,
|
||||
entity_name=entity_name,
|
||||
document_type=document_type,
|
||||
recipient_name=recipient_name,
|
||||
submitted_at=datetime.fromisoformat(web_result["submitted_at"]),
|
||||
)
|
||||
return {
|
||||
"success": True,
|
||||
"method": "web",
|
||||
"attested_pdf": attested,
|
||||
"submitted_at": web_result["submitted_at"],
|
||||
"screenshot_path": web_result.get("screenshot_path")
|
||||
or web_result.get("pre_submit_screenshot"),
|
||||
"fax_log_id": None,
|
||||
"error": None,
|
||||
}
|
||||
|
||||
LOG.warning("[filing] Web attempt %d failed: %s", attempt, web_result["error"])
|
||||
if attempt < web_retries:
|
||||
LOG.info("[filing] Waiting %ds before retry...", web_retry_interval)
|
||||
await asyncio.sleep(web_retry_interval)
|
||||
|
||||
# ── Phase 2: Fall back to fax ──
|
||||
LOG.info("[filing] All %d web attempts failed, falling back to fax for DOT %s",
|
||||
web_retries, dot_number)
|
||||
|
||||
if not pdf_url:
|
||||
return {
|
||||
"success": False,
|
||||
"method": "none",
|
||||
"attested_pdf": None,
|
||||
"submitted_at": None,
|
||||
"screenshot_path": None,
|
||||
"fax_log_id": None,
|
||||
"error": "Web submission failed and no PDF URL provided for fax fallback",
|
||||
}
|
||||
|
||||
fax_result = await send_and_attest(
|
||||
pdf_url=pdf_url,
|
||||
original_pdf_path=original_pdf_path,
|
||||
order_number=order_number,
|
||||
dot_number=dot_number,
|
||||
entity_name=entity_name,
|
||||
document_type=document_type,
|
||||
recipient_name=recipient_name,
|
||||
)
|
||||
|
||||
return {
|
||||
"success": fax_result["success"],
|
||||
"method": "fax" if fax_result["success"] else "none",
|
||||
"attested_pdf": fax_result.get("attested_pdf"),
|
||||
"submitted_at": fax_result.get("submitted_at"),
|
||||
"screenshot_path": None,
|
||||
"fax_log_id": fax_result.get("fax_log_id"),
|
||||
"error": fax_result.get("error"),
|
||||
}
|
||||
|
||||
|
||||
async def _generate_attestation(
|
||||
original_pdf_path: str,
|
||||
order_number: str,
|
||||
dot_number: str,
|
||||
entity_name: str,
|
||||
document_type: str,
|
||||
recipient_name: str,
|
||||
submitted_at: datetime,
|
||||
) -> str | None:
|
||||
"""Generate attestation cover page and prepend to original PDF."""
|
||||
try:
|
||||
from scripts.document_gen.templates.filing_attestation import (
|
||||
generate_attestation_page,
|
||||
prepend_attestation,
|
||||
)
|
||||
attest_pdf = generate_attestation_page(
|
||||
order_number=order_number,
|
||||
dot_number=dot_number,
|
||||
entity_name=entity_name,
|
||||
document_type=document_type,
|
||||
submitted_at=submitted_at,
|
||||
recipient_name=recipient_name,
|
||||
)
|
||||
return prepend_attestation(attest_pdf, original_pdf_path)
|
||||
except Exception as exc:
|
||||
LOG.error("[filing] Attestation generation failed: %s", exc)
|
||||
return None
|
||||
|
||||
|
||||
async def send_and_attest(
|
||||
pdf_url: str,
|
||||
original_pdf_path: str,
|
||||
|
|
@ -216,39 +351,20 @@ async def send_and_attest(
|
|||
|
||||
# 3. Fax delivered — generate attestation
|
||||
submitted_at = datetime.now(timezone.utc)
|
||||
attested = await _generate_attestation(
|
||||
original_pdf_path=original_pdf_path,
|
||||
order_number=order_number,
|
||||
dot_number=dot_number,
|
||||
entity_name=entity_name,
|
||||
document_type=document_type,
|
||||
recipient_name=recipient_name,
|
||||
submitted_at=submitted_at,
|
||||
)
|
||||
|
||||
try:
|
||||
from scripts.document_gen.templates.filing_attestation import (
|
||||
generate_attestation_page,
|
||||
prepend_attestation,
|
||||
)
|
||||
|
||||
attest_pdf = generate_attestation_page(
|
||||
order_number=order_number,
|
||||
dot_number=dot_number,
|
||||
entity_name=entity_name,
|
||||
document_type=document_type,
|
||||
submitted_at=submitted_at,
|
||||
recipient_name=recipient_name,
|
||||
)
|
||||
|
||||
combined_pdf = prepend_attestation(attest_pdf, original_pdf_path)
|
||||
|
||||
LOG.info("[fax] Attested copy generated: %s", combined_pdf)
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"attested_pdf": combined_pdf,
|
||||
"fax_log_id": log_id,
|
||||
"submitted_at": submitted_at.isoformat(),
|
||||
"error": None,
|
||||
}
|
||||
except Exception as exc:
|
||||
LOG.error("[fax] Attestation generation failed: %s", exc)
|
||||
return {
|
||||
"success": True, # Fax still succeeded
|
||||
"attested_pdf": None,
|
||||
"fax_log_id": log_id,
|
||||
"submitted_at": submitted_at.isoformat(),
|
||||
"error": f"Fax sent but attestation failed: {exc}",
|
||||
}
|
||||
return {
|
||||
"success": True,
|
||||
"attested_pdf": attested,
|
||||
"fax_log_id": log_id,
|
||||
"submitted_at": submitted_at.isoformat(),
|
||||
"error": None if attested else "Fax sent but attestation generation failed",
|
||||
}
|
||||
|
|
|
|||
|
|
@ -229,10 +229,19 @@ async def submit_mcs150(
|
|||
confirmation_text = await page.inner_text("body")
|
||||
|
||||
# Check for success indicators
|
||||
success = any(kw in confirmation_text.lower() for kw in [
|
||||
# Note: after successful submission, FMCSA redirects to www.fmcsa.dot.gov
|
||||
# which may return 403 (Akamai WAF). The submission still went through —
|
||||
# FMCSA sends a confirmation email to the address we provided.
|
||||
# So a redirect away from ask.fmcsa.dot.gov IS a success signal.
|
||||
redirected_away = "ask.fmcsa.dot.gov" not in page.url
|
||||
has_confirmation_keywords = any(kw in confirmation_text.lower() for kw in [
|
||||
"thank you", "submitted", "received", "confirmation",
|
||||
"reference number", "ticket", "case"
|
||||
"reference number", "ticket", "case",
|
||||
])
|
||||
has_error_keywords = any(kw in confirmation_text.lower() for kw in [
|
||||
"please select an item", "required field", "invalid",
|
||||
])
|
||||
success = (redirected_away or has_confirmation_keywords) and not has_error_keywords
|
||||
|
||||
LOG.info("[fmcsa] Submission %s for DOT %s",
|
||||
"succeeded" if success else "may have failed", dot_number)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue