@alvera-ai/platform-sdk 0.17.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agent/AGENTS.md +82 -144
- package/.agent/account_management.md +2 -2
- package/.agent/action_logs.md +4 -4
- package/.agent/ai_agents.md +28 -21
- package/.agent/ai_sandbox.md +49 -39
- package/.agent/connected_apps.md +3 -3
- package/.agent/cookbook/_fixtures/README.md +1 -1
- package/.agent/cookbook/_fixtures/{foundation → organic-marketing}/_lead_submissions_foundation_generic_table.liquid +1 -1
- package/.agent/cookbook/_fixtures/organic-marketing/_lead_submissions_foundation_legal_entity.liquid +80 -0
- package/.agent/cookbook/_fixtures/{foundation → organic-marketing}/_lead_submissions_foundation_mdm.liquid +2 -1
- package/.agent/cookbook/_fixtures/payments-compliance/_compliance_screenings_generic_table.liquid +57 -0
- package/.agent/cookbook/_fixtures/payments-compliance/_compliance_screenings_legal_entity.liquid +30 -0
- package/.agent/cookbook/_fixtures/payments-compliance/_compliance_screenings_mdm.liquid +44 -0
- package/.agent/cookbook/_fixtures/payments-compliance/_payment_accounts_generic_table.liquid +57 -0
- package/.agent/cookbook/_fixtures/payments-compliance/_payment_accounts_legal_entity.liquid +36 -0
- package/.agent/cookbook/_fixtures/payments-compliance/_payment_accounts_mdm.liquid +41 -0
- package/.agent/cookbook/_fixtures/primary-care-feedback/_cahps_appointments_generic_table.liquid +70 -0
- package/.agent/cookbook/_fixtures/primary-care-feedback/_cahps_appointments_legal_entity.liquid +52 -0
- package/.agent/cookbook/_fixtures/primary-care-feedback/_cahps_appointments_mdm.liquid +42 -0
- package/.agent/cookbook/_fixtures/subscription-saas/_customers_subscription_generic_table.liquid +38 -0
- package/.agent/cookbook/_fixtures/subscription-saas/_customers_subscription_legal_entity.liquid +48 -0
- package/.agent/cookbook/_fixtures/subscription-saas/_customers_subscription_mdm.liquid +49 -0
- package/.agent/cookbook/organic-marketing.md +2801 -0
- package/.agent/cookbook/payments-compliance.md +2180 -0
- package/.agent/cookbook/primary-care.md +2175 -0
- package/.agent/cookbook/subscription-saas.md +2403 -0
- package/.agent/data_activation_clients.md +65 -52
- package/.agent/datalakes.md +338 -171
- package/.agent/errors.md +3 -3
- package/.agent/generic_tables.md +151 -62
- package/.agent/interoperability_contracts.md +57 -22
- package/.agent/mdm.md +136 -153
- package/.agent/messages.md +36 -34
- package/.agent/mock-services.md +1 -1
- package/.agent/mutations.md +2 -2
- package/.agent/templates.md +14 -13
- package/.agent/tools.md +63 -21
- package/.agent/type_naming.md +13 -13
- package/.agent/workflows.md +99 -53
- package/README.md +2 -2
- package/dist/bin/platform-sdk.mjs +33 -47
- package/dist/bin/platform-sdk.mjs.map +1 -1
- package/dist/index.d.mts +565 -379
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +494 -59
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -3
- package/.agent/cookbook/_fixtures/foundation/_lead_submissions_foundation_legal_entity.liquid +0 -88
- package/.agent/cookbook/_fixtures/healthcare/_cahps_appointments_healthcare_appointment.liquid +0 -47
- package/.agent/cookbook/_fixtures/healthcare/_cahps_appointments_healthcare_mdm.liquid +0 -24
- package/.agent/cookbook/_fixtures/healthcare/_cahps_appointments_healthcare_patient.liquid +0 -38
- package/.agent/cookbook/_fixtures/payments/_compliance_screenings_payments_compliance_screening.liquid +0 -59
- package/.agent/cookbook/_fixtures/payments/_compliance_screenings_payments_mdm.liquid +0 -36
- package/.agent/cookbook/_fixtures/payments/_payment_accounts_payments_mdm.liquid +0 -30
- package/.agent/cookbook/_fixtures/payments/_payment_accounts_payments_payment_account.liquid +0 -55
- package/.agent/cookbook/_fixtures/subscription/_customers_subscription_mdm.liquid +0 -20
- package/.agent/cookbook/_setup/foundation.md +0 -359
- package/.agent/cookbook/_setup/healthcare.md +0 -361
- package/.agent/cookbook/_setup/payments.md +0 -365
- package/.agent/cookbook/_setup/subscription.md +0 -364
- package/.agent/cookbook/action-status-updaters.md +0 -278
- package/.agent/cookbook/ai-agent-invoke.md +0 -279
- package/.agent/cookbook/appointment-review-sms-workflow.md +0 -801
- package/.agent/cookbook/birthday-greeting-sms-trigger.md +0 -696
- package/.agent/cookbook/bulk-ingest.md +0 -302
- package/.agent/cookbook/contact-us-triage-with-llm.md +0 -663
- package/.agent/cookbook/dunning-sms-for-delinquent.md +0 -659
- package/.agent/cookbook/generic-tables.md +0 -244
- package/.agent/cookbook/invite-team.md +0 -200
- package/.agent/cookbook/kyc-notification-on-account-activation.md +0 -661
- package/.agent/cookbook/marketing-campaign-send.md +0 -1044
- package/.agent/cookbook/paginated-restapi-poller.md +0 -383
- package/.agent/cookbook/rest-fetch.md +0 -273
- package/.agent/cookbook/sanctions-screening-with-agent-review.md +0 -773
- package/.agent/cookbook/score-leads-with-llm-categorization.md +0 -665
- package/.agent/cookbook/system-templates.md +0 -165
- package/.agent/cookbook/talk-to-data.md +0 -178
- package/.agent/cookbook/triage-prospects-by-priority.md +0 -571
- package/.agent/cookbook/welcome-sms-for-customers.md +0 -647
- /package/.agent/cookbook/_fixtures/{healthcare → primary-care-feedback}/memorandum-of-association-01.png +0 -0
- /package/.agent/cookbook/_fixtures/{healthcare → primary-care-feedback}/sample_two_page.pdf +0 -0
- /package/.agent/cookbook/_fixtures/{subscription → subscription-saas}/_customers_subscription_customer.liquid +0 -0
- /package/.agent/cookbook/_fixtures/{subscription → subscription-saas}/stripe_customers_batch1.csv +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alvera-ai/platform-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "Typed SDK for the Alvera platform API — manage data sources, tools, generic tables, AI agents, and action status updaters.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -31,11 +31,12 @@
|
|
|
31
31
|
"codegen": "openapi-ts && tsx scripts/patch-generated.ts",
|
|
32
32
|
"regen": "bun run fetch-metadata && bun run gen-environments && bun run codegen",
|
|
33
33
|
"build": "tsdown",
|
|
34
|
-
"test": "bun test
|
|
34
|
+
"test": "bun test",
|
|
35
35
|
"test:contract": "bun test test/contract.test.ts",
|
|
36
36
|
"test:prism-surface": "bun test test/prism-surface.test.ts",
|
|
37
37
|
"validate:cookbook": "tsx scripts/cookbook-doctest/run.ts",
|
|
38
|
-
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.test.json && tsc --noEmit -p scripts/tsconfig.json",
|
|
38
|
+
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.test.json && tsc --noEmit -p scripts/tsconfig.json && bun run typecheck:guides",
|
|
39
|
+
"typecheck:guides": "tsx scripts/type-gate.ts",
|
|
39
40
|
"clean": "rm -rf dist src/generated src/environments.generated.ts .cookbook-doctest .agent",
|
|
40
41
|
"sync-agent-corpus": "tsx scripts/sync-agent-corpus.ts",
|
|
41
42
|
"prepack": "bun run sync-agent-corpus",
|
package/.agent/cookbook/_fixtures/foundation/_lead_submissions_foundation_legal_entity.liquid
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
{% comment %}
|
|
2
|
-
Foundation Airflow Lead Form → Foundation LegalEntity attrs.
|
|
3
|
-
|
|
4
|
-
Maps a single Google-Sheet lead row into a Foundation
|
|
5
|
-
`LegalEntity` upsert payload. Used by Contract A
|
|
6
|
-
(`resource_type: "legal_entity"`, `mdm_input_type: :null`) — Contract A
|
|
7
|
-
writes the LE directly because the row IS the MDM subject for Foundation.
|
|
8
|
-
Identifier-based dedupe in `Foundation.LegalEntities.upsert_legal_entity`
|
|
9
|
-
collapses repeat submissions sharing the same digital_identifier
|
|
10
|
-
(verified email) onto a single LE row.
|
|
11
|
-
|
|
12
|
-
## Branches
|
|
13
|
-
* `legal_entity_type: "individual"` when `company` is empty
|
|
14
|
-
* `legal_entity_type: "business"` when `company` is non-empty
|
|
15
|
-
(the company name becomes `business_name` and the submitter's name
|
|
16
|
-
is dropped — businesses don't carry first/last on the LE row)
|
|
17
|
-
|
|
18
|
-
## Identifications
|
|
19
|
-
* One identification per row: `id_type: "digital_identifier"`,
|
|
20
|
-
`uri: <p.source_uri>` — the verifying platform's URI, which DAC
|
|
21
|
-
injects from the configured `data_source.uri` (e.g. the Airflow
|
|
22
|
-
form's host). `id_number: <email>`. Same triple is emitted on the
|
|
23
|
-
regulated nested attrs so the raw plaintext id_number lives on the
|
|
24
|
-
regulated mirror
|
|
25
|
-
(`Foundation.LegalEntities.find_legal_entity_by_identifications/2`
|
|
26
|
-
queries the regulated table — public id_number is tokenized).
|
|
27
|
-
{% endcomment %}
|
|
28
|
-
{% assign p = msg %}
|
|
29
|
-
{% assign le_type = "individual" %}
|
|
30
|
-
{% if p.company and p.company != "" %}{% assign le_type = "business" %}{% endif %}
|
|
31
|
-
{% assign name_parts = p.name | default: "" | split: " " %}
|
|
32
|
-
{% assign first_name = name_parts[0] | default: "" %}
|
|
33
|
-
{% assign last_name_parts = name_parts | slice: 1, 9 %}
|
|
34
|
-
{% assign last_name = last_name_parts | join: " " %}
|
|
35
|
-
{
|
|
36
|
-
"legal_entity_type": "{{ le_type }}",
|
|
37
|
-
"role": "direct",
|
|
38
|
-
{% if le_type == "business" %}"business_name": "{{ p.company | json_escape }}",{% endif %}
|
|
39
|
-
{% if le_type == "individual" and first_name != "" %}"first_name": "{{ first_name | json_escape }}",{% endif %}
|
|
40
|
-
{% if le_type == "individual" and last_name != "" %}"last_name": "{{ last_name | json_escape }}",{% endif %}
|
|
41
|
-
{% comment %}
|
|
42
|
-
Optional date_of_birth + phone_numbers — emitted at the TOP LEVEL
|
|
43
|
-
because `Platform.Foundation.LegalEntities.upsert_legal_entity/5`
|
|
44
|
-
feeds the SAME flat attrs map to both the public and the
|
|
45
|
-
regulated half's changeset (see the @doc above the function: "Both
|
|
46
|
-
halves consume the same flat `attrs` map — column names are
|
|
47
|
-
identical on the public and regulated schemas, so each side's
|
|
48
|
-
changeset reads the same keys"). Nesting these inside the
|
|
49
|
-
`regulated_legal_entity` block here would render them invisible
|
|
50
|
-
to the upsert (the regulated changeset reads `:date_of_birth` and
|
|
51
|
-
`:phone_numbers` from the flat top-level, not from a nested
|
|
52
|
-
object). The public LegalEntity schema does not declare
|
|
53
|
-
`:date_of_birth` or `has_many :phone_numbers`, so the public
|
|
54
|
-
changeset silently drops them; only the regulated mirror picks
|
|
55
|
-
them up.
|
|
56
|
-
|
|
57
|
-
`date_of_birth` is rendered as ISO 8601 YYYY-MM-DD; if the CSV
|
|
58
|
-
column is absent, the {% if %} guard renders nothing and the
|
|
59
|
-
regulated mirror's :date_of_birth stays nil.
|
|
60
|
-
|
|
61
|
-
`phone_numbers` renders as a single-element list — matches the
|
|
62
|
-
one-phone-per-lead shape of inbound lead-capture forms. Absent
|
|
63
|
-
column leaves the has_many empty.
|
|
64
|
-
{% endcomment %}
|
|
65
|
-
{% if p.date_of_birth and p.date_of_birth != "" %}"date_of_birth": "{{ p.date_of_birth | json_escape }}",{% endif %}
|
|
66
|
-
{% if p.phone and p.phone != "" %}"phone_numbers": [{ "phone_number": "{{ p.phone | json_escape }}" }],{% endif %}
|
|
67
|
-
"identifications": [
|
|
68
|
-
{
|
|
69
|
-
"id_type": "digital_identifier",
|
|
70
|
-
"uri": "{{ p.source_uri | json_escape }}",
|
|
71
|
-
"id_number": "{{ p.email | json_escape }}"
|
|
72
|
-
}
|
|
73
|
-
],
|
|
74
|
-
"regulated_legal_entity": {
|
|
75
|
-
"legal_entity_type": "{{ le_type }}",
|
|
76
|
-
"role": "direct",
|
|
77
|
-
{% if le_type == "business" %}"business_name": "{{ p.company | json_escape }}",{% endif %}
|
|
78
|
-
{% if le_type == "individual" and first_name != "" %}"first_name": "{{ first_name | json_escape }}",{% endif %}
|
|
79
|
-
{% if le_type == "individual" and last_name != "" %}"last_name": "{{ last_name | json_escape }}",{% endif %}
|
|
80
|
-
"identifications": [
|
|
81
|
-
{
|
|
82
|
-
"id_type": "digital_identifier",
|
|
83
|
-
"uri": "{{ p.source_uri | json_escape }}",
|
|
84
|
-
"id_number": "{{ p.email | json_escape }}"
|
|
85
|
-
}
|
|
86
|
-
]
|
|
87
|
-
}
|
|
88
|
-
}
|
package/.agent/cookbook/_fixtures/healthcare/_cahps_appointments_healthcare_appointment.liquid
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
{% comment %}CAHPS Appointments → FHIR R4 Appointment attrs{% endcomment %}
|
|
2
|
-
{% comment %}Parent appointment filtering is handled by filter_template{% endcomment %}
|
|
3
|
-
{% assign a = msg %}
|
|
4
|
-
{
|
|
5
|
-
{% if a.appt_slot_status %}
|
|
6
|
-
{% assign raw_status = a.appt_slot_status | downcase | strip %}
|
|
7
|
-
{% if raw_status == "2 - checked in" %}
|
|
8
|
-
"status": "arrived"
|
|
9
|
-
{% elsif raw_status == "3 - checked out" or raw_status == "4 - charge entered" %}
|
|
10
|
-
"status": "fulfilled"
|
|
11
|
-
{% elsif raw_status == "f - filled" %}
|
|
12
|
-
"status": "booked"
|
|
13
|
-
{% elsif raw_status == "o - open slot" %}
|
|
14
|
-
"status": "pending"
|
|
15
|
-
{% elsif raw_status == "x - cancelled" %}
|
|
16
|
-
"status": "cancelled"
|
|
17
|
-
{% endif %}
|
|
18
|
-
{% endif %},
|
|
19
|
-
{% if a.appt_date %}"start": "{{ a.appt_date | parse_date: "{M}/{D}/{YYYY}" }}{% if a.appt_start_time %}T{{ a.appt_start_time | convert_time: "{h12}:{m} {am}" }}{% endif %}{{ a.timezone | tz_offset }}",{% endif %}
|
|
20
|
-
{% if a.appt_slot_duration and a.appt_slot_duration != "" %}"minutes_duration": {{ a.appt_slot_duration }},{% endif %}
|
|
21
|
-
{% if a.appt_type and a.appt_type != "" %}"description": "{{ a.appt_type }}",{% endif %}
|
|
22
|
-
"identifier": [
|
|
23
|
-
{
|
|
24
|
-
"system": "urn:{{ a.source_uri }}:appointment-id",
|
|
25
|
-
"value": "{{ a.appointment_id | default: "" }}"
|
|
26
|
-
}
|
|
27
|
-
],
|
|
28
|
-
"participants": [
|
|
29
|
-
{% if a.svc_department and a.svc_department != "" %}
|
|
30
|
-
{
|
|
31
|
-
"actor_type": "location",
|
|
32
|
-
"actor_id": "{{ a.svc_department }}",
|
|
33
|
-
"required": "required",
|
|
34
|
-
"status": "accepted"
|
|
35
|
-
}{% if a.rndrng_provider_id and a.rndrng_provider_id != "" %},{% endif %}
|
|
36
|
-
{% endif %}
|
|
37
|
-
{% if a.rndrng_provider_id and a.rndrng_provider_id != "" %}
|
|
38
|
-
{
|
|
39
|
-
"actor_type": "practitioner",
|
|
40
|
-
"actor_id": "{{ a.rndrng_provider_id }}",
|
|
41
|
-
"required": "required",
|
|
42
|
-
"status": "accepted"
|
|
43
|
-
}
|
|
44
|
-
{% endif %}
|
|
45
|
-
],
|
|
46
|
-
"source_uri": "{{ a.source_uri | default: "" }}"
|
|
47
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
{% comment %}CAHPS Appointments → Healthcare MDM Input{% endcomment %}
|
|
2
|
-
{% assign p = msg %}
|
|
3
|
-
{
|
|
4
|
-
"identifiers": [
|
|
5
|
-
{
|
|
6
|
-
"system": "urn:{{ p.source_uri }}:patient-id",
|
|
7
|
-
"value": "{{ p.patient_id }}"
|
|
8
|
-
}{% if p.enterprise_id and p.enterprise_id != "" %},
|
|
9
|
-
{
|
|
10
|
-
"system": "urn:{{ p.source_uri }}:enterprise-id",
|
|
11
|
-
"value": "{{ p.enterprise_id }}"
|
|
12
|
-
}{% endif %}
|
|
13
|
-
],
|
|
14
|
-
{% assign space_parts = p.patient_name | split: " " %}
|
|
15
|
-
{% if space_parts.size > 1 %}
|
|
16
|
-
"given_name": "{{ space_parts | first }}",
|
|
17
|
-
"family_name": "{{ space_parts | last }}",
|
|
18
|
-
{% else %}
|
|
19
|
-
"family_name": "{{ p.patient_name | strip }}",
|
|
20
|
-
{% endif %}
|
|
21
|
-
{% if p.patientdob and p.patientdob != "" %}"birth_date": "{{ p.patientdob | parse_date: "{M}/{D}/{YYYY}" }}",{% endif %}
|
|
22
|
-
{% if p.patient_mobile_no and p.patient_mobile_no != "" %}"phone": "{{ p.patient_mobile_no }}",{% endif %}
|
|
23
|
-
"gender": "unknown"
|
|
24
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
{% comment %}CAHPS Appointments → FHIR R4 Patient attrs{% endcomment %}
|
|
2
|
-
{% comment %}Parent appointment filtering is handled by filter_template{% endcomment %}
|
|
3
|
-
{% assign p = msg %}
|
|
4
|
-
{
|
|
5
|
-
"active": true,
|
|
6
|
-
"gender": "unknown",
|
|
7
|
-
{% if p.patientdob %}"birth_date": "{{ p.patientdob | parse_date: "{M}/{D}/{YYYY}" }}",{% endif %}
|
|
8
|
-
"identifier": [
|
|
9
|
-
{
|
|
10
|
-
"system": "urn:{{ p.source_uri }}:patient-id",
|
|
11
|
-
"value": "{{ p.patient_id | default: "" }}"
|
|
12
|
-
}{% if p.enterprise_id and p.enterprise_id != "" %},
|
|
13
|
-
{
|
|
14
|
-
"system": "urn:{{ p.source_uri }}:enterprise-id",
|
|
15
|
-
"value": "{{ p.enterprise_id }}"
|
|
16
|
-
}{% endif %}
|
|
17
|
-
],
|
|
18
|
-
{% if p.patient_name %}"name": [
|
|
19
|
-
{
|
|
20
|
-
"use": "official",
|
|
21
|
-
{% assign space_parts = p.patient_name | split: " " %}
|
|
22
|
-
{% if space_parts.size > 1 %}
|
|
23
|
-
"given": ["{{ space_parts | first }}"],
|
|
24
|
-
"family": "{{ space_parts | last }}"
|
|
25
|
-
{% else %}
|
|
26
|
-
"family": "{{ p.patient_name | strip }}"
|
|
27
|
-
{% endif %}
|
|
28
|
-
}
|
|
29
|
-
],{% endif %}
|
|
30
|
-
{% if p.patient_mobile_no and p.patient_mobile_no != "" %}"telecom": [
|
|
31
|
-
{
|
|
32
|
-
"system": "phone",
|
|
33
|
-
"value": "{{ p.patient_mobile_no }}",
|
|
34
|
-
"use": "mobile"
|
|
35
|
-
}
|
|
36
|
-
],{% endif %}
|
|
37
|
-
"source_uri": "{{ p.source_uri | default: "" }}"
|
|
38
|
-
}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
{% comment %}Atomic FI ComplianceScreenings → Payments ComplianceScreening attrs
|
|
2
|
-
|
|
3
|
-
Source: GET /api/compliance-screenings on Atomic FI (paginated; the
|
|
4
|
-
fetch pipeline extracts the `data` array via the response_extractor_key
|
|
5
|
-
and streams one row per `msg`).
|
|
6
|
-
|
|
7
|
-
The FK columns `legal_entity_id` and `account_holder_id` are NOT emitted
|
|
8
|
-
here — `ComplianceScreening.upsert_changeset/9` `put_change`s them from
|
|
9
|
-
the resolved MDMOutput after the MDM template's MDMInput drives
|
|
10
|
-
`MDM.resolve/5` (which find-or-creates the LE+AH parent pair).
|
|
11
|
-
|
|
12
|
-
Field handling on the unregulated side:
|
|
13
|
-
* narrative + name fields (screened_entity_name, review_notes,
|
|
14
|
-
pep_list_name) are persisted through TokenizedDataType — pass them
|
|
15
|
-
as raw strings here; the changeset's `cast_tokenized_data/4` calls
|
|
16
|
-
tokenize automatically before insert.
|
|
17
|
-
* analytic numerics (aml_risk_score, aml_velocity_count,
|
|
18
|
-
aml_high_risk_country) stay plaintext on both unreg + reg.
|
|
19
|
-
* `sanctions_matches` is explicitly looped — Liquid's default
|
|
20
|
-
rendering on a list produces a string, not JSON; the explicit
|
|
21
|
-
{% for %} loop emits one JSON object per element so the CS
|
|
22
|
-
upsert's `sync_sanctions_matches/6` can cast each child row.
|
|
23
|
-
{% endcomment %}
|
|
24
|
-
{% assign p = msg %}
|
|
25
|
-
{
|
|
26
|
-
"compliance_screening_number": "{{ p.compliance_screening_number | default: p.id | json_escape }}",
|
|
27
|
-
"scope": "{{ p.scope | default: "account_holder" | json_escape }}",
|
|
28
|
-
"screening_type": "{{ p.screening_type | default: "sanctions" | json_escape }}",
|
|
29
|
-
"screening_status": "{{ p.screening_status | default: "pending" | json_escape }}",
|
|
30
|
-
"screened_entity_type": "{{ p.screened_entity_type | default: "individual" | json_escape }}",
|
|
31
|
-
{% if p.screening_score and p.screening_score != "" %}"screening_score": {{ p.screening_score }},{% endif %}
|
|
32
|
-
{% if p.match_count and p.match_count != "" %}"match_count": {{ p.match_count }},{% endif %}
|
|
33
|
-
{% if p.screened_at and p.screened_at != "" %}"screened_at": "{{ p.screened_at | json_escape }}",{% endif %}
|
|
34
|
-
{% if p.sanctions_screening_status and p.sanctions_screening_status != "" %}"sanctions_screening_status": "{{ p.sanctions_screening_status | json_escape }}",{% endif %}
|
|
35
|
-
{% if p.sanctions_screening_date and p.sanctions_screening_date != "" %}"sanctions_screening_date": "{{ p.sanctions_screening_date | json_escape }}",{% endif %}
|
|
36
|
-
{% if p.manual_review_required %}"manual_review_required": {{ p.manual_review_required }},{% endif %}
|
|
37
|
-
{% if p.screened_entity_name and p.screened_entity_name != "" %}"screened_entity_name": "{{ p.screened_entity_name | json_escape }}",{% endif %}
|
|
38
|
-
{% if p.review_notes and p.review_notes != "" %}"review_notes": "{{ p.review_notes | json_escape }}",{% endif %}
|
|
39
|
-
{% if p.pep_list_name and p.pep_list_name != "" %}"pep_list_name": "{{ p.pep_list_name | json_escape }}",{% endif %}
|
|
40
|
-
{% if p.aml_risk_score and p.aml_risk_score != "" %}"aml_risk_score": {{ p.aml_risk_score }},{% endif %}
|
|
41
|
-
{% if p.aml_velocity_count and p.aml_velocity_count != "" %}"aml_velocity_count": {{ p.aml_velocity_count }},{% endif %}
|
|
42
|
-
{% if p.aml_high_risk_country and p.aml_high_risk_country != "" %}"aml_high_risk_country": "{{ p.aml_high_risk_country | json_escape }}",{% endif %}
|
|
43
|
-
{% if p.sanctions_matches %}
|
|
44
|
-
"sanctions_matches": [
|
|
45
|
-
{% for m in p.sanctions_matches %}
|
|
46
|
-
{
|
|
47
|
-
"matched_name": "{{ m.matched_name | json_escape }}",
|
|
48
|
-
{% if m.matched_entity_type and m.matched_entity_type != "" %}"matched_entity_type": "{{ m.matched_entity_type | json_escape }}",{% endif %}
|
|
49
|
-
"match_score": {{ m.match_score }},
|
|
50
|
-
"source_list": "{{ m.source_list | json_escape }}",
|
|
51
|
-
{% if m.source_id and m.source_id != "" %}"source_id": "{{ m.source_id | json_escape }}",{% endif %}
|
|
52
|
-
{% if m.false_positive_qualifier and m.false_positive_qualifier != "" %}"false_positive_qualifier": "{{ m.false_positive_qualifier | json_escape }}",{% endif %}
|
|
53
|
-
{% if m.list_synced_at and m.list_synced_at != "" %}"list_synced_at": "{{ m.list_synced_at | json_escape }}"{% else %}"list_synced_at": null{% endif %}
|
|
54
|
-
}{% unless forloop.last %},{% endunless %}
|
|
55
|
-
{% endfor %}
|
|
56
|
-
],
|
|
57
|
-
{% endif %}
|
|
58
|
-
"source_uri": "{{ p.source_uri | default: "api.atomic.fi" | json_escape }}"
|
|
59
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
{% comment %}Atomic FI ComplianceScreenings → Payments MDM Input
|
|
2
|
-
|
|
3
|
-
A CS row from Atomic FI references an account_holder UUID
|
|
4
|
-
(`p.account_holder_id`). MDM-resolution side uses that as the external
|
|
5
|
-
`account_holder_number` to find the LegalEntity + AccountHolder pair
|
|
6
|
-
already ingested via the account-holders IOC.
|
|
7
|
-
|
|
8
|
-
`legal_entity_id` on the resulting MDMOutput is what links the CS row's
|
|
9
|
-
`legal_entity_id` (mandatory per the consistency trigger). The
|
|
10
|
-
`account_number_uri + account_holder_number` pair is the canonical
|
|
11
|
-
external identity used by `AccountHolders.match_account_holder/2`.
|
|
12
|
-
{% endcomment %}
|
|
13
|
-
{% assign p = msg %}
|
|
14
|
-
{
|
|
15
|
-
"owner_type": "account_holder",
|
|
16
|
-
"account_holder_type": "individual",
|
|
17
|
-
"account_holder_number": "{{ p.account_holder_id | json_escape }}",
|
|
18
|
-
"account_number_uri": "{{ p.source_uri | default: "api.atomic.fi" | json_escape }}",
|
|
19
|
-
"identifiers": [
|
|
20
|
-
{
|
|
21
|
-
"system": "urn:atomic.fi:account-holder-id",
|
|
22
|
-
"value": "{{ p.account_holder_id | json_escape }}",
|
|
23
|
-
"id_type": "digital_identifier"
|
|
24
|
-
}
|
|
25
|
-
],
|
|
26
|
-
{% if p.screened_entity_name and p.screened_entity_name != "" %}
|
|
27
|
-
{% assign space_parts = p.screened_entity_name | split: " " %}
|
|
28
|
-
{% if space_parts.size > 1 %}
|
|
29
|
-
"given_name": "{{ space_parts | first | json_escape }}",
|
|
30
|
-
"family_name": "{{ space_parts | last | json_escape }}",
|
|
31
|
-
{% else %}
|
|
32
|
-
"family_name": "{{ p.screened_entity_name | strip | json_escape }}",
|
|
33
|
-
{% endif %}
|
|
34
|
-
{% endif %}
|
|
35
|
-
"gender": "unknown"
|
|
36
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
{% comment %}Atomic FI PaymentAccount → Payments MDM Input
|
|
2
|
-
|
|
3
|
-
A PaymentAccount row from Atomic FI references an account_holder UUID
|
|
4
|
-
(`p.account_holder_id`) — that's the canonical external identity used by
|
|
5
|
-
`AccountHolders.match_account_holder/2` to find-or-create the
|
|
6
|
-
LegalEntity + AccountHolder pair already ingested via the
|
|
7
|
-
account-holders IOC.
|
|
8
|
-
|
|
9
|
-
`legal_entity_id` on the resulting MDMOutput is what links the PA row's
|
|
10
|
-
`legal_entity_id` (PA belongs_to LE — provides the address slice for
|
|
11
|
-
sanctions-review override-agent context). The MDM scope is always
|
|
12
|
-
`account_holder` for PA rows because the PA inherently serves an
|
|
13
|
-
AccountHolder (per Atomic FI's PA schema invariant
|
|
14
|
-
`validate_required([:account_type, :account_holder_id, :currency,
|
|
15
|
-
:tenant_id])`).
|
|
16
|
-
{% endcomment %}
|
|
17
|
-
{% assign p = msg %}
|
|
18
|
-
{
|
|
19
|
-
"owner_type": "account_holder",
|
|
20
|
-
"account_holder_type": "individual",
|
|
21
|
-
"account_holder_number": "{{ p.account_holder_id | json_escape }}",
|
|
22
|
-
"account_number_uri": "{{ p.source_uri | default: "api.atomic.fi" | json_escape }}",
|
|
23
|
-
"identifiers": [
|
|
24
|
-
{
|
|
25
|
-
"system": "urn:atomic.fi:account-holder-id",
|
|
26
|
-
"value": "{{ p.account_holder_id | json_escape }}",
|
|
27
|
-
"id_type": "digital_identifier"
|
|
28
|
-
}
|
|
29
|
-
]
|
|
30
|
-
}
|
package/.agent/cookbook/_fixtures/payments/_payment_accounts_payments_payment_account.liquid
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
{% comment %}Atomic FI PaymentAccount → Payments PaymentAccount attrs
|
|
2
|
-
|
|
3
|
-
Source: GET /api/payment-accounts on Atomic FI (paginated; the fetch
|
|
4
|
-
pipeline extracts the `data` array via the response_extractor_key and
|
|
5
|
-
streams one row per `msg`).
|
|
6
|
-
|
|
7
|
-
FK columns (`legal_entity_id`, `account_holder_id`, `counterparty_id`)
|
|
8
|
-
are NOT emitted here — `PaymentAccount.upsert_changeset/7` `put_change`s
|
|
9
|
-
them from the resolved MDMOutput after the MDM template's MDMInput
|
|
10
|
-
drives `MDM.resolve/5`.
|
|
11
|
-
|
|
12
|
-
Field handling on the unregulated side:
|
|
13
|
-
* PCI-DSS-sensitive fields (`account_number`, `iban`, `card_pan`,
|
|
14
|
-
`wallet_address`) and narratives (`purpose_of_payment_detail`,
|
|
15
|
-
`business_relationship_description`) are persisted through
|
|
16
|
-
`TokenizedDataType` — pass them as raw strings here; the
|
|
17
|
-
changeset's `cast_tokenized_data/4` calls tokenize automatically
|
|
18
|
-
before insert.
|
|
19
|
-
* `enabled_regimes` is rendered as a JSON array; Liquid's `{{ x }}`
|
|
20
|
-
on a string array would produce a stringified Elixir list, not
|
|
21
|
-
JSON — the explicit `{% for %}` loop emits one quoted element per
|
|
22
|
-
regime so the changeset's array cast accepts it.
|
|
23
|
-
|
|
24
|
-
`destination_country` is derived here from `swift_bic` (chars 5-6 per
|
|
25
|
-
ISO 9362) or `iban` (chars 1-2 per ISO 13616), with BIC preferred when
|
|
26
|
-
both are present. Downstream agents (sanctions-review override) read
|
|
27
|
-
this field directly without re-parsing.
|
|
28
|
-
{% endcomment %}
|
|
29
|
-
{% assign p = msg %}
|
|
30
|
-
{% if p.swift_bic and p.swift_bic != "" %}
|
|
31
|
-
{% assign derived_country = p.swift_bic | slice: 4, 2 | upcase %}
|
|
32
|
-
{% elsif p.iban and p.iban != "" %}
|
|
33
|
-
{% assign derived_country = p.iban | slice: 0, 2 | upcase %}
|
|
34
|
-
{% else %}
|
|
35
|
-
{% assign derived_country = nil %}
|
|
36
|
-
{% endif %}
|
|
37
|
-
{
|
|
38
|
-
{% if p.payment_account_external_id and p.payment_account_external_id != "" %}"payment_account_external_id": "{{ p.payment_account_external_id | json_escape }}",{% endif %}
|
|
39
|
-
{% if p.payment_account_number and p.payment_account_number != "" %}"payment_account_number": "{{ p.payment_account_number | json_escape }}",{% endif %}
|
|
40
|
-
{% if p.status and p.status != "" %}"status": "{{ p.status | json_escape }}",{% endif %}
|
|
41
|
-
{% if p.account_type and p.account_type != "" %}"account_type": "{{ p.account_type | json_escape }}",{% endif %}
|
|
42
|
-
{% if p.currency and p.currency != "" %}"currency": "{{ p.currency | json_escape }}",{% endif %}
|
|
43
|
-
{% if p.routing_number and p.routing_number != "" %}"routing_number": "{{ p.routing_number | json_escape }}",{% endif %}
|
|
44
|
-
{% if p.swift_bic and p.swift_bic != "" %}"swift_bic": "{{ p.swift_bic | json_escape }}",{% endif %}
|
|
45
|
-
{% if p.bank_name and p.bank_name != "" %}"bank_name": "{{ p.bank_name | json_escape }}",{% endif %}
|
|
46
|
-
{% if p.wallet_chain and p.wallet_chain != "" %}"wallet_chain": "{{ p.wallet_chain | json_escape }}",{% endif %}
|
|
47
|
-
{% if p.account_number and p.account_number != "" %}"account_number": "{{ p.account_number | json_escape }}",{% endif %}
|
|
48
|
-
{% if p.iban and p.iban != "" %}"iban": "{{ p.iban | json_escape }}",{% endif %}
|
|
49
|
-
{% if p.card_pan and p.card_pan != "" %}"card_pan": "{{ p.card_pan | json_escape }}",{% endif %}
|
|
50
|
-
{% if p.wallet_address and p.wallet_address != "" %}"wallet_address": "{{ p.wallet_address | json_escape }}",{% endif %}
|
|
51
|
-
{% if p.purpose_of_payment_detail and p.purpose_of_payment_detail != "" %}"purpose_of_payment_detail": "{{ p.purpose_of_payment_detail | json_escape }}",{% endif %}
|
|
52
|
-
{% if p.business_relationship_description and p.business_relationship_description != "" %}"business_relationship_description": "{{ p.business_relationship_description | json_escape }}",{% endif %}
|
|
53
|
-
{% if derived_country and derived_country != "" %}"destination_country": "{{ derived_country | json_escape }}",{% endif %}
|
|
54
|
-
"enabled_regimes": [{% for r in p.enabled_regimes %}"{{ r | json_escape }}"{% unless forloop.last %},{% endunless %}{% endfor %}]
|
|
55
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
{% comment %}Stripe Customers → Subscription MDM Input{% endcomment %}
|
|
2
|
-
{% assign p = msg %}
|
|
3
|
-
{
|
|
4
|
-
"identifiers": [
|
|
5
|
-
{
|
|
6
|
-
"system": "urn:{{ p.source_uri | json_escape }}:customer-number",
|
|
7
|
-
"value": "{{ p.customer_number | json_escape }}"
|
|
8
|
-
}
|
|
9
|
-
],
|
|
10
|
-
{% assign space_parts = p.name | split: " " %}
|
|
11
|
-
{% if space_parts.size > 1 %}
|
|
12
|
-
"given_name": "{{ space_parts | first | json_escape }}",
|
|
13
|
-
"family_name": "{{ space_parts | last | json_escape }}",
|
|
14
|
-
{% else %}
|
|
15
|
-
"family_name": "{{ p.name | strip | json_escape }}",
|
|
16
|
-
{% endif %}
|
|
17
|
-
{% if p.phone and p.phone != "" %}"phone": "{{ p.phone | json_escape }}",{% endif %}
|
|
18
|
-
{% if p.email and p.email != "" %}"email": "{{ p.email | json_escape }}",{% endif %}
|
|
19
|
-
"gender": "unknown"
|
|
20
|
-
}
|