hc: add 'revalidation due soon' warmup segment (proactive, grows supply)
The HC warmup pool is supply-constrained (~400 verified providers, all fed by the same narrow 'revalidation 1-90 days OVERDUE' slice). This adds a mirror-image proactive segment that targets providers whose Medicare revalidation is UPCOMING within the next 1-90 days, drawn from the same CMS Revalidation Due Date List -- no new data source needed. 'Handle it before your deadline' is a strong pitch and roughly doubles the deliverable pool. - New selector reval_due_soon (status=upcoming, days_until in [HC_DUE_SOON_MIN, HC_DUE_SOON_MAX] default 1-90). - New segment revalidation_due_soon reusing the existing /order/npi-revalidation service ($599) with template hc_revalidation_due_soon.html. - attribs_for now exposes days_until (positive days to due date). - Added to ACTIVE_SEGMENTS.
This commit is contained in:
parent
773c443079
commit
c8c9a04c1d
3 changed files with 149 additions and 3 deletions
106
data/hc_campaigns/hc_revalidation_due_soon.html
Normal file
106
data/hc_campaigns/hc_revalidation_due_soon.html
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><style>@media only screen and (max-width:600px){.pw-wrap{width:100%!important;border-radius:0!important;}.pw-pad{padding:24px 16px!important;}}body,table,td,p,a{-webkit-text-size-adjust:100%;}table{border-collapse:collapse!important;}img{border:0;}</style></head><body style="margin:0;padding:0;background:#eef0f3;">
|
||||
<center>
|
||||
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="background:#eef0f3;"><tr><td style="padding:24px 10px;">
|
||||
<table role="presentation" class="pw-wrap" width="620" cellpadding="0" cellspacing="0" style="margin:0 auto;border-radius:10px;overflow:hidden;background:#fff;">
|
||||
|
||||
<!-- Header -->
|
||||
<tr><td style="background-color:#0f766e;background:linear-gradient(135deg,#0f766e 0%,#14b8a6 100%);padding:26px 28px;">
|
||||
<img src="https://performancewest.net/images/logo-white.png" alt="Performance West" style="height:44px;margin-bottom:10px;display:block" />
|
||||
<h1 style="color:#fff;margin:0;font-size:22px;font-weight:700;font-family:Inter,system-ui,sans-serif;">Medicare Revalidation Reminder</h1>
|
||||
<p style="color:#ccfbf1;margin:6px 0 0;font-size:13px;font-family:Inter,system-ui,sans-serif;">Your CMS revalidation deadline is coming up</p>
|
||||
</td></tr>
|
||||
|
||||
<!-- Body -->
|
||||
<tr><td class="pw-pad" style="padding:28px;font-family:Inter,system-ui,sans-serif;color:#1f2937;">
|
||||
<p style="font-size:15px;margin:0 0 18px;line-height:1.5;">Hi {{ .Subscriber.Name }},</p>
|
||||
<h2 style="font-size:19px;margin:0 0 14px;color:#0f172a;line-height:1.3;">Get ahead of your revalidation deadline</h2>
|
||||
<p style="font-size:14px;line-height:1.7;margin:0 0 18px;">CMS records indicate the Medicare enrollment revalidation for <strong>{{ .Subscriber.Attribs.practice }}</strong> (NPI {{ .Subscriber.Attribs.npi }}) is <strong>coming due</strong>. Handling it now — before the deadline — keeps your billing privileges uninterrupted.</p>
|
||||
|
||||
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="margin:22px 0;"><tr><td style="background:#ecfdf5;border:2px solid #6ee7b7;border-radius:10px;padding:18px;">
|
||||
<h3 style="margin:0 0 10px;font-size:15px;color:#065f46;font-weight:700;">Why act before the date</h3>
|
||||
<div style="font-size:13px;color:#065f46;line-height:1.7;">If a revalidation lapses, CMS can <strong>deactivate your Medicare billing privileges</strong> — claims stop paying and you may have to re-enroll, losing your effective date and any retroactive billing. Filing ahead of the deadline avoids that risk entirely.</div>
|
||||
</td></tr></table>
|
||||
|
||||
<!-- Official CMS record card: data is straight from the CMS Revalidation Due
|
||||
Date List (verified to match by NPI), presented as a clearly-labeled data
|
||||
readout. NOT a CMS screenshot / not impersonating CMS. -->
|
||||
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="margin:22px 0;">
|
||||
<tr><td style="border:1px solid #cbd5e1;border-radius:10px;overflow:hidden;">
|
||||
<table role="presentation" width="100%" cellpadding="0" cellspacing="0">
|
||||
<tr><td style="background:#2563eb;background-image:repeating-linear-gradient(45deg,#0ea5e9 0,#0ea5e9 14px,#ffffff 14px,#ffffff 28px,#2563eb 28px,#2563eb 42px,#ffffff 42px,#ffffff 56px);padding:0;">
|
||||
<p style="margin:0;padding:11px 16px;background:rgba(15,23,42,0.58);font-size:11px;letter-spacing:.4px;text-transform:uppercase;color:#ffffff;font-weight:700;text-align:center;">Official record · CMS Medicare Revalidation Due Date List</p>
|
||||
</td></tr>
|
||||
<tr><td style="background:#f8fafc;padding:6px 16px 14px;">
|
||||
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="font-size:13px;">
|
||||
<tr style="border-bottom:1px solid #e5e7eb;"><td style="padding:9px 0;color:#64748b;">Provider / NPI</td><td style="padding:9px 0;font-weight:700;text-align:right;color:#0f172a;">{{ .Subscriber.Attribs.npi }}</td></tr>
|
||||
<tr style="border-bottom:1px solid #e5e7eb;"><td style="padding:9px 0;color:#64748b;">Enrolled as</td><td style="padding:9px 0;font-weight:600;text-align:right;color:#0f172a;">{{ .Subscriber.Attribs.practice }}</td></tr>
|
||||
<tr style="border-bottom:1px solid #e5e7eb;"><td style="padding:9px 0;color:#64748b;">Revalidation due date</td><td style="padding:9px 0;font-weight:700;text-align:right;color:#b45309;">{{ .Subscriber.Attribs.reval_due_date }}</td></tr>
|
||||
<tr><td style="padding:9px 0;color:#64748b;">Status</td><td style="padding:9px 0;font-weight:700;text-align:right;color:#b45309;">DUE SOON · in {{ .Subscriber.Attribs.days_until }} days</td></tr>
|
||||
</table>
|
||||
<p style="margin:10px 0 0;font-size:11px;color:#94a3b8;line-height:1.5;">Source: CMS Revalidation Due Date List (data.cms.gov), refreshed monthly.</p>
|
||||
</td></tr>
|
||||
</table>
|
||||
</td></tr>
|
||||
</table>
|
||||
|
||||
<!-- Verify-it-yourself: nothing is more convincing than the government's own site -->
|
||||
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="margin:14px 0 22px;"><tr><td style="background:#eff6ff;border:1px solid #bfdbfe;border-radius:10px;padding:16px;">
|
||||
<p style="margin:0 0 6px;font-size:13px;color:#1e3a8a;font-weight:700;">Don’t take our word for it — check the official CMS record.</p>
|
||||
<p style="margin:0 0 12px;font-size:13px;color:#1e40af;line-height:1.6;">Look up your NPI <strong>{{ .Subscriber.Attribs.npi }}</strong> on the U.S. government’s public Medicare Revalidation List and you’ll see the same due date above.</p>
|
||||
<a href="https://data.cms.gov/tools/medicare-revalidation-list" style="display:inline-block;padding:10px 22px;background:#fff;border:1px solid #1d4ed8;color:#1d4ed8;font-weight:700;border-radius:8px;text-decoration:none;font-size:13px;">Verify on CMS.gov ↗</a>
|
||||
</td></tr></table>
|
||||
|
||||
<!-- Service fee -->
|
||||
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="margin:18px 0;"><tr><td style="background:#f8fafc;border:1px solid #e5e7eb;border-radius:10px;padding:14px 18px;">
|
||||
<table role="presentation" width="100%" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td style="font-size:13px;color:#6b7280;font-family:Inter,system-ui,sans-serif;">Our service fee to file it for you</td>
|
||||
<td style="font-size:22px;font-weight:800;text-align:right;color:#047857;font-family:Inter,system-ui,sans-serif;white-space:nowrap;">$599</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td></tr></table>
|
||||
|
||||
<!-- Convenience: no password / no login / no 2FA: we do the work, you just e-sign -->
|
||||
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="margin:18px 0;"><tr><td style="background:#f0fdfa;border:1px solid #99f6e4;border-radius:10px;padding:18px;">
|
||||
<h3 style="margin:0 0 10px;font-size:15px;color:#0f766e;font-weight:700;">No logins, no 2FA codes, no headaches</h3>
|
||||
<p style="font-size:13px;color:#134e4a;line-height:1.7;margin:0 0 10px;">We complete the entire revalidation for you and track it through to confirmation. <strong>You never share your password and you never have to log in or chase a two-factor code.</strong> The only thing we may need is a one-minute e-signature on a secure link.</p>
|
||||
<p style="font-size:13px;color:#134e4a;line-height:1.7;margin:0;">That's it. We handle the rest and keep you posted until it's confirmed.</p>
|
||||
</td></tr></table>
|
||||
|
||||
<!-- CTA -->
|
||||
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="margin:22px 0;"><tr><td style="background:#ecfdf5;border:2px solid #10b981;border-radius:10px;padding:18px;text-align:center;">
|
||||
<p style="font-size:14px;color:#065f46;margin:0 0 6px;font-weight:600;">We file your PECOS revalidation for you, well before the deadline.</p>
|
||||
<p style="font-size:12px;color:#047857;margin:0 0 14px;">Most filings submitted within 1-2 business days.</p>
|
||||
<a href="https://performancewest.net/order/npi-revalidation?npi={{ .Subscriber.Attribs.npi }}" style="display:inline-block;padding:14px 40px;background:#10b981;color:#fff;font-weight:700;border-radius:8px;text-decoration:none;font-size:15px;">Start my revalidation →</a>
|
||||
</td></tr></table>
|
||||
|
||||
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="margin:18px 0;"><tr><td style="background:#f0f4f8;border-radius:8px;padding:16px;font-size:13px;color:#374151;line-height:1.6;">
|
||||
<strong>Questions?</strong> Reply to this email or call <strong>(888) 411-0383</strong>. Performance West is a dedicated healthcare compliance firm — we handle the CMS/NPPES paperwork so you can focus on patients.
|
||||
</td></tr></table>
|
||||
|
||||
<!-- Trust signals (data-safety + guarantee — relevant when sharing provider info) -->
|
||||
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="margin:20px 0 6px;border-top:1px solid #e5e7eb;padding-top:14px;">
|
||||
<tr>
|
||||
<td align="center" style="padding:10px 4px;font-family:Inter,system-ui,sans-serif;">
|
||||
<span style="display:inline-block;margin:0 8px;font-size:11px;font-weight:600;color:#0f766e;">🛡️ SOC 2 Type II hosting</span>
|
||||
<span style="display:inline-block;margin:0 8px;font-size:11px;font-weight:600;color:#0f766e;">✅ HIPAA & PCI compliant</span>
|
||||
<span style="display:inline-block;margin:0 8px;font-size:11px;font-weight:600;color:#0f766e;">🔒 256-bit TLS encrypted</span>
|
||||
<span style="display:inline-block;margin:0 8px;font-size:11px;font-weight:600;color:#0f766e;">💳 Secure payment by Stripe</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" style="padding:4px;font-family:Inter,system-ui,sans-serif;font-size:12px;color:#4b5563;">
|
||||
<strong style="color:#047857;">100% satisfaction guarantee</strong> · fixed pricing, no billable hours · trusted by providers nationwide
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td></tr>
|
||||
|
||||
<!-- Footer -->
|
||||
<tr><td style="padding:16px 28px;background:#f8fafc;border-top:1px solid #e5e7eb;font-size:11px;color:#9ca3af;text-align:center;">
|
||||
<p style="margin:0 0 8px;">Performance West is an independent compliance firm, not affiliated with CMS or Medicare.</p>
|
||||
<p style="margin:0;">Performance West Inc. · Cheyenne, WY · <a href="https://performancewest.net" style="color:#6b7280;">performancewest.net</a></p>
|
||||
<p style="margin:6px 0 0;"><a href="{{ UnsubscribeURL }}" style="color:#6b7280;">Unsubscribe</a></p>
|
||||
</td></tr>
|
||||
|
||||
</table></td></tr></table></center></body></html>
|
||||
|
|
@ -59,6 +59,15 @@ SEGMENTS = {
|
|||
"campaign_name": "HC Warmup - Medicare Revalidation",
|
||||
"selector": "reval_overdue",
|
||||
},
|
||||
"revalidation_due_soon": {
|
||||
"subject": "Your Medicare revalidation deadline is approaching",
|
||||
"template": "hc_revalidation_due_soon.html",
|
||||
"cta_path": "/order/npi-revalidation",
|
||||
"price": "$599",
|
||||
"list_name": "HC Warmup - Revalidation Due Soon",
|
||||
"campaign_name": "HC Warmup - Revalidation Due Soon",
|
||||
"selector": "reval_due_soon",
|
||||
},
|
||||
"npi_reactivation": {
|
||||
"subject": "Your NPI / Medicare enrollment appears deactivated",
|
||||
"template": "hc_npi_reactivation.html",
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ def load_suppressed() -> set[str]:
|
|||
# without overwhelming the warming IPs.
|
||||
ACTIVE_SEGMENTS = os.getenv(
|
||||
"HC_SEGMENTS",
|
||||
"revalidation_overdue,oig_screening,nppes_outdated,npi_reactivation,compliance_bundle",
|
||||
"revalidation_overdue,revalidation_due_soon,oig_screening,nppes_outdated,npi_reactivation,compliance_bundle",
|
||||
).split(",")
|
||||
|
||||
# Warmup deliverability guard: only mail SLIGHTLY-overdue providers. A practice
|
||||
|
|
@ -84,6 +84,11 @@ ACTIVE_SEGMENTS = os.getenv(
|
|||
# warming IP's reputation. Window is inclusive [MIN, MAX] days overdue.
|
||||
WARMUP_OVERDUE_MIN = int(os.getenv("HC_OVERDUE_MIN", "1"))
|
||||
WARMUP_OVERDUE_MAX = int(os.getenv("HC_OVERDUE_MAX", "90"))
|
||||
# Proactive "revalidation due soon" window (days UNTIL the due date). Mirrors the
|
||||
# overdue window so we reach providers shortly before AND after their deadline,
|
||||
# roughly doubling the deliverable warmup pool from the same CMS data source.
|
||||
WARMUP_DUE_SOON_MIN = int(os.getenv("HC_DUE_SOON_MIN", "1"))
|
||||
WARMUP_DUE_SOON_MAX = int(os.getenv("HC_DUE_SOON_MAX", "90"))
|
||||
|
||||
|
||||
def _overdue_days(r: dict):
|
||||
|
|
@ -245,6 +250,20 @@ def row_matches(seg_key: str, r: dict) -> bool:
|
|||
return False
|
||||
od = _overdue_days(r)
|
||||
return od is not None and WARMUP_OVERDUE_MIN <= od <= WARMUP_OVERDUE_MAX
|
||||
if sel == "reval_due_soon":
|
||||
# Proactive: revalidation is UPCOMING within the lookahead window. Pitch
|
||||
# is "handle it before your deadline" -- taps the same CMS Revalidation
|
||||
# Due Date List as reval_overdue but the (much larger) not-yet-due slice,
|
||||
# so it grows warmup supply without touching a new data source.
|
||||
# days_overdue is negative for upcoming (days until due), so a provider
|
||||
# due in N days has days_overdue == -N.
|
||||
if status != "upcoming":
|
||||
return False
|
||||
od = _overdue_days(r)
|
||||
if od is None:
|
||||
return False
|
||||
days_until = -od
|
||||
return WARMUP_DUE_SOON_MIN <= days_until <= WARMUP_DUE_SOON_MAX
|
||||
if sel == "reval_upcoming": return status == "upcoming"
|
||||
if sel == "leie_or_deactivated":
|
||||
# Reactivation targets: flagged excluded, OR no longer on the reval list
|
||||
|
|
@ -265,16 +284,28 @@ def row_matches(seg_key: str, r: dict) -> bool:
|
|||
|
||||
|
||||
def attribs_for(r: dict) -> dict:
|
||||
# days_overdue is positive when past due and negative when upcoming (days
|
||||
# until the due date). Expose a clean positive "days_until" for the
|
||||
# due-soon segment's template.
|
||||
od_raw = (str(r.get("days_overdue", "")) or "").strip()
|
||||
days_until = ""
|
||||
try:
|
||||
od = int(od_raw)
|
||||
if od < 0:
|
||||
days_until = str(-od)
|
||||
except ValueError:
|
||||
pass
|
||||
return {
|
||||
"npi": r.get("npi", ""),
|
||||
"practice": r.get("name", ""),
|
||||
"specialty": r.get("specialty", ""),
|
||||
"state": r.get("state", ""),
|
||||
# Separate fields so the email's "official CMS record" card can render
|
||||
# the due date + overdue count cleanly (mirrors the CMS Revalidation Due
|
||||
# Date List, verified by NPI via the weekly hc_data_refresh).
|
||||
# the due date + overdue/until count cleanly (mirrors the CMS
|
||||
# Revalidation Due Date List, verified by NPI via the weekly refresh).
|
||||
"reval_due_date": r.get("reval_due_date", ""),
|
||||
"days_overdue": str(r.get("days_overdue", "")),
|
||||
"days_until": days_until,
|
||||
"detail": (f"{r.get('reval_due_date','')} ({r.get('days_overdue','')} days overdue)"
|
||||
if r.get("reval_status") == "overdue" else r.get("reval_due_date", "")),
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue