diff --git a/package-lock.json b/package-lock.json index 155eb36..79f87b7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "method-node", - "version": "1.1.7", + "version": "1.1.8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "method-node", - "version": "1.1.5", + "version": "1.1.8", "license": "ISC", "dependencies": { "axios": "^1.7.4", diff --git a/package.json b/package.json index 5fe51de..34107f9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "method-node", - "version": "1.1.7", + "version": "1.1.8", "description": "Node.js library for the Method API", "main": "dist/index.ts", "module": "dist/index.mjs", diff --git a/src/resources/Account/Attributes.ts b/src/resources/Account/Attributes.ts new file mode 100644 index 0000000..f99d1f5 --- /dev/null +++ b/src/resources/Account/Attributes.ts @@ -0,0 +1,40 @@ +import Resource, { IResourceListOpts } from '../../resource'; +import Configuration, { IResponse } from '../../configuration'; +import type { IAccountAttributes } from './types'; + +export default class AccountAttributes extends Resource { + constructor(config: Configuration) { + super(config.addPath('attributes')); + } + + /** + * Retrieves an Attributes record for an Account. + * + * @param acc_attr_id ID of the Attribute + * @returns Returns an Account’s Attribute object. + */ + + async retrieve(acc_attr_id: string) { + return super._getWithId>(acc_attr_id); + } + + /** + * Retrieves a list of Attributes objects for an account. + * + * @returns Returns a list of Attributes objects. + */ + + async list(opts?: IResourceListOpts) { + return super._list>(opts); + } + + /** + * Creates a new Attributes request to retrieve the Account’s attributes. + * + * @returns Returns an Account’s Attributes object. + */ + + async create() { + return super._create, {}>({}); + } +}; diff --git a/src/resources/Account/Products.ts b/src/resources/Account/Products.ts new file mode 100644 index 0000000..38a3c43 --- /dev/null +++ b/src/resources/Account/Products.ts @@ -0,0 +1,30 @@ +import Resource from '../../resource'; +import Configuration, { IResponse } from '../../configuration'; +import type { IAccountProduct, IAccountProductListResponse } from './types'; + +export default class AccountProducts extends Resource { + constructor(config: Configuration) { + super(config.addPath('products')); + } + + /** + * Retrieve an account's product. + * + * @param prd_id ID of the product. + * @returns Returns a Product object. + */ + + async retrieve(prd_id: string) { + return super._getWithId>(prd_id); + } + + /** + * Retrieve an account's product list. + * + * @returns Returns a map of Product names to Product objects for an Account. + */ + + async list() { + return super._get>(); + } +}; diff --git a/src/resources/Account/index.ts b/src/resources/Account/index.ts index 4c5dca9..b86a0c5 100644 --- a/src/resources/Account/index.ts +++ b/src/resources/Account/index.ts @@ -3,11 +3,13 @@ import Configuration, { IResponse } from '../../configuration'; import AccountCardBrand from './CardBrands'; import AccountPayoffs from './Payoffs'; import AccountUpdates from './Updates'; +import AccountAttributes from './Attributes'; import AccountBalances from './Balances'; import AccountSensitive from './Sensitive'; import AccountTransactions from './Transactions'; import AccountSubscriptions from './Subscriptions'; import AccountVerificationSession from './VerificationSessions'; +import AccountProducts from './Products'; import type { IAccount, IAccountListOpts, @@ -23,8 +25,10 @@ export class AccountSubResources { payoffs: AccountPayoffs; sensitive: AccountSensitive; subscriptions: AccountSubscriptions; + products: AccountProducts; transactions: AccountTransactions; updates: AccountUpdates; + attributes: AccountAttributes; verificationSessions: AccountVerificationSession; constructor(acc_id: string, config: Configuration) { @@ -33,8 +37,10 @@ export class AccountSubResources { this.payoffs = new AccountPayoffs(config.addPath(acc_id)); this.sensitive = new AccountSensitive(config.addPath(acc_id)); this.subscriptions = new AccountSubscriptions(config.addPath(acc_id)); + this.products = new AccountProducts(config.addPath(acc_id)); this.transactions = new AccountTransactions(config.addPath(acc_id)); this.updates = new AccountUpdates(config.addPath(acc_id)); + this.attributes = new AccountAttributes(config.addPath(acc_id)); this.verificationSessions = new AccountVerificationSession(config.addPath(acc_id)); } }; diff --git a/src/resources/Account/types.ts b/src/resources/Account/types.ts index 2fc1172..485242d 100644 --- a/src/resources/Account/types.ts +++ b/src/resources/Account/types.ts @@ -34,10 +34,42 @@ export const AccountProducts = { card_brand: 'card_brand', payoff: 'payoff', update: 'update', + attribute: 'attribute', + transactions: 'transactions', } as const; export type TAccountProducts = keyof typeof AccountProducts; +export const AccountProductStatuses = { + unavailable: 'unavailable', + available: 'available', + restricted: 'restricted', +} as const; + +export type TAccountProductStatuses = keyof typeof AccountProductStatuses; + +export interface IAccountProduct { + id: string; + name: string; + status: TAccountProductStatuses; + status_error: IResourceError | null; + latest_request_id: string | null; + is_subscribable: boolean; + created_at: string; + updated_at: string; +}; + +export interface IAccountProductListResponse { + payment?: IAccountProduct; + balance?: IAccountProduct; + sensitive?: IAccountProduct; + card_brand?: IAccountProduct; + payoff?: IAccountProduct; + update?: IAccountProduct; + attribute?: IAccountProduct; + transactions?: IAccountProduct; +}; + export const AccountSubscriptionTypes = { transactions: 'transactions', update: 'update', @@ -597,6 +629,33 @@ export interface IAccountWithdrawConsentOpts { reason: 'holder_withdrew_consent' | null; }; +export const AccountAttributeNames = { + usage_pattern: 'usage_pattern', + account_standing: 'account_standing', + delinquent_period: 'delinquent_period', + delinquent_outcome: 'delinquent_outcome', + delinquent_amount: 'delinquent_amount', + utilization: 'utilization', +}; + +export type TAccountAttributeNames = keyof typeof AccountAttributeNames; + +export type TAccountAttributes = { + [K in TAccountAttributeNames]: { + value: any | null; + } +}; + +export interface IAccountAttributes { + id: string; + account_id: string; + status: TResourceStatus; + attributes: TAccountAttributes | null; + error: IResourceError | null; + created_at: string; + updated_at: string; +} + export interface IAccount { id: string; holder_id: string; @@ -615,6 +674,7 @@ export interface IAccount { payoff?: string | IAccountPayoff | null; transactions?: string | IAccountTransaction[] | null; update?: string | IAccountUpdate | null; + attribute?: string | IAccountAttributes | null; latest_verification_session?: string | IAccountVerificationSession | null; error: IResourceError | null; created_at: string; diff --git a/test/resources/Account.tests.ts b/test/resources/Account.tests.ts index 7828663..3bd9824 100644 --- a/test/resources/Account.tests.ts +++ b/test/resources/Account.tests.ts @@ -15,6 +15,9 @@ import type { IAccountVerificationSession, IAccountUpdate, TAccountProducts, + IAccountAttributes, + IAccountProduct, + IAccountProductListResponse, } from '../../src/resources/Account'; import { IResponse } from '../../src/configuration'; @@ -40,6 +43,8 @@ describe('Accounts - core methods tests', () => { let create_update_subscriptions_response: IResponse; let create_update_snapshot_subscriptions_response: IResponse; let create_updates_response: IResponse; + let create_attributes_response: IResponse; + let accounts_retrieve_product_list_response: IAccountProductListResponse; before(async () => { holder_1_response = await client.entities.create({ @@ -134,9 +139,10 @@ describe('Accounts - core methods tests', () => { }, latest_verification_session: accounts_create_liability_response.latest_verification_session, balance: null, + attribute: null, update: accounts_create_liability_response.update, card_brand: null, - products: [ 'balance', 'payment', 'sensitive', 'update' ].sort() as TAccountProducts[], + products: accounts_create_liability_response.products, restricted_products: accounts_create_liability_response.restricted_products, subscriptions: accounts_create_liability_response.subscriptions, available_subscriptions: [ 'update' ], @@ -928,9 +934,237 @@ describe('Accounts - core methods tests', () => { }); }); + describe('accounts.attributes', () => { + it('should successfully create an attributes request', async () => { + create_attributes_response = await client.accounts(test_credit_card_account.id).attributes.create(); + + const expect_results: IAccountAttributes = { + id: create_attributes_response.id, + account_id: test_credit_card_account.id, + status: 'completed', + attributes: create_attributes_response.attributes, + error: null, + created_at: create_attributes_response.created_at, + updated_at: create_attributes_response.updated_at + }; + + create_attributes_response.should.be.eql(expect_results); + }); + + it('should successfully retrieve an attributes request', async () => { + const retrieve_attributes_response = await client.accounts(test_credit_card_account.id).attributes.retrieve(create_attributes_response.id); + + const expect_results: IAccountAttributes = { + id: create_attributes_response.id, + account_id: test_credit_card_account.id, + status: 'completed', + attributes: create_attributes_response.attributes, + error: null, + created_at: retrieve_attributes_response.created_at, + updated_at: retrieve_attributes_response.updated_at + }; + + retrieve_attributes_response.should.be.eql(expect_results); + }); + + it('should successfully list attributes for an account', async () => { + const list_attributes_response = await client.accounts(test_credit_card_account.id).attributes.list(); + + const expect_results: IAccountAttributes = { + id: create_attributes_response.id, + account_id: test_credit_card_account.id, + status: 'completed', + attributes: create_attributes_response.attributes, + error: null, + created_at: list_attributes_response[0].created_at, + updated_at: list_attributes_response[0].updated_at + }; + + list_attributes_response[0].should.be.eql(expect_results); + }); + }); + + describe('accounts.products', () => { + let accounts_retrieve_product_list_response: IAccountProductListResponse; + + it('should successfully list products for an account', async () => { + accounts_retrieve_product_list_response = await client + .accounts(test_credit_card_account.id) + .products.list(); + + const expect_results: IAccountProductListResponse = { + balance: { + id: accounts_retrieve_product_list_response.balance?.id || '', + name: 'balance', + status: 'available', + status_error: null, + latest_request_id: accounts_retrieve_product_list_response.balance?.latest_request_id || null, + is_subscribable: false, + created_at: accounts_retrieve_product_list_response.balance?.created_at || '', + updated_at: accounts_retrieve_product_list_response.balance?.updated_at || '' + }, + payment: { + id: accounts_retrieve_product_list_response.payment?.id || '', + name: 'payment', + status: 'available', + status_error: null, + latest_request_id: accounts_retrieve_product_list_response.payment?.latest_request_id || null, + is_subscribable: false, + created_at: accounts_retrieve_product_list_response.payment?.created_at || '', + updated_at: accounts_retrieve_product_list_response.payment?.updated_at || '' + }, + sensitive: { + id: accounts_retrieve_product_list_response.sensitive?.id || '', + name: 'sensitive', + status: 'available', + status_error: null, + latest_request_id: accounts_retrieve_product_list_response.sensitive?.latest_request_id || null, + is_subscribable: false, + created_at: accounts_retrieve_product_list_response.sensitive?.created_at || '', + updated_at: accounts_retrieve_product_list_response.sensitive?.updated_at || '' + }, + update: { + id: accounts_retrieve_product_list_response.update?.id || '', + name: 'update', + status: 'available', + status_error: null, + latest_request_id: accounts_retrieve_product_list_response.update?.latest_request_id || null, + is_subscribable: true, + created_at: accounts_retrieve_product_list_response.update?.created_at || '', + updated_at: accounts_retrieve_product_list_response.update?.updated_at || '' + }, + attribute: { + id: accounts_retrieve_product_list_response.attribute?.id || '', + name: 'attribute', + status: 'available', + status_error: null, + latest_request_id: accounts_retrieve_product_list_response.attribute?.latest_request_id || null, + is_subscribable: false, + created_at: accounts_retrieve_product_list_response.attribute?.created_at || '', + updated_at: accounts_retrieve_product_list_response.attribute?.updated_at || '' + }, + transactions: { + id: accounts_retrieve_product_list_response.transactions?.id || '', + name: 'transactions', + status: 'available', + status_error: null, + latest_request_id: accounts_retrieve_product_list_response.transactions?.latest_request_id || null, + is_subscribable: true, + created_at: accounts_retrieve_product_list_response.transactions?.created_at || '', + updated_at: accounts_retrieve_product_list_response.transactions?.updated_at || '' + }, + card_brand: { + id: accounts_retrieve_product_list_response.card_brand?.id || '', + name: 'card_brand', + status: 'available', + status_error: null, + latest_request_id: accounts_retrieve_product_list_response.card_brand?.latest_request_id || null, + is_subscribable: false, + created_at: accounts_retrieve_product_list_response.card_brand?.created_at || '', + updated_at: accounts_retrieve_product_list_response.card_brand?.updated_at || '' + }, + payoff: { + id: accounts_retrieve_product_list_response.payoff?.id || '', + name: 'payoff', + status: 'unavailable', + status_error: accounts_retrieve_product_list_response.payoff?.status_error || null, + latest_request_id: accounts_retrieve_product_list_response.payoff?.latest_request_id || null, + is_subscribable: false, + created_at: accounts_retrieve_product_list_response.payoff?.created_at || '', + updated_at: accounts_retrieve_product_list_response.payoff?.updated_at || '' + } + }; + + accounts_retrieve_product_list_response.should.be.eql(expect_results); + }); + + it('should successfully retrieve specific products for an account', async () => { + const account_balance_product = await client + .accounts(test_credit_card_account.id) + .products.retrieve(accounts_retrieve_product_list_response.balance?.id || ''); + + const account_payment_product = await client + .accounts(test_credit_card_account.id) + .products.retrieve(accounts_retrieve_product_list_response.payment?.id || ''); + + const account_sensitive_product = await client + .accounts(test_credit_card_account.id) + .products.retrieve(accounts_retrieve_product_list_response.sensitive?.id || ''); + + const account_update_product = await client + .accounts(test_credit_card_account.id) + .products.retrieve(accounts_retrieve_product_list_response.update?.id || ''); + + const account_attribute_product = await client + .accounts(test_credit_card_account.id) + .products.retrieve(accounts_retrieve_product_list_response.attribute?.id || ''); + + const expect_balance_results: IAccountProduct = { + id: accounts_retrieve_product_list_response.balance?.id || '', + name: 'balance', + status: 'available', + status_error: null, + latest_request_id: account_balance_product.latest_request_id, + is_subscribable: false, + created_at: account_balance_product.created_at, + updated_at: account_balance_product.updated_at + }; + + const expect_payment_results: IAccountProduct = { + id: accounts_retrieve_product_list_response.payment?.id || '', + name: 'payment', + status: 'available', + status_error: null, + latest_request_id: account_payment_product.latest_request_id, + is_subscribable: false, + created_at: account_payment_product.created_at, + updated_at: account_payment_product.updated_at + }; + + const expect_sensitive_results: IAccountProduct = { + id: accounts_retrieve_product_list_response.sensitive?.id || '', + name: 'sensitive', + status: 'available', + status_error: null, + latest_request_id: account_sensitive_product.latest_request_id, + is_subscribable: false, + created_at: account_sensitive_product.created_at, + updated_at: account_sensitive_product.updated_at + }; + + const expect_update_results: IAccountProduct = { + id: accounts_retrieve_product_list_response.update?.id || '', + name: 'update', + status: 'available', + status_error: null, + latest_request_id: account_update_product.latest_request_id, + is_subscribable: true, + created_at: account_update_product.created_at, + updated_at: account_update_product.updated_at + }; + + const expect_attribute_results: IAccountProduct = { + id: accounts_retrieve_product_list_response.attribute?.id || '', + name: 'attribute', + status: 'available', + status_error: null, + latest_request_id: account_attribute_product.latest_request_id, + is_subscribable: false, + created_at: account_attribute_product.created_at, + updated_at: account_attribute_product.updated_at + }; + + account_balance_product.should.be.eql(expect_balance_results); + account_payment_product.should.be.eql(expect_payment_results); + account_sensitive_product.should.be.eql(expect_sensitive_results); + account_update_product.should.be.eql(expect_update_results); + account_attribute_product.should.be.eql(expect_attribute_results); + }); + }); + + describe('accounts.withdrawConsent', () => { it('should successfully withdraw consent from an account.', async () => { - console.log('test_credit_card_account.id', test_credit_card_account.id); const withdraw_consent_response = await client.accounts.withdrawConsent(test_credit_card_account.id); const expect_results: IAccount = { diff --git a/test/resources/Event.tests.ts b/test/resources/Event.tests.ts index 9da8a38..5c2ff6a 100644 --- a/test/resources/Event.tests.ts +++ b/test/resources/Event.tests.ts @@ -150,36 +150,5 @@ describe('Events - core methods tests', () => { response.should.be.eql(expect_results); }); - - it('should simulate a credit score created event', async () => { - await client.simulate.events.create({ - type: 'credit_score.increased', - entity_id: entity_response.id, - }); - - // timeout to allow event to be created - await new Promise((resolve) => { setTimeout(resolve, 5000); }); - - const events_list_response = await client.events.list({ - type: 'credit_score.increased', - }); - - [event_response] = events_list_response; - - const response = await client.events.retrieve(event_response.id); - - const expect_results: IEvent = { - id: event_response.id, - created_at: event_response.created_at, - updated_at: event_response.updated_at, - type: 'credit_score.increased', - resource_id: event_response.resource_id, - resource_type: 'credit_score', - data: event_response.data, - diff: event_response.diff, - }; - - response.should.be.eql(expect_results); - }); }); });