Companies House Integration
Companies House for UK Customers/Vendors/CompanyInfo — surface, score, alert, audit. Officer/PSC monitoring, insolvency signals, composite risk score, bulk import, change log, self-monitor.
- Current version: v0.4.0.0
- AL prefix: COMPA
- Object range: 80200-80299
- Business Central: 27.0.0.0
- Publisher: Amplio Solutions
Companies House Integration (ASCHI)
Auto-populates UK customer, vendor and own-company master data from the Companies House public REST API. Surfaces statutory filings, secured-lending charges, officers, PSCs and a composite credit-risk score on the FactBox; raises notifications when counterparties drift into distress; and keeps an append-only audit trail of every detected change.
- Publisher: Amplio Solutions
- App version: 0.4.0.0
- Target: Business Central 26.x (Cloud / OnPrem), Country = GB
- Object prefix:
ASCHI - ID range: 80200–80299
What it does
- Lookup + refresh on Customer Card, Vendor Card and Company Information.
- FactBox rendering CH status, statutory filings, distress signals, risk score, and the Officer + PSC list parts on every parent record.
- Daily Job Queue sweep that re-pulls profile + officers + PSCs + charges + filings + risk score for stale records, writes change-log entries for every detected change, raises notifications, and (if enabled) self-monitors the company's own filings.
- Bulk import wizard for onboarding many customers/vendors from a CSV.
- Setup page holds API credentials (key in Isolated Storage), refresh schedule, self-monitor configuration, and entry points to the Risk Weights, Change Log, and Bulk Import Jobs pages.
What v0.3.0.0 adds
1. Officer + PSC change monitoring
- New tables
ASCHI Officer(80224) andASCHI PSC(80225) — one-to-many to Customer / Vendor / Company Information via (Linked Table No, Linked PK). Append-only: rows are never deleted, only the resigned-date / ceased-date columns flip when CH reports a transition. - Two new API client methods (
GetCompanyOfficers/GetCompanyPSCs) hit/company/{number}/officersand/company/{number}/persons-with-significant-control. RefreshFromCHnow syncs both into the new tables, dedupes by CH's officer-id / psc-id (with a stable name+date fallback), and emits Change Log entries for every appointment / resignation / notification / cessation.- Notifications fire when officers are appointed, resign, or PSCs cease — gated by the new
Officer/PSC Notify Enabledsetup flag so chatty boards don't spam credit control. - FactBox grows two list-part panels rendering the parent's officers and PSCs; rows that resigned / ceased in the last 90 days render red.
2. Insolvency + financial-distress signals
- New API client methods
GetCompanyChargesandGetCompanyFilingHistoryhit/chargesand/filing-history. - New fields on Customer + Vendor + Company Information:
| Field id | Field | Source |
|---|---|---|
| 80224 | ASCHI Outstanding Charges |
Count of /charges items where status='outstanding'. |
| 80225 | ASCHI Charges Last Filed |
Most recent created_on across all charges. |
| 80226 | ASCHI In Liquidation |
True when company_status='liquidation' (or status_detail indicates winding-up). |
| 80227 | ASCHI Strike-Off Active |
True when filing history has an active gazetted strike-off in the last 90d. |
| 80228 | ASCHI Distress Reason |
One-line summary of triggered distress flags (comma-joined). |
- Any of the four boolean flags transitioning false → true emits a Change Log entry and a high-priority notification (gated by the new
Distress Notify Enabledsetup flag).
3. Composite risk score (0–100)
- New singleton config table
ASCHI Risk Weights(80226) — defaults: Dissolved/Liquidation=100, Strike-Off Active=80, Accounts Overdue=30, Conf Stmt Overdue=20, Dormant=25, charges 5/each (cap 30), director resignations 10/each (cap 30), recent office change=10. Score floor=0, cap=100. - New setup page
ASCHI Risk Weights Setup(80227) — single-row card with all weights, tooltips, and a Restore defaults action. - New codeunit
ASCHI Risk Score Calc(80228) — pure functionCalculateScore(sourceTableNo, sourceKey)over the parent record + its officers + PSCs + cached distress flags. Deterministic; same input ⇒ same output. - New fields on Customer + Vendor + Company Information:
| Field id | Field | Notes |
|---|---|---|
| 80229 | ASCHI Risk Score |
Integer 0..100. Recomputed on each refresh. |
| 80230 | ASCHI Risk Score Calc At |
DateTime stamp of last computation. |
| 80231 | ASCHI Risk Score Reasons |
Comma-joined list of triggered weights for explainability. |
- FactBox surfaces the score at the top — green 0–25, amber 26–60, red 61–100.
- Customer List + Vendor List get a hidden-by-default
CH Risk Scorecolumn. Finance teams turn it on via personalisation, then filterRisk Score >= 60to find every high-risk record.
4. Bulk import wizard
- New tables
ASCHI Import Job(80229) andASCHI Import Job Line(80230). Lines hold the source key, search term, status, up to three candidate matches per row with a 0–100 confidence score. - New page
ASCHI Bulk Import Wizard(80231) — a four-stepNavigatePage:- Pick target — Customer or Vendor.
- Upload a CSV (cols: customerno/vendorno, search_term — header row optional).
- Preview matches — opens the Job Lines page modal so the user can pick the right candidate per row, or skip a row.
- Confirm + apply — writes CH numbers and calls
RefreshFromCHon each line.
- Direct CH-number rows (8-char alphanumeric or padded numeric) hit
/company/{number}directly; free-text rows go through/search/companies?q=with a heuristic name-similarity score. - Auto-pick: if exactly one candidate has score ≥ 90, the line is auto-MATCHED.
- New page
ASCHI Import Jobs List(80232) — history of imports with drill-down to lines. - Customer List + Vendor List grow a "Companies House Bulk Import" action that launches the wizard.
5. Audit trail / change log
- New table
ASCHI Change Log(80233) — append-only. Each row: source table+key, CH number, field name, change type (ADDED / MODIFIED / REMOVED / THRESHOLD_CROSSED), old/new values, detected-at, refresh job id (per-sweep correlation), detected-by user. - The refresh codeunit emits entries for: status flips, registered-office changes, officer additions/resignations, PSC notifications/cessations, charge additions, risk-score crossings (only when the delta exceeds
Setup."Risk Score Change Threshold", default ±10), and the rising edges of the four overdue/distress booleans. - New page
ASCHI Change Log List(80234) — sortable / filterable list. THRESHOLD_CROSSED rows render red; REMOVED rows render amber. - "View CH Change Log" action on Customer Card, Vendor Card, Customer List, Vendor List filters the log to the relevant scope.
- Retention is configurable via
Setup."Change Log Retention Days"(default 0 = keep forever); applied at the end of each sweep byASCHI Change Log Writer.RunRetention.
Company Information (self-monitor)
- New table extension on table 79 mirrors every CH field added to Customer + Vendor.
- New page extension on page 1 surfaces a "Statutory Filings & Risk (self-monitor)" group, a
CH self-monitor FactBox(80239), and a "Refresh CH self-monitor" action. - Refresh resolves the CH number from
Setup."Self-Monitor Override CH No."(preferred) →Company Information."Registration No.", then runs the full v0.3 refresh pipeline against the singleton row. - The daily sweep refreshes Company Information whenever
Enable Self-Monitoris on, regardless of the staleness window — one record, runs daily. - Notifications fire to
Setup."Self-Monitor Recipient"(or the session user if blank).
ID allocation (80200–80299)
| Range | Used for |
|---|---|
| 80200, 80201 | Tables: Setup, Search Result |
| 80210, 80211 | Table extensions: Customer, Vendor |
| 80220–80223 | Pages: Setup, Search Results, Customer FactBox, Vendor FactBox |
| 80224, 80225 | Tables: Officer, PSC (v0.3) |
| 80226 | Table: Risk Weights (v0.3) |
| 80227 | Page: Risk Weights Setup (v0.3) |
| 80228 | Codeunit: Risk Score Calc (v0.3) |
| 80229, 80230 | Tables: Import Job, Import Job Line (v0.3) |
| 80230, 80231 | Page extensions: Customer Card, Vendor Card |
| 80231 | Page: Bulk Import Wizard (v0.3) |
| 80232 | Page: Import Jobs List (v0.3) |
| 80233 | Table: Change Log (v0.3) |
| 80234 | Page: Change Log List (v0.3) |
| 80235 | Table extension: Company Information (v0.3) |
| 80236 | Page extension: Company Information (v0.3) |
| 80237, 80238 | Pages: Officer List Part, PSC List Part (v0.3) |
| 80239 | Page: CH Company Info FactBox (v0.3) |
| 80240–80246 | Codeunits: API Client, Lookup Mgt, Refresh JQ, Install, Change Log Writer, Bulk Import Mgt, Officer/PSC Sync |
| 80247, 80248 | Pages: Officer List, PSC List (full / drilldown) |
| 80246 | Page: Import Job Lines (drilldown) |
| 80248, 80249 | Page extensions: Customer List, Vendor List (v0.3) |
| 80250 | Permission set: Admin |
Page IDs 80230 / 80231 collide-by-number with page extensions 80230 / 80231 — different object types so AL accepts them. We could renumber for visual cleanliness but that would force consumers of the extension to re-test the existing page-extension IDs.
Install / configure
- Publish the extension to your sandbox or production tenant.
- Register a Companies House API key at https://developer.company-information.service.gov.uk/get-started.
- Open Companies House Setup.
- Paste the key into the masked API Key field (held in Isolated Storage).
- Click Test Connection.
- Toggle Auto Refresh Enabled, set Refresh Frequency (Days) (default 7), pick the notify flags you want.
- v0.3 self-monitor: open the Self-monitor group, toggle Enable Self-Monitor, set Self-Monitor Recipient (User Name) for who receives overdue notifications, optionally set the Override CH Number.
- v0.3 risk score: open Risk Score Weights (action on the Setup page promoted bar). Tune to your risk appetite, or click Restore defaults.
- v0.3 retention: optionally set
Change Log Retention Daysif you don't want unbounded log growth. - Provision the Job Queue entry —
Codeunit 80242 "ASCHI Refresh JQ", daily, e.g. 02:00. - Assign the permission set
ASCHI Adminto:- Users who curate Customer/Vendor master data.
- The Job Queue user account that runs the daily sweep.
ASCHI Admindoes not grant rights on Customer, Vendor, Company Information, or Job Queue Entry. Those should already be granted via the user's existing role (e.g.D365 BUS PREMIUM).
Upgrade from v0.2.0.0
No data migration required — every v0.3 field is additive on the existing extensions. After publishing v0.3:
- Open Companies House Setup. The new sections (
Self-monitor,Risk score & change log) appear with sensible defaults. - The Risk Weights singleton is auto-seeded with default weights on
OnInstallAppPerCompany. If you publish via AppSource without triggering install (rare), it auto-seeds the first time the Setup page or a refresh reads it. - Run a manual
Refresh Now(Setup page → Run Refresh Now). Each customer/vendor + company info will re-fetch and populate the new fields. - Optionally personalise the Customer / Vendor list to show the CH Risk Score column.
Manual test plan (extended)
The v0.2 scenarios still apply (active company, recently-incorporated company, forced overdue transition, notification idempotency). v0.3 adds the following:
- Officer change. Look up SIR ROBERT MCALPINE LIMITED (
00006245) on a Customer record, run Refresh from CH. Confirm the Officers list-part populates. Manually edit one row'sResigned Dateto today (via the full Officer List page or page inspection), then refresh again — the row stays (append-only) but the new Resigned Date is preserved. A change-log row should record the resignation. A "director resignation" notification should fire — gated byOfficer/PSC Notify Enabled. - Insolvency. Pick a known-recently-dissolved or in-liquidation company (search "in liquidation" via CH). Apply it to a test Customer. Run Refresh. Expect:
In Liquidation = TRUE, distress reason populated, risk score jumps to 100. A high-priority notification fires. A change-log entry recordsIn Liquidation: false → truewithChange Type = MODIFIED. - Risk score. Open CH Risk Score Weights, change
Outstanding Charge Weightfrom 5 to 10. Run Refresh against a customer with 3 outstanding charges and an overdue confirmation statement. Expect score = 30 (charges, capped) + 20 (conf stmt) = 50. Reasons string lists "Outstanding Charges (3) +30, Confirmation Stmt Overdue +20". Restore defaults and re-refresh — score returns to 35. - Bulk import. Prepare a 10-row CSV: 5 valid CH numbers, 3 ambiguous names ("Acme Ltd"), 2 deliberately wrong. Open Customer List → Companies House Bulk Import. Walk Steps 1–4. Expect: 5 auto-MATCHED, 3 MULTIPLEMATCHES (pick or skip in the lines page), 2 NOMATCH. After Finish, the 5 matched customers have CH metadata populated, and 8/10 success on the Job Header.
- Change log. With no recent changes, run Refresh on a stable record — change log should remain empty. In the BC Customer table, manually edit the cached
ASCHI Company Statusto a different value (via page inspection / a dev test), then run Refresh — the next refresh sees the discrepancy and writes a status-change row. - Self-monitor. On Company Information, populate
Registration No.with a valid CH number (e.g. your own company). Open Setup, confirmEnable Self-Monitor = TRUEand pick aSelf-Monitor Recipient. Run Run Refresh Now. Expect Company Information to populate with CH metadata + risk score; subsequent overdue transitions raise notifications addressed to the configured user.
Stubs & TODOs left in code
ASCHI API Client.InvokeGet— 429 surfaces as an error; v1 should honourRetry-After.ASCHI API Client.UriEncode— non-ASCII behaviour unverified.ASCHI Lookup Mgt.IsLiquidationStatus— currently checkscompany_status = 'liquidation'. CH'sstatus_detail(winding-up, in-administration) is not yet exposed by the API client; OR-in here when it is.ASCHI Officer PSC Sync.ComputeChargeAggregates— does NOT yet emit a "new charge filed" change-log row when MostRecentFiled advances. Needed for v1 KYC overlay.ASCHI Risk Score Calc.RegisteredOfficeChangedRecently— relies on Change Log having a row. First-ever refresh of a fresh record never trips this signal (correct behaviour, but worth flagging for testers).ASCHI Bulk Import Mgt.ScheduleApply— still inline-synchronous. v1 should drop a Job Queue Entry so large CSV imports don't block the wizard.ASCHI Refresh JQ.SafeRefreshCustomer/Vendor— has the existing commented Sleep(50). v0.3 issues 5 calls per record (profile + officers + PSCs + charges + filing-history); a tenant with 1000 customers is well inside the CH 600/5min ceiling but a 10k-customer tenant should add the soft brake.- Job Queue dependency for v0.2 overdue notifications — the same caveat applies to all v0.3 transition notifications: they fire only when the daily refresh runs against the record. There is no separate scheduler.
What Lee still needs to ship
- Production CH API key.
- Tune the refresh schedule for the largest tenants (5 calls per record × 1000+ records may bite the ceiling).
- Decide CH-vs-curated-data overwrite policy — still v0.1 behaviour: we don't auto-merge Name/Address from CH onto the standard fields.
- Consider Teams / email notification channels for the rising-edge alerts (currently in-client only).
- Add structured telemetry (
Session.LogMessage) for refresh outcomes + risk-score deltas. - Sibling AL test app with mocked HTTP fixtures so the JSON parsing has regression coverage.
Source layout
08-Companies-House-Integration/
app.json
README.md
src/
Tables/
ASCHISetup.Table.al
ASCHISearchResult.Table.al
ASCHIOfficer.Table.al (v0.3)
ASCHIPSC.Table.al (v0.3)
ASCHIRiskWeights.Table.al (v0.3)
ASCHIImportJob.Table.al (v0.3)
ASCHIImportJobLine.Table.al (v0.3)
ASCHIChangeLog.Table.al (v0.3)
TableExtensions/
ASCHICustomer.TableExt.al
ASCHIVendor.TableExt.al
ASCHICompanyInfo.TableExt.al (v0.3)
Pages/
ASCHISetup.Page.al
ASCHISearchResults.Page.al
ASCHICustomerFactBox.Page.al
ASCHIVendorFactBox.Page.al
ASCHIRiskWeightsSetup.Page.al (v0.3)
ASCHIBulkImportWizard.Page.al (v0.3)
ASCHIImportJobsList.Page.al (v0.3)
ASCHIImportJobLines.Page.al (v0.3)
ASCHIChangeLogList.Page.al (v0.3)
ASCHIOfficerListPart.Page.al (v0.3)
ASCHIOfficerList.Page.al (v0.3)
ASCHIPSCListPart.Page.al (v0.3)
ASCHIPSCList.Page.al (v0.3)
ASCHICompanyInfoFactBox.Page.al (v0.3)
PageExtensions/
ASCHICustomerCard.PageExt.al
ASCHIVendorCard.PageExt.al
ASCHICompanyInfo.PageExt.al (v0.3)
ASCHICustomerList.PageExt.al (v0.3)
ASCHIVendorList.PageExt.al (v0.3)
Codeunits/
ASCHIAPIClient.Codeunit.al
ASCHILookupMgt.Codeunit.al
ASCHIRefreshJQ.Codeunit.al
ASCHIInstall.Codeunit.al
ASCHIRiskScoreCalc.Codeunit.al (v0.3)
ASCHIChangeLogWriter.Codeunit.al (v0.3)
ASCHIBulkImportMgt.Codeunit.al (v0.3)
ASCHIOfficerPSCSync.Codeunit.al (v0.3)
PermissionSets/
ASCHIAdmin.PermissionSet.al