-
Notifications
You must be signed in to change notification settings - Fork 0
feat(nw-registered-agent): emit annualFeeUsd for ChittyFinance cost flow #21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: feat/governance-scrapers
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,6 +18,39 @@ export interface NWAgentResult { | |
| mailForwardingStatus?: string; | ||
| paymentStatus?: string; | ||
| alerts: string[]; | ||
| /** | ||
| * Annual registered-agent fee in USD, parsed from the account/billing page | ||
| * when the portal surfaces it. Undefined when no fee is shown (e.g. the | ||
| * inbox view carries no billing total) — consumers that book a cost MUST | ||
| * treat absence as "amount unknown", never as $0. This is the monetary | ||
| * field ChittyFinance's vendor-charge ingest consumes. | ||
| */ | ||
| annualFeeUsd?: number; | ||
| } | ||
|
|
||
| /** | ||
| * Parse a registered-agent annual fee from portal page text. | ||
| * | ||
| * Northwest's billing/account pages render the renewal cost near phrases like | ||
| * "Registered Agent", "Annual Fee", "Renewal", or "Service Fee" followed by a | ||
| * dollar amount. We scan for those anchors and return the nearest USD figure. | ||
| * Returns undefined when nothing matches — the caller must not default to 0. | ||
| */ | ||
| export function parseAnnualFee(text: string): number | undefined { | ||
| if (!text) return undefined; | ||
| const anchors = /(registered\s+agent|annual\s+fee|renewal|service\s+fee|yearly)/i; | ||
| // $amount allowing thousands separators and optional cents. | ||
| const money = /\$\s?([0-9]{1,3}(?:,[0-9]{3})*(?:\.[0-9]{2})?|[0-9]+(?:\.[0-9]{2})?)/; | ||
| for (const rawLine of text.split(/\n|\.|;/)) { | ||
|
Comment on lines
+43
to
+44
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When the portal shows an uncommaed four-digit fee or a fee with cents, this parser can emit a smaller amount than shown: the first regex alternative matches only the prefix of Useful? React with 👍 / 👎. |
||
| const line = rawLine.trim(); | ||
| if (!anchors.test(line)) continue; | ||
| const m = line.match(money); | ||
|
Comment on lines
+44
to
+47
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This only checks for a dollar amount on the same split segment as the anchor, so common billing layouts such as a table/card with Useful? React with 👍 / 👎. |
||
| if (m) { | ||
| const val = parseFloat(m[1].replace(/,/g, '')); | ||
| if (Number.isFinite(val) && val > 0) return val; | ||
| } | ||
| } | ||
| return undefined; | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -294,6 +327,10 @@ async function scrapeNWRegisteredAgent( | |
|
|
||
| const alerts = accountData?.alerts || []; | ||
|
|
||
| // Best-effort parse of the annual fee from the account page text. Undefined | ||
| // when the portal view shows no fee — never coerced to 0. | ||
| const annualFeeUsd = parseAnnualFee(accountData?.bodySnippet || ''); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This calls the fee parser on Useful? React with 👍 / 👎. |
||
|
|
||
| return { | ||
| success: true, | ||
| data: { | ||
|
|
@@ -302,6 +339,7 @@ async function scrapeNWRegisteredAgent( | |
| documents, | ||
| paymentStatus: alerts.includes('PAYMENT_FAILED') ? 'failed' : 'ok', | ||
| alerts, | ||
| annualFeeUsd, | ||
| }, | ||
| }; | ||
| } catch (err: any) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because
renewalby itself is treated as a fee anchor, any dashboard line such as an annual-report renewal or other renewal notice with a$amount will be returned asannualFeeUsdbefore a later registered-agent charge is considered. In accounts with annual report reminders or multiple renewal notices, this can book the wrong vendor-charge amount; the match needs to be scoped to registered-agent/service-fee billing text instead of any renewal line.Useful? React with 👍 / 👎.