From 1025d4128354ba108df65b877fb70a5f732efb05 Mon Sep 17 00:00:00 2001 From: bsanduc Date: Thu, 3 Oct 2024 09:57:11 +0300 Subject: [PATCH 01/12] Add script template and update card types --- packages/wallet/backend/src/card/types.ts | 133 +++++++++++++++++----- packages/wallet/backend/src/cardUsers.ts | 90 +++++++++++++++ 2 files changed, 197 insertions(+), 26 deletions(-) create mode 100644 packages/wallet/backend/src/cardUsers.ts diff --git a/packages/wallet/backend/src/card/types.ts b/packages/wallet/backend/src/card/types.ts index 1d8c96b2c..38ba91a4a 100644 --- a/packages/wallet/backend/src/card/types.ts +++ b/packages/wallet/backend/src/card/types.ts @@ -17,39 +17,120 @@ export interface ILinksResponse { } export interface ICreateCustomerRequest { - emailAddress: string + walletAddress: string account: { productCode: string + card: { + productCode: string + } } - card: { - productCode: string - } - user: { - firstName: string - lastName: string - mobileNumber?: string - nationalIdentifier?: string - } - identification: { - documents: Array<{ - type: string - file: string // Base64-encoded file content - }> - } - address: { - addressLine1: string - addressLine2?: string - city: string - region?: string - postalCode: string - countryCode: string + citizen: { + name: string + surname: string + birthPlace?: string | null } } +export interface ICitizen { + name: string + surname: string + birthDate?: string | null + birthPlace?: string | null + gender?: 'Female' | 'Male' | 'Unspecified' | 'Unknown' | null + title?: string | null + language?: string | null +} + +export interface ILegalEntity { + longName: string + shortName: string + sector?: + | 'Public' + | 'Private' + | 'Corporate' + | 'Others' + | 'NoInformation' + | 'UnrelatedPersonsLegalEntities' + | null + industrialClassificationProvider?: string | null + industrialClassificationValue?: string | null + type?: string | null + vat?: string | null + hqCustomerId?: number | null + contactPerson?: string | null + agentCode?: string | null + agentName?: string | null +} + +export interface IAddress { + sourceId?: string | null + type: 'PermanentResidence' | 'Work' | 'Other' | 'TemporaryResidence' + countryCode: string + line1: string + line2?: string | null + line3?: string | null + city: string + postOffice?: string | null + zipCode: string + status?: 'Inactive' | 'Active' | null + id?: string | null + customerId?: string | null + customerSourceId?: string | null +} + +export interface ICommunication { + sourceId?: string | null + type: 'Email' | 'Mobile' + value?: string | null + id?: string | null + status?: 'Inactive' | 'Active' | null + customerId?: string | null + customerSourceId?: string | null +} + +export interface IAccount { + sourceId?: string | null + type?: 'CHARGE' | 'LOAN' | 'DEBIT' | 'PREPAID' | null + productCode?: string | null + accountNumber?: string | null + feeProfile?: string | null + accountProfile?: string | null + id?: string | null + customerId?: string | null + customerSourceId?: string | null + status?: 'ACTIVE' | 'LOCKED' | 'BLOCKED' | null + statusReasonCode?: + | 'TemporaryBlockForDelinquency' + | 'TemporaryBlockOnIssuerRequest' + | 'TemporaryBlockForDepo' + | 'TemporaryBlockForAmlKyc' + | 'IssuerRequestGeneral' + | 'UserRequest' + | 'PremanentBlockChargeOff' + | 'IssuerRequestBureauInquiry' + | 'IssuerRequestCustomerDeceased' + | 'IssuerRequestStornoFromCollectionStraight' + | 'IssuerRequestStornoFromCollectionDepo' + | 'IssuerRequestStornoFromCollectionDepoPaid' + | 'IssuerRequestHandoverToAttorney' + | 'IssuerRequestLegalAction' + | 'IssuerRequestAmlKyc' + | null + currency?: string | null + cards?: ICardResponse[] | null +} + export interface ICreateCustomerResponse { - customerId: string - accountId: string - cardId: string + sourceId?: string | null + taxNumber?: string | null + code: string + type: 'Citizen' | 'LegalEntity' + citizen?: ICitizen | null + legalEntity?: ILegalEntity | null + id?: string | null + addresses?: IAddress[] | null + communications?: ICommunication[] | null + accounts?: IAccount[] | null } export interface ICardResponse { diff --git a/packages/wallet/backend/src/cardUsers.ts b/packages/wallet/backend/src/cardUsers.ts new file mode 100644 index 000000000..6ccb8bc59 --- /dev/null +++ b/packages/wallet/backend/src/cardUsers.ts @@ -0,0 +1,90 @@ +import { Knex } from 'knex' +import { createContainer } from '@/createContainer' +import { env } from '@/config/env' +import { + ICreateCustomerRequest, + ICreateCustomerResponse, + ICitizen +} from '@/card/types' +import { GateHubService } from './gatehub/service' +import { GateHubClient } from './gatehub/client' + +interface UserData { + email: string + walletAddress: string + firstName: string + lastName: string +} + +const usersData: UserData[] = [ + { + email: 'user1@example.com', + walletAddress: '123456789', + firstName: 'Alice', + lastName: 'Smith' + } +] + +async function cardManagement() { + // Initialize container and dependencies + const container = await createContainer(env) + const knex = container.resolve('knex') + const gateHubClient = container.resolve('gateHubClient') + + try { + // TODO: Create whitelist table and everything related + // TODO: Add users to whitelist + + // Fetch card application products + const cardProducts = await gateHubClient.fetchCardApplicationProducts() + if (!cardProducts || cardProducts.length === 0) { + throw new Error('No card application products found.') + } + + // Use the "code" field from the fetched products + // Should only be one product + const productCodes = cardProducts.map((product) => product.code) + + for (const userData of usersData) { + const { email, walletAddress, firstName, lastName } = userData + + const managedUser = await gateHubClient.createManagedUser(email) + + console.log(`Created managed user for ${email}: ${managedUser.id}`) + + // TODO: Get wallet address from GateHub + + // Create customer using product codes fetched earlier + const createCustomerRequestBody: ICreateCustomerRequest = { + walletAddress, + account: { + productCode: productCodes[0], + card: { + productCode: productCodes[0] + } + }, + citizen: { + name: firstName, + surname: lastName + } + } + + const customer: ICreateCustomerResponse = + await gateHubClient.createCustomer(createCustomerRequestBody) + + console.log(`Created customer for ${email}: ${customer.id}`) + + // TODO: Map managed user to customer + } + } catch (error: any) { + console.log(`An error occurred: ${error.message}`) + } finally { + await knex.destroy() + await container.dispose() + } +} + +cardManagement().catch((error) => { + console.error(`Script failed: ${error.message}`) + process.exit(1) +}) From c9003cff20e9c89b995b06291c964824da7dd1ab Mon Sep 17 00:00:00 2001 From: bsanduc Date: Thu, 3 Oct 2024 10:27:34 +0300 Subject: [PATCH 02/12] Remove unused imports --- packages/wallet/backend/src/cardUsers.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/wallet/backend/src/cardUsers.ts b/packages/wallet/backend/src/cardUsers.ts index 6ccb8bc59..237a675ce 100644 --- a/packages/wallet/backend/src/cardUsers.ts +++ b/packages/wallet/backend/src/cardUsers.ts @@ -1,12 +1,7 @@ import { Knex } from 'knex' import { createContainer } from '@/createContainer' import { env } from '@/config/env' -import { - ICreateCustomerRequest, - ICreateCustomerResponse, - ICitizen -} from '@/card/types' -import { GateHubService } from './gatehub/service' +import { ICreateCustomerRequest, ICreateCustomerResponse } from '@/card/types' import { GateHubClient } from './gatehub/client' interface UserData { From e17050948a4ebb3feb1ad2b6f27943e5492a7221 Mon Sep 17 00:00:00 2001 From: bsanduc Date: Thu, 3 Oct 2024 14:18:42 +0300 Subject: [PATCH 03/12] Change endpoint for create customer --- packages/wallet/backend/src/gatehub/client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/wallet/backend/src/gatehub/client.ts b/packages/wallet/backend/src/gatehub/client.ts index d1d21f2c9..9624f63eb 100644 --- a/packages/wallet/backend/src/gatehub/client.ts +++ b/packages/wallet/backend/src/gatehub/client.ts @@ -332,7 +332,7 @@ export class GateHubClient { async createCustomer( requestBody: ICreateCustomerRequest ): Promise { - const url = `${this.apiUrl}/v1/customers` + const url = `${this.apiUrl}/v1/customers/managed` return this.request( 'POST', url, From 0a7f5dcb421ac021f6eb6f9b82cf7aa65815ed56 Mon Sep 17 00:00:00 2001 From: bsanduc Date: Tue, 8 Oct 2024 18:07:29 +0300 Subject: [PATCH 04/12] WIP --- docker/dev/.env.example | 3 + docker/dev/docker-compose.yml | 2 + docker/prod/.env.example | 3 + docker/prod/docker-compose.yml | 3 + ...20241008143459_add_customer_id_to_users.js | 19 +++++ packages/wallet/backend/src/card/types.ts | 1 + packages/wallet/backend/src/cardUsers.ts | 75 ++++++++++++------- packages/wallet/backend/src/config/env.ts | 5 ++ packages/wallet/backend/src/gatehub/client.ts | 17 +++++ packages/wallet/backend/src/user/model.ts | 1 + 10 files changed, 100 insertions(+), 29 deletions(-) create mode 100644 packages/wallet/backend/migrations/20241008143459_add_customer_id_to_users.js diff --git a/docker/dev/.env.example b/docker/dev/.env.example index d4dddddb5..c7406c4b6 100644 --- a/docker/dev/.env.example +++ b/docker/dev/.env.example @@ -10,6 +10,9 @@ GATEHUB_VAULT_UUID_EUR= GATEHUB_VAULT_UUID_USD= GATEHUB_SETTLEMENT_WALLET_ADDRESS= GATEHUB_CARD_APP_ID= +GATEHUB_ACCOUNT_PRODUCT_CODE= +GATEHUB_CARD_PRODUCT_CODE= +NAME_ON_CARD_PREFIX= # commerce env variables # encoded base 64 private key diff --git a/docker/dev/docker-compose.yml b/docker/dev/docker-compose.yml index c8188142c..bfe981964 100644 --- a/docker/dev/docker-compose.yml +++ b/docker/dev/docker-compose.yml @@ -56,6 +56,8 @@ services: GATEHUB_VAULT_UUID_USD: ${GATEHUB_VAULT_UUID_USD} GATEHUB_SETTLEMENT_WALLET_ADDRESS: ${GATEHUB_SETTLEMENT_WALLET_ADDRESS} GATEHUB_CARD_APP_ID: ${GATEHUB_CARD_APP_ID} + GATEHUB_ACCOUNT_PRODUCT_CODE: = ${GATEHUB_ACCOUNT_PRODUCT_CODE} + GATEHUB_CARD_PRODUCT_CODE: = ${GATEHUB_CARD_PRODUCT_CODE} restart: always networks: - testnet diff --git a/docker/prod/.env.example b/docker/prod/.env.example index a25cded13..deafedb1c 100644 --- a/docker/prod/.env.example +++ b/docker/prod/.env.example @@ -33,6 +33,9 @@ WALLET_BACKEND_GATEHUB_VAULT_UUID_EUR= WALLET_BACKEND_GATEHUB_VAULT_UUID_USD= WALLET_BACKEND_GATEHUB_SETTLEMENT_WALLET_ADDRESS= WALLET_BACKEND_GATEHUB_CARD_APP_ID= +WALLET_BACKEND_GATEHUB_ACCOUNT_PRODUCT_CODE= +WALLET_BACKEND_GATEHUB_CARD_PRODUCT_CODE= +WALLET_NAME_ON_CARD_PREFIX= # BOUTIQUE BOUTIQUE_BACKEND_PORT= diff --git a/docker/prod/docker-compose.yml b/docker/prod/docker-compose.yml index af6c85eab..e52c91b88 100644 --- a/docker/prod/docker-compose.yml +++ b/docker/prod/docker-compose.yml @@ -67,6 +67,9 @@ services: GATEHUB_VAULT_UUID_USD: ${WALLET_BACKEND_GATEHUB_VAULT_UUID_USD} GATEHUB_SETTLEMENT_WALLET_ADDRESS: ${WALLET_BACKEND_GATEHUB_SETTLEMENT_WALLET_ADDRESS} GATEHUB_CARD_APP_ID: ${WALLET_BACKEND_GATEHUB_CARD_APP_ID} + GATEHUB_ACCOUNT_PRODUCT_CODE: ${WALLET_BACKEND_GATEHUB_ACCOUNT_PRODUCT_CODE} + GATEHUB_CARD_PRODUCT_CODE: ${WALLET_BACKEND_GATEHUB_CARD_PRODUCT_CODE} + NAME_ON_CARD_PREFIX: ${WALLET_BACKEND_NAME_ON_CARD_PREFIX} networks: - testnet ports: diff --git a/packages/wallet/backend/migrations/20241008143459_add_customer_id_to_users.js b/packages/wallet/backend/migrations/20241008143459_add_customer_id_to_users.js new file mode 100644 index 000000000..ae1b26719 --- /dev/null +++ b/packages/wallet/backend/migrations/20241008143459_add_customer_id_to_users.js @@ -0,0 +1,19 @@ +/** + * @param { import("knex").Knex } knex + * @returns { Promise } + */ +exports.up = function (knex) { + return knex.schema.table('users', function (table) { + table.string('customerId').unique().nullable() + }) +} + +/** + * @param { import("knex").Knex } knex + * @returns { Promise } + */ +exports.down = function (knex) { + return knex.schema.table('users', function (table) { + table.dropColumn('customerId') + }) +} diff --git a/packages/wallet/backend/src/card/types.ts b/packages/wallet/backend/src/card/types.ts index 38ba91a4a..1c98c6657 100644 --- a/packages/wallet/backend/src/card/types.ts +++ b/packages/wallet/backend/src/card/types.ts @@ -24,6 +24,7 @@ export interface ICreateCustomerRequest { productCode: string } } + nameOnCard: string, citizen: { name: string surname: string diff --git a/packages/wallet/backend/src/cardUsers.ts b/packages/wallet/backend/src/cardUsers.ts index 237a675ce..74df07090 100644 --- a/packages/wallet/backend/src/cardUsers.ts +++ b/packages/wallet/backend/src/cardUsers.ts @@ -3,61 +3,74 @@ import { createContainer } from '@/createContainer' import { env } from '@/config/env' import { ICreateCustomerRequest, ICreateCustomerResponse } from '@/card/types' import { GateHubClient } from './gatehub/client' +import fs from 'fs' +import path from 'path' +import csv from 'csv-parser' interface UserData { email: string - walletAddress: string firstName: string lastName: string + ppNumber: string } -const usersData: UserData[] = [ - { - email: 'user1@example.com', - walletAddress: '123456789', - firstName: 'Alice', - lastName: 'Smith' - } -] +async function readUsersData(): Promise { + const usersData: UserData[] = [] + const csvFilePath = path.resolve(__dirname, 'users.csv') + + return new Promise((resolve, reject) => { + fs.createReadStream(csvFilePath) + .pipe(csv()) + .on('data', (row) => { + usersData.push({ + email: row.email, + firstName: row.firstName, + lastName: row.lastName, + ppNumber: row.ppNumber + }) + }) + .on('end', () => { + console.log('CSV file successfully processed') + resolve(usersData) + }) + .on('error', (error) => { + reject(error) + }) + }) +} async function cardManagement() { - // Initialize container and dependencies const container = await createContainer(env) const knex = container.resolve('knex') const gateHubClient = container.resolve('gateHubClient') + const accountProductCode = env.GATEHUB_ACCOUNT_PRODUCT_CODE + const cardProductCode = env.GATEHUB_CARD_PRODUCT_CODE + const nameOnCardPrefix = env.NAME_ON_CARD_PREFIX try { - // TODO: Create whitelist table and everything related - // TODO: Add users to whitelist - - // Fetch card application products - const cardProducts = await gateHubClient.fetchCardApplicationProducts() - if (!cardProducts || cardProducts.length === 0) { - throw new Error('No card application products found.') - } - - // Use the "code" field from the fetched products - // Should only be one product - const productCodes = cardProducts.map((product) => product.code) + const usersData = await readUsersData() for (const userData of usersData) { - const { email, walletAddress, firstName, lastName } = userData + const { email, ppNumber, firstName, lastName } = userData const managedUser = await gateHubClient.createManagedUser(email) console.log(`Created managed user for ${email}: ${managedUser.id}`) - // TODO: Get wallet address from GateHub + const wallet = await gateHubClient.getWalletForUser( + managedUser.id + ) - // Create customer using product codes fetched earlier + // Create customer using product codes as env vars const createCustomerRequestBody: ICreateCustomerRequest = { - walletAddress, + walletAddress: wallet.address, account: { - productCode: productCodes[0], + productCode: accountProductCode, card: { - productCode: productCodes[0] + productCode: cardProductCode } }, + nameOnCard: nameOnCardPrefix + ppNumber, citizen: { name: firstName, surname: lastName @@ -69,7 +82,11 @@ async function cardManagement() { console.log(`Created customer for ${email}: ${customer.id}`) - // TODO: Map managed user to customer + const pp = nameOnCardPrefix + ppNumber + await gateHubClient.updateMetaForManagedUser( + managedUser.id, + pp.split(' ')[1].toLowerCase + ) } } catch (error: any) { console.log(`An error occurred: ${error.message}`) diff --git a/packages/wallet/backend/src/config/env.ts b/packages/wallet/backend/src/config/env.ts index 1a9308dc8..9eb572730 100644 --- a/packages/wallet/backend/src/config/env.ts +++ b/packages/wallet/backend/src/config/env.ts @@ -21,6 +21,11 @@ const envSchema = z.object({ .string() .default('GATEHUB_SETTLEMENT_WALLET_ADDRESS'), GATEHUB_CARD_APP_ID: z.string().default('GATEHUB_CARD_APP_ID'), + GATEHUB_ACCOUNT_PRODUCT_CODE: z + .string() + .default('GATEHUB_ACCOUNT_PRODUCT_CODE'), + GATEHUB_CARD_PRODUCT_CODE: z.string().default('GATEHUB_CARD_PRODUCT_CODE'), + NAME_ON_CARD_PREFIX: z.string().default('NAME_ON_CARD_PREFIX'), GRAPHQL_ENDPOINT: z.string().url().default('http://localhost:3011/graphql'), AUTH_GRAPHQL_ENDPOINT: z .string() diff --git a/packages/wallet/backend/src/gatehub/client.ts b/packages/wallet/backend/src/gatehub/client.ts index 9624f63eb..99212d865 100644 --- a/packages/wallet/backend/src/gatehub/client.ts +++ b/packages/wallet/backend/src/gatehub/client.ts @@ -178,6 +178,13 @@ export class GateHubClient { return response } + async updateMetaForManagedUser(meta: Record): Promise { + const url = `${this.apiUrl}/auth/v1/users/managed` + const body = { meta } + + return await this.request('PUT', url, JSON.stringify(body)) + } + async createManagedUser(email: string): Promise { const url = `${this.apiUrl}/auth/v1/users/managed` const body: ICreateManagedUserRequest = { email } @@ -272,6 +279,16 @@ export class GateHubClient { return response } + async getWalletForUser( + userUuid: string + ): Promise { + const url = `${this.apiUrl}/core/v1/users/${userUuid}/wallets/` + + const response = await this.request('GET', url) + + return response + } + async getWalletBalance(walletId: string): Promise { const url = `${this.apiUrl}/core/v1/wallets/${walletId}/balances` diff --git a/packages/wallet/backend/src/user/model.ts b/packages/wallet/backend/src/user/model.ts index c853b307b..b70239124 100644 --- a/packages/wallet/backend/src/user/model.ts +++ b/packages/wallet/backend/src/user/model.ts @@ -20,6 +20,7 @@ export class User extends BaseModel { public kycVerified!: boolean public gateHubUserId?: string + public customerId?: string public sessions?: Session[] public passwordResetToken?: string | null From b2c3ad0e886dfb3e26b0972b5ee50a8e63ffe39d Mon Sep 17 00:00:00 2001 From: Radu-Cristian Popa Date: Wed, 9 Oct 2024 06:46:36 +0300 Subject: [PATCH 05/12] Finish script & additional changes - Update ENV variables (DEV & PROD) - Fix API endpoints - Update types --- docker/dev/.env.example | 2 +- docker/dev/docker-compose.yml | 5 +- docker/prod/.env.example | 2 +- docker/prod/docker-compose.yml | 2 +- packages/wallet/backend/src/card/types.ts | 26 +++-- packages/wallet/backend/src/cardUsers.ts | 106 ++++++++++-------- packages/wallet/backend/src/config/env.ts | 2 +- packages/wallet/backend/src/gatehub/client.ts | 53 +++++++-- packages/wallet/backend/src/gatehub/types.ts | 5 + 9 files changed, 128 insertions(+), 75 deletions(-) diff --git a/docker/dev/.env.example b/docker/dev/.env.example index c7406c4b6..da3fa07ca 100644 --- a/docker/dev/.env.example +++ b/docker/dev/.env.example @@ -12,7 +12,7 @@ GATEHUB_SETTLEMENT_WALLET_ADDRESS= GATEHUB_CARD_APP_ID= GATEHUB_ACCOUNT_PRODUCT_CODE= GATEHUB_CARD_PRODUCT_CODE= -NAME_ON_CARD_PREFIX= +GATEHUB_NAME_ON_CARD_PREFIX= # commerce env variables # encoded base 64 private key diff --git a/docker/dev/docker-compose.yml b/docker/dev/docker-compose.yml index bfe981964..faf24eb04 100644 --- a/docker/dev/docker-compose.yml +++ b/docker/dev/docker-compose.yml @@ -56,8 +56,9 @@ services: GATEHUB_VAULT_UUID_USD: ${GATEHUB_VAULT_UUID_USD} GATEHUB_SETTLEMENT_WALLET_ADDRESS: ${GATEHUB_SETTLEMENT_WALLET_ADDRESS} GATEHUB_CARD_APP_ID: ${GATEHUB_CARD_APP_ID} - GATEHUB_ACCOUNT_PRODUCT_CODE: = ${GATEHUB_ACCOUNT_PRODUCT_CODE} - GATEHUB_CARD_PRODUCT_CODE: = ${GATEHUB_CARD_PRODUCT_CODE} + GATEHUB_ACCOUNT_PRODUCT_CODE: ${GATEHUB_ACCOUNT_PRODUCT_CODE} + GATEHUB_CARD_PRODUCT_CODE: ${GATEHUB_CARD_PRODUCT_CODE} + GATEHUB_NAME_ON_CARD_PREFIX: ${GATEHUB_NAME_ON_CARD_PREFIX} restart: always networks: - testnet diff --git a/docker/prod/.env.example b/docker/prod/.env.example index deafedb1c..513c756c0 100644 --- a/docker/prod/.env.example +++ b/docker/prod/.env.example @@ -35,7 +35,7 @@ WALLET_BACKEND_GATEHUB_SETTLEMENT_WALLET_ADDRESS= WALLET_BACKEND_GATEHUB_CARD_APP_ID= WALLET_BACKEND_GATEHUB_ACCOUNT_PRODUCT_CODE= WALLET_BACKEND_GATEHUB_CARD_PRODUCT_CODE= -WALLET_NAME_ON_CARD_PREFIX= +WALLET_BACKEND_GATEHUB_NAME_ON_CARD_PREFIX= # BOUTIQUE BOUTIQUE_BACKEND_PORT= diff --git a/docker/prod/docker-compose.yml b/docker/prod/docker-compose.yml index e52c91b88..22ae101ad 100644 --- a/docker/prod/docker-compose.yml +++ b/docker/prod/docker-compose.yml @@ -69,7 +69,7 @@ services: GATEHUB_CARD_APP_ID: ${WALLET_BACKEND_GATEHUB_CARD_APP_ID} GATEHUB_ACCOUNT_PRODUCT_CODE: ${WALLET_BACKEND_GATEHUB_ACCOUNT_PRODUCT_CODE} GATEHUB_CARD_PRODUCT_CODE: ${WALLET_BACKEND_GATEHUB_CARD_PRODUCT_CODE} - NAME_ON_CARD_PREFIX: ${WALLET_BACKEND_NAME_ON_CARD_PREFIX} + GATEHUB_NAME_ON_CARD_PREFIX: ${WALLET_BACKEND_NAME_ON_CARD_PREFIX} networks: - testnet ports: diff --git a/packages/wallet/backend/src/card/types.ts b/packages/wallet/backend/src/card/types.ts index 1c98c6657..576f95f9a 100644 --- a/packages/wallet/backend/src/card/types.ts +++ b/packages/wallet/backend/src/card/types.ts @@ -20,11 +20,12 @@ export interface ICreateCustomerRequest { walletAddress: string account: { productCode: string + currency: 'EUR' card: { productCode: string } } - nameOnCard: string, + nameOnCard: string citizen: { name: string surname: string @@ -122,16 +123,19 @@ export interface IAccount { } export interface ICreateCustomerResponse { - sourceId?: string | null - taxNumber?: string | null - code: string - type: 'Citizen' | 'LegalEntity' - citizen?: ICitizen | null - legalEntity?: ILegalEntity | null - id?: string | null - addresses?: IAddress[] | null - communications?: ICommunication[] | null - accounts?: IAccount[] | null + walletAddress: string + customers: { + sourceId?: string | null + taxNumber?: string | null + code: string + type: 'Citizen' | 'LegalEntity' + citizen?: ICitizen | null + legalEntity?: ILegalEntity | null + id?: string | null + addresses?: IAddress[] | null + communications?: ICommunication[] | null + accounts?: IAccount[] | null + } } export interface ICardResponse { diff --git a/packages/wallet/backend/src/cardUsers.ts b/packages/wallet/backend/src/cardUsers.ts index 74df07090..72e63431f 100644 --- a/packages/wallet/backend/src/cardUsers.ts +++ b/packages/wallet/backend/src/cardUsers.ts @@ -1,11 +1,6 @@ -import { Knex } from 'knex' import { createContainer } from '@/createContainer' import { env } from '@/config/env' -import { ICreateCustomerRequest, ICreateCustomerResponse } from '@/card/types' -import { GateHubClient } from './gatehub/client' -import fs from 'fs' -import path from 'path' -import csv from 'csv-parser' +import { ICreateCustomerRequest } from '@/card/types' interface UserData { email: string @@ -14,82 +9,95 @@ interface UserData { ppNumber: string } -async function readUsersData(): Promise { - const usersData: UserData[] = [] - const csvFilePath = path.resolve(__dirname, 'users.csv') - - return new Promise((resolve, reject) => { - fs.createReadStream(csvFilePath) - .pipe(csv()) - .on('data', (row) => { - usersData.push({ - email: row.email, - firstName: row.firstName, - lastName: row.lastName, - ppNumber: row.ppNumber - }) - }) - .on('end', () => { - console.log('CSV file successfully processed') - resolve(usersData) - }) - .on('error', (error) => { - reject(error) - }) - }) +const entries = `John;Doe;john@doe.com:8888; +Alice;Smith;alice@smith.com;9999` + +function processEntries() { + const users: Array = [] + const lines = entries.split('\n') + for (const line of lines) { + const [firstName, lastName, email, ppNumber] = line.split(';') + users.push({ + email, + firstName, + lastName, + ppNumber + }) + } + + return users } async function cardManagement() { const container = await createContainer(env) - const knex = container.resolve('knex') - const gateHubClient = container.resolve('gateHubClient') + const logger = container.resolve('logger') + const knex = container.resolve('knex') + const gateHubClient = container.resolve('gateHubClient') const accountProductCode = env.GATEHUB_ACCOUNT_PRODUCT_CODE const cardProductCode = env.GATEHUB_CARD_PRODUCT_CODE - const nameOnCardPrefix = env.NAME_ON_CARD_PREFIX + const nameOnCardPrefix = env.GATEHUB_NAME_ON_CARD_PREFIX + const GATEWAY_UUID = env.GATEHUB_GATEWAY_UUID try { - const usersData = await readUsersData() + const usersData = processEntries() for (const userData of usersData) { - const { email, ppNumber, firstName, lastName } = userData + const { email, firstName, lastName, ppNumber } = userData const managedUser = await gateHubClient.createManagedUser(email) - console.log(`Created managed user for ${email}: ${managedUser.id}`) + logger.info(`Created managed user for ${email}: ${managedUser.id}`) + + await gateHubClient.connectUserToGateway(managedUser.id, GATEWAY_UUID) - const wallet = await gateHubClient.getWalletForUser( - managedUser.id + logger.info( + `Connected user ${managedUser.id} - ${managedUser.email} to gateway` ) + const user = await gateHubClient.getWalletForUser(managedUser.id) + const walletAddress = user.wallets[0].address + const nameOnCard = nameOnCardPrefix + ppNumber + + logger.info(`Retrieved user ${managedUser.id} wallet - ${walletAddress}`) + // Create customer using product codes as env vars const createCustomerRequestBody: ICreateCustomerRequest = { - walletAddress: wallet.address, + walletAddress, account: { productCode: accountProductCode, + currency: 'EUR', card: { productCode: cardProductCode } }, - nameOnCard: nameOnCardPrefix + ppNumber, + nameOnCard, citizen: { name: firstName, surname: lastName } } - const customer: ICreateCustomerResponse = - await gateHubClient.createCustomer(createCustomerRequestBody) - - console.log(`Created customer for ${email}: ${customer.id}`) - - const pp = nameOnCardPrefix + ppNumber - await gateHubClient.updateMetaForManagedUser( + const customer = await gateHubClient.createCustomer( managedUser.id, - pp.split(' ')[1].toLowerCase + createCustomerRequestBody ) + + logger.info(`Created customer for ${email}: ${customer.customers.id}`) + + await gateHubClient.updateMetaForManagedUser(managedUser.id, { + paymentPointer: nameOnCard.split(' ')[1].toLowerCase(), + customerId: customer.customers.id! + }) + + logger.info(`Updated meta object for user ${email}`) + + const accounts = customer.customers.accounts![0] + const card = accounts.cards![0] + + await gateHubClient.orderPlasticForCard(managedUser.id, card.id) } - } catch (error: any) { - console.log(`An error occurred: ${error.message}`) + } catch (error: unknown) { + console.log(`An error occurred: ${(error as Error).message}`) } finally { await knex.destroy() await container.dispose() diff --git a/packages/wallet/backend/src/config/env.ts b/packages/wallet/backend/src/config/env.ts index 9eb572730..f1835d646 100644 --- a/packages/wallet/backend/src/config/env.ts +++ b/packages/wallet/backend/src/config/env.ts @@ -25,7 +25,7 @@ const envSchema = z.object({ .string() .default('GATEHUB_ACCOUNT_PRODUCT_CODE'), GATEHUB_CARD_PRODUCT_CODE: z.string().default('GATEHUB_CARD_PRODUCT_CODE'), - NAME_ON_CARD_PREFIX: z.string().default('NAME_ON_CARD_PREFIX'), + GATEHUB_NAME_ON_CARD_PREFIX: z.string().default('NAME_ON_CARD_PREFIX'), GRAPHQL_ENDPOINT: z.string().url().default('http://localhost:3011/graphql'), AUTH_GRAPHQL_ENDPOINT: z .string() diff --git a/packages/wallet/backend/src/gatehub/client.ts b/packages/wallet/backend/src/gatehub/client.ts index 99212d865..3c2db797b 100644 --- a/packages/wallet/backend/src/gatehub/client.ts +++ b/packages/wallet/backend/src/gatehub/client.ts @@ -12,6 +12,7 @@ import { ICreateWalletResponse, IGetUserStateResponse, IGetVaultsResponse, + IGetWalletForUserResponse, IGetWalletResponse, IRatesResponse, ITokenRequest, @@ -178,11 +179,20 @@ export class GateHubClient { return response } - async updateMetaForManagedUser(meta: Record): Promise { + /** + * The meta was createad as `meta.meta.[property]` + * We should be aware of this when the user signs up (for production) + */ + async updateMetaForManagedUser( + userUuid: string, + meta: Record + ): Promise { const url = `${this.apiUrl}/auth/v1/users/managed` const body = { meta } - return await this.request('PUT', url, JSON.stringify(body)) + return await this.request('PUT', url, JSON.stringify(body), { + managedUserUuid: userUuid + }) } async createManagedUser(email: string): Promise { @@ -279,12 +289,23 @@ export class GateHubClient { return response } - async getWalletForUser( - userUuid: string - ): Promise { - const url = `${this.apiUrl}/core/v1/users/${userUuid}/wallets/` + /** + * Retrieves the user with its corresponding wallets. + * + * !!! The `meta` object is not present here - not the same output as + * ICreateManagedUserResponse !!! + */ + async getWalletForUser(userUuid: string): Promise { + const url = `${this.apiUrl}/core/v1/users/${userUuid}` - const response = await this.request('GET', url) + const response = await this.request( + 'GET', + url, + undefined, + { + managedUserUuid: userUuid + } + ) return response } @@ -347,17 +368,31 @@ export class GateHubClient { } async createCustomer( + userUuid: string, requestBody: ICreateCustomerRequest ): Promise { - const url = `${this.apiUrl}/v1/customers/managed` - return this.request( + const url = `${this.apiUrl}/cards/v1/customers/managed` + const response = await this.request( 'POST', url, JSON.stringify(requestBody), { + managedUserUuid: userUuid, cardAppId: this.env.GATEHUB_CARD_APP_ID } ) + return response + } + + /** + * @deprecated Only used when ordering cards. + */ + async orderPlasticForCard(userUuid: string, cardId: string): Promise { + const url = `${this.apiUrl}/cards/v1/cards/${cardId}/plastic` + await this.request('POST', url, undefined, { + managedUserUuid: userUuid, + cardAppId: this.env.GATEHUB_CARD_APP_ID + }) } async getCardsByCustomer(customerId: string): Promise { diff --git a/packages/wallet/backend/src/gatehub/types.ts b/packages/wallet/backend/src/gatehub/types.ts index 471af48d3..4b7f684f3 100644 --- a/packages/wallet/backend/src/gatehub/types.ts +++ b/packages/wallet/backend/src/gatehub/types.ts @@ -55,6 +55,11 @@ export interface ICreateWalletRequest { export interface ICreateWalletResponse { address: string } + +export interface IGetWalletForUserResponse { + wallets: ICreateWalletResponse[] +} + export interface IGetWalletResponse { address: string } From 930e7509ebc3a98425963fc6a6ef980059a27d87 Mon Sep 17 00:00:00 2001 From: Radu-Cristian Popa Date: Wed, 9 Oct 2024 06:53:55 +0300 Subject: [PATCH 06/12] Add comment related to faulty meta object --- packages/wallet/backend/src/gatehub/client.ts | 2 ++ packages/wallet/backend/src/gatehub/types.ts | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/wallet/backend/src/gatehub/client.ts b/packages/wallet/backend/src/gatehub/client.ts index 3c2db797b..6e7fd5792 100644 --- a/packages/wallet/backend/src/gatehub/client.ts +++ b/packages/wallet/backend/src/gatehub/client.ts @@ -188,6 +188,8 @@ export class GateHubClient { meta: Record ): Promise { const url = `${this.apiUrl}/auth/v1/users/managed` + // This is the reason why the `meta` was created as `meta.meta`. + // Keeping this as is for consistency const body = { meta } return await this.request('PUT', url, JSON.stringify(body), { diff --git a/packages/wallet/backend/src/gatehub/types.ts b/packages/wallet/backend/src/gatehub/types.ts index 4b7f684f3..b5f4cc486 100644 --- a/packages/wallet/backend/src/gatehub/types.ts +++ b/packages/wallet/backend/src/gatehub/types.ts @@ -29,7 +29,12 @@ export interface ICreateManagedUserResponse { type2fa: string activated: boolean role: string - meta: Record + meta: { + meta: { + paymentPointer: string + customerId: string + } + } & Record lastPasswordChange: string features: string[] managed: boolean From a3001c03a03a129b34b49943012fa99b50f99523 Mon Sep 17 00:00:00 2001 From: Radu-Cristian Popa Date: Wed, 9 Oct 2024 07:01:10 +0300 Subject: [PATCH 07/12] Add lost code during merge --- packages/wallet/backend/src/gatehub/client.ts | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/packages/wallet/backend/src/gatehub/client.ts b/packages/wallet/backend/src/gatehub/client.ts index d1f386dc5..342be1ffc 100644 --- a/packages/wallet/backend/src/gatehub/client.ts +++ b/packages/wallet/backend/src/gatehub/client.ts @@ -294,6 +294,26 @@ export class GateHubClient { return response } + /** + * Retrieves the user with its corresponding wallets. + * + * !!! The `meta` object is not present here - not the same output as + * ICreateManagedUserResponse !!! + */ + async getWalletForUser(userUuid: string): Promise { + const url = `${this.apiUrl}/core/v1/users/${userUuid}` + + const response = await this.request( + 'GET', + url, + undefined, + { + managedUserUuid: userUuid + } + ) + return response + } + async getWalletBalance( walletId: string, managedUserUuid: string From 6f37b6b1b73b9a5f527587830020d87e50b739b2 Mon Sep 17 00:00:00 2001 From: sanducb <167857039+sanducb@users.noreply.github.com> Date: Wed, 9 Oct 2024 10:34:06 +0300 Subject: [PATCH 08/12] Remove unnecessary semicolon --- packages/wallet/backend/src/cardUsers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/wallet/backend/src/cardUsers.ts b/packages/wallet/backend/src/cardUsers.ts index 72e63431f..7dbf303fc 100644 --- a/packages/wallet/backend/src/cardUsers.ts +++ b/packages/wallet/backend/src/cardUsers.ts @@ -9,7 +9,7 @@ interface UserData { ppNumber: string } -const entries = `John;Doe;john@doe.com:8888; +const entries = `John;Doe;john@doe.com:8888 Alice;Smith;alice@smith.com;9999` function processEntries() { From 9eb7bd4dddf3d4eff7491fd971946c97250947ff Mon Sep 17 00:00:00 2001 From: Radu-Cristian Popa Date: Thu, 10 Oct 2024 13:11:53 +0300 Subject: [PATCH 09/12] Add reorder script --- packages/wallet/backend/src/card/types.ts | 26 ++++- packages/wallet/backend/src/cardUsers.ts | 4 +- packages/wallet/backend/src/gatehub/client.ts | 36 ++++++- packages/wallet/backend/src/reorder.ts | 97 +++++++++++++++++++ 4 files changed, 158 insertions(+), 5 deletions(-) create mode 100644 packages/wallet/backend/src/reorder.ts diff --git a/packages/wallet/backend/src/card/types.ts b/packages/wallet/backend/src/card/types.ts index 632764f00..c1f7ae419 100644 --- a/packages/wallet/backend/src/card/types.ts +++ b/packages/wallet/backend/src/card/types.ts @@ -1,5 +1,8 @@ import { CardLimitType } from '@wallet/shared/src' +export type GateHubCardCurrency = 'EUR' +export type GateHubNameOnCard = 'INTERLEDGER' + export interface ICardDetailsRequest { cardId: string publicKeyBase64: string @@ -22,12 +25,12 @@ export interface ICreateCustomerRequest { walletAddress: string account: { productCode: string - currency: 'EUR' + currency: GateHubCardCurrency card: { productCode: string } } - nameOnCard: string + nameOnCard: GateHubNameOnCard citizen: { name: string surname: string @@ -194,3 +197,22 @@ export interface ICardLimitResponse { currency: string isDisabled: boolean } + +export type CloseCardReason = + | 'IssuerRequestGeneral' + | 'IssuerRequestFraud' + | 'IssuerRequestLegal' + | 'IssuerRequestIncorrectOpening' + | 'UserRequest' + | 'IssuerRequestCustomerDeceased' + +export interface ICreateCardRequest { + nameOnCard: GateHubNameOnCard + deliveryAddressId: string + walletAddress: string + currency: GateHubCardCurrency + productCode: string + card: { + productCode: string + } +} diff --git a/packages/wallet/backend/src/cardUsers.ts b/packages/wallet/backend/src/cardUsers.ts index 7dbf303fc..a875954af 100644 --- a/packages/wallet/backend/src/cardUsers.ts +++ b/packages/wallet/backend/src/cardUsers.ts @@ -9,7 +9,7 @@ interface UserData { ppNumber: string } -const entries = `John;Doe;john@doe.com:8888 +const entries = `John;Doe;john@doe.com;8888 Alice;Smith;alice@smith.com;9999` function processEntries() { @@ -70,7 +70,7 @@ async function cardManagement() { productCode: cardProductCode } }, - nameOnCard, + nameOnCard: 'INTERLEDGER', citizen: { name: firstName, surname: lastName diff --git a/packages/wallet/backend/src/gatehub/client.ts b/packages/wallet/backend/src/gatehub/client.ts index 342be1ffc..e033c63f4 100644 --- a/packages/wallet/backend/src/gatehub/client.ts +++ b/packages/wallet/backend/src/gatehub/client.ts @@ -49,7 +49,9 @@ import { ICardLockRequest, ICardUnlockRequest, ICardLimitResponse, - ICardLimitRequest + ICardLimitRequest, + ICreateCardRequest, + CloseCardReason } from '@/card/types' import { BlockReasonCode } from '@wallet/shared/src' @@ -599,6 +601,38 @@ export class GateHubClient { return this.request('PUT', url) } + async closeCard(userUuid: string, cardId: string, reason: CloseCardReason) { + const url = `${this.apiUrl}/cards/v1/cards/${cardId}/card?reasonCode=${reason}` + + await this.request('DELETE', url, undefined, { + managedUserUuid: userUuid, + cardAppId: this.env.GATEHUB_CARD_APP_ID + }) + } + + /** + * @deprecated + */ + async createCard( + userUuid: string, + accountId: string, + payload: ICreateCardRequest + ) { + const url = `${this.apiUrl}/cards/v1/cards/${accountId}/card` + + const response = await this.request( + 'POST', + url, + JSON.stringify(payload), + { + managedUserUuid: userUuid, + cardAppId: this.env.GATEHUB_CARD_APP_ID + } + ) + + return response + } + private async request( method: HTTP_METHODS, url: string, diff --git a/packages/wallet/backend/src/reorder.ts b/packages/wallet/backend/src/reorder.ts new file mode 100644 index 000000000..631e9dba8 --- /dev/null +++ b/packages/wallet/backend/src/reorder.ts @@ -0,0 +1,97 @@ +import { createContainer } from '@/createContainer' +import { env } from '@/config/env' + +interface Entry { + userUuid: string + accountId: string + cardId: string + customerId: string + walletAddress: string + email: string + deliveryAddressId: string +} + +const entries = `userUuid1,accountId1,cardId1,customerId1,walletAddress1,john@doe.com,deliveryAddressId1 +userUuid2,accountId2,cardId2,customerId2,walletAddress2,alice@smith.com,deliveryAddressId2` + +function processEntries() { + const e: Array = [] + const lines = entries.split('\n') + for (const line of lines) { + const [ + userUuid, + accountId, + cardId, + customerId, + walletAddress, + email, + deliveryAddressId + ] = line.split(',') + e.push({ + userUuid, + accountId, + cardId, + customerId, + walletAddress, + email, + deliveryAddressId + }) + } + + return e +} + +async function reorder() { + const container = await createContainer(env) + const logger = container.resolve('logger') + const knex = container.resolve('knex') + const gateHubClient = container.resolve('gateHubClient') + const accountProductCode = env.GATEHUB_ACCOUNT_PRODUCT_CODE + const cardProductCode = env.GATEHUB_CARD_PRODUCT_CODE + + try { + const entries = processEntries() + + for (const entry of entries) { + const { userUuid, accountId, cardId, walletAddress, deliveryAddressId } = + entry + + await gateHubClient.closeCard( + userUuid, + cardId, + 'IssuerRequestIncorrectOpening' + ) + + logger.info(`Closed card with cardId: ${cardId}; user: ${userUuid}`) + + const card = await gateHubClient.createCard(userUuid, accountId, { + nameOnCard: 'INTERLEDGER', + deliveryAddressId, + walletAddress, + currency: 'EUR', + productCode: accountProductCode, + card: { productCode: cardProductCode } + }) + + logger.info( + `Created card with cardId: ${card.id}; customerId: ${card.customerId}` + ) + + await gateHubClient.orderPlasticForCard(userUuid, card.id) + + logger.info( + `Ordered plastic card for user: ${userUuid}; new card id: ${card.id}` + ) + } + } catch (error: unknown) { + console.log(`An error occurred: ${(error as Error).message}`) + } finally { + await knex.destroy() + await container.dispose() + } +} + +reorder().catch((error) => { + console.error(`Script failed: ${error.message}`) + process.exit(1) +}) From 284dcc307d60eb7b8fa42ebfa07ed85ae0200e98 Mon Sep 17 00:00:00 2001 From: bsanduc Date: Thu, 10 Oct 2024 15:55:45 +0300 Subject: [PATCH 10/12] Repurpose env vars and update card holder name usage in script --- docker/dev/.env.example | 3 ++- docker/dev/docker-compose.yml | 3 ++- docker/prod/.env.example | 3 ++- docker/prod/docker-compose.yml | 3 ++- packages/wallet/backend/src/card/types.ts | 3 +-- packages/wallet/backend/src/cardUsers.ts | 9 +++++---- packages/wallet/backend/src/config/env.ts | 6 +++++- 7 files changed, 19 insertions(+), 11 deletions(-) diff --git a/docker/dev/.env.example b/docker/dev/.env.example index 81c2c6766..18a2fd310 100644 --- a/docker/dev/.env.example +++ b/docker/dev/.env.example @@ -16,7 +16,8 @@ GATEHUB_SETTLEMENT_WALLET_ADDRESS= GATEHUB_CARD_APP_ID= GATEHUB_ACCOUNT_PRODUCT_CODE= GATEHUB_CARD_PRODUCT_CODE= -GATEHUB_NAME_ON_CARD_PREFIX= +GATEHUB_NAME_ON_CARD= +GATEHUB_CARD_PP_PREFIX= # commerce env variables # encoded base 64 private key diff --git a/docker/dev/docker-compose.yml b/docker/dev/docker-compose.yml index 3c1c8477f..87213603f 100644 --- a/docker/dev/docker-compose.yml +++ b/docker/dev/docker-compose.yml @@ -60,7 +60,8 @@ services: GATEHUB_CARD_APP_ID: ${GATEHUB_CARD_APP_ID} GATEHUB_ACCOUNT_PRODUCT_CODE: ${GATEHUB_ACCOUNT_PRODUCT_CODE} GATEHUB_CARD_PRODUCT_CODE: ${GATEHUB_CARD_PRODUCT_CODE} - GATEHUB_NAME_ON_CARD_PREFIX: ${GATEHUB_NAME_ON_CARD_PREFIX} + GATEHUB_NAME_ON_CARD: ${GATEHUB_NAME_ON_CARD} + GATEHUB_CARD_PP_PREFIX: ${GATEHUB_CARD_PP_PREFIX} restart: always networks: - testnet diff --git a/docker/prod/.env.example b/docker/prod/.env.example index 3606e1404..3944dcd66 100644 --- a/docker/prod/.env.example +++ b/docker/prod/.env.example @@ -37,7 +37,8 @@ WALLET_BACKEND_GATEHUB_SETTLEMENT_WALLET_ADDRESS= WALLET_BACKEND_GATEHUB_CARD_APP_ID= WALLET_BACKEND_GATEHUB_ACCOUNT_PRODUCT_CODE= WALLET_BACKEND_GATEHUB_CARD_PRODUCT_CODE= -WALLET_BACKEND_GATEHUB_NAME_ON_CARD_PREFIX= +WALLET_BACKEND_GATEHUB_NAME_ON_CARD= +WALLET_BACKEND_GATEHUB_CARD_PP_PREFIX= # BOUTIQUE BOUTIQUE_BACKEND_PORT= diff --git a/docker/prod/docker-compose.yml b/docker/prod/docker-compose.yml index b918556ef..444c03e84 100644 --- a/docker/prod/docker-compose.yml +++ b/docker/prod/docker-compose.yml @@ -72,7 +72,8 @@ services: GATEHUB_CARD_APP_ID: ${WALLET_BACKEND_GATEHUB_CARD_APP_ID} GATEHUB_ACCOUNT_PRODUCT_CODE: ${WALLET_BACKEND_GATEHUB_ACCOUNT_PRODUCT_CODE} GATEHUB_CARD_PRODUCT_CODE: ${WALLET_BACKEND_GATEHUB_CARD_PRODUCT_CODE} - GATEHUB_NAME_ON_CARD_PREFIX: ${WALLET_BACKEND_NAME_ON_CARD_PREFIX} + GATEHUB_NAME_ON_CARD: ${WALLET_BACKEND_GATEHUB_NAME_ON_CARD} + GATEHUB_CARD_PP_PREFIX: ${WALLET_BACKEND_GATEHUB_CARD_PP_PREFIX} networks: - testnet ports: diff --git a/packages/wallet/backend/src/card/types.ts b/packages/wallet/backend/src/card/types.ts index c1f7ae419..5edd54a51 100644 --- a/packages/wallet/backend/src/card/types.ts +++ b/packages/wallet/backend/src/card/types.ts @@ -1,7 +1,6 @@ import { CardLimitType } from '@wallet/shared/src' export type GateHubCardCurrency = 'EUR' -export type GateHubNameOnCard = 'INTERLEDGER' export interface ICardDetailsRequest { cardId: string @@ -30,7 +29,7 @@ export interface ICreateCustomerRequest { productCode: string } } - nameOnCard: GateHubNameOnCard + nameOnCard: string citizen: { name: string surname: string diff --git a/packages/wallet/backend/src/cardUsers.ts b/packages/wallet/backend/src/cardUsers.ts index a875954af..f1a8832bd 100644 --- a/packages/wallet/backend/src/cardUsers.ts +++ b/packages/wallet/backend/src/cardUsers.ts @@ -35,7 +35,8 @@ async function cardManagement() { const gateHubClient = container.resolve('gateHubClient') const accountProductCode = env.GATEHUB_ACCOUNT_PRODUCT_CODE const cardProductCode = env.GATEHUB_CARD_PRODUCT_CODE - const nameOnCardPrefix = env.GATEHUB_NAME_ON_CARD_PREFIX + const nameOnCard = env.GATEHUB_NAME_ON_CARD + const ppPrefix = env.GATEHUB_CARD_PP_PREFIX const GATEWAY_UUID = env.GATEHUB_GATEWAY_UUID try { @@ -56,7 +57,6 @@ async function cardManagement() { const user = await gateHubClient.getWalletForUser(managedUser.id) const walletAddress = user.wallets[0].address - const nameOnCard = nameOnCardPrefix + ppNumber logger.info(`Retrieved user ${managedUser.id} wallet - ${walletAddress}`) @@ -70,7 +70,7 @@ async function cardManagement() { productCode: cardProductCode } }, - nameOnCard: 'INTERLEDGER', + nameOnCard, citizen: { name: firstName, surname: lastName @@ -84,8 +84,9 @@ async function cardManagement() { logger.info(`Created customer for ${email}: ${customer.customers.id}`) + const pp = ppPrefix + ppNumber await gateHubClient.updateMetaForManagedUser(managedUser.id, { - paymentPointer: nameOnCard.split(' ')[1].toLowerCase(), + paymentPointer: pp.toLowerCase(), customerId: customer.customers.id! }) diff --git a/packages/wallet/backend/src/config/env.ts b/packages/wallet/backend/src/config/env.ts index 59e608b83..30f104b84 100644 --- a/packages/wallet/backend/src/config/env.ts +++ b/packages/wallet/backend/src/config/env.ts @@ -27,7 +27,11 @@ const envSchema = z.object({ .string() .default('GATEHUB_ACCOUNT_PRODUCT_CODE'), GATEHUB_CARD_PRODUCT_CODE: z.string().default('GATEHUB_CARD_PRODUCT_CODE'), - GATEHUB_NAME_ON_CARD_PREFIX: z.string().default('NAME_ON_CARD_PREFIX'), + GATEHUB_NAME_ON_CARD: z + .string() + .regex(/^[a-zA-Z0-9]*$/, 'Only alphanumeric characters are allowed') + .default('GATEHUB_NAME_ON_CARD'), + GATEHUB_CARD_PP_PREFIX: z.string().default('GATEHUB_GATEHUB_CARD_PP_PREFIX'), GRAPHQL_ENDPOINT: z.string().url().default('http://localhost:3011/graphql'), AUTH_GRAPHQL_ENDPOINT: z .string() From 974c8549d1d9cb54e36fb51ea9446066f791c72f Mon Sep 17 00:00:00 2001 From: bsanduc Date: Thu, 10 Oct 2024 16:02:52 +0300 Subject: [PATCH 11/12] Remove unused type --- packages/wallet/backend/src/card/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/wallet/backend/src/card/types.ts b/packages/wallet/backend/src/card/types.ts index 5edd54a51..80fa83c1a 100644 --- a/packages/wallet/backend/src/card/types.ts +++ b/packages/wallet/backend/src/card/types.ts @@ -206,7 +206,7 @@ export type CloseCardReason = | 'IssuerRequestCustomerDeceased' export interface ICreateCardRequest { - nameOnCard: GateHubNameOnCard + nameOnCard: string deliveryAddressId: string walletAddress: string currency: GateHubCardCurrency From 09d2d3dd199f12bea22ecf0c5910cca21c332d4d Mon Sep 17 00:00:00 2001 From: sanducb <167857039+sanducb@users.noreply.github.com> Date: Thu, 10 Oct 2024 16:21:03 +0300 Subject: [PATCH 12/12] Update default card holder name --- packages/wallet/backend/src/config/env.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/wallet/backend/src/config/env.ts b/packages/wallet/backend/src/config/env.ts index 30f104b84..c53b8583c 100644 --- a/packages/wallet/backend/src/config/env.ts +++ b/packages/wallet/backend/src/config/env.ts @@ -30,7 +30,7 @@ const envSchema = z.object({ GATEHUB_NAME_ON_CARD: z .string() .regex(/^[a-zA-Z0-9]*$/, 'Only alphanumeric characters are allowed') - .default('GATEHUB_NAME_ON_CARD'), + .default('INTERLEDGER'), GATEHUB_CARD_PP_PREFIX: z.string().default('GATEHUB_GATEHUB_CARD_PP_PREFIX'), GRAPHQL_ENDPOINT: z.string().url().default('http://localhost:3011/graphql'), AUTH_GRAPHQL_ENDPOINT: z