Files
bunq/ts/bunq.classes.card.ts

259 lines
6.9 KiB
TypeScript

import * as plugins from './bunq.plugins.js';
import { BunqAccount } from './bunq.classes.account.js';
import type { IBunqCard, IBunqAmount } from './bunq.interfaces.js';
export class BunqCard {
private bunqAccount: BunqAccount;
// Card properties
public id: number;
public created: string;
public updated: string;
public publicUuid: string;
public type: 'MAESTRO' | 'MASTERCARD';
public subType: string;
public secondLine: string;
public status: string;
public orderStatus?: string;
public expiryDate?: string;
public nameOnCard: string;
public primaryAccountNumberFourDigit?: string;
public limit?: IBunqAmount;
public monetaryAccountIdFallback?: number;
public country?: string;
constructor(bunqAccount: BunqAccount, cardData?: any) {
this.bunqAccount = bunqAccount;
if (cardData) {
this.updateFromApiResponse(cardData);
}
}
/**
* Update card properties from API response
*/
private updateFromApiResponse(cardData: any): void {
this.id = cardData.id;
this.created = cardData.created;
this.updated = cardData.updated;
this.publicUuid = cardData.public_uuid;
this.type = cardData.type;
this.subType = cardData.sub_type;
this.secondLine = cardData.second_line;
this.status = cardData.status;
this.orderStatus = cardData.order_status;
this.expiryDate = cardData.expiry_date;
this.nameOnCard = cardData.name_on_card;
this.primaryAccountNumberFourDigit = cardData.primary_account_number_four_digit;
this.limit = cardData.limit;
this.monetaryAccountIdFallback = cardData.monetary_account_id_fallback;
this.country = cardData.country;
}
/**
* List all cards for the user
*/
public static async list(bunqAccount: BunqAccount): Promise<BunqCard[]> {
await bunqAccount.apiContext.ensureValidSession();
const response = await bunqAccount.getHttpClient().list(
`/v1/user/${bunqAccount.userId}/card`
);
const cards: BunqCard[] = [];
if (response.Response) {
for (const item of response.Response) {
if (item.CardDebit || item.CardCredit) {
const cardData = item.CardDebit || item.CardCredit;
cards.push(new BunqCard(bunqAccount, cardData));
}
}
}
return cards;
}
/**
* Get a specific card
*/
public static async get(bunqAccount: BunqAccount, cardId: number): Promise<BunqCard> {
await bunqAccount.apiContext.ensureValidSession();
const response = await bunqAccount.getHttpClient().get(
`/v1/user/${bunqAccount.userId}/card/${cardId}`
);
if (response.Response && response.Response[0]) {
const cardData = response.Response[0].CardDebit || response.Response[0].CardCredit;
return new BunqCard(bunqAccount, cardData);
}
throw new Error('Card not found');
}
/**
* Update card settings
*/
public async update(updates: any): Promise<void> {
// Check if this is a dangerous operation
if ((updates.status === 'CANCELLED' || updates.status === 'BLOCKED') &&
!this.bunqAccount.options.dangerousOperations) {
throw new Error('Dangerous operations are not enabled. Initialize the BunqAccount with dangerousOperations: true to allow cancelling or blocking cards.');
}
await this.bunqAccount.apiContext.ensureValidSession();
const cardType = this.type === 'MASTERCARD' ? 'CardCredit' : 'CardDebit';
await this.bunqAccount.getHttpClient().put(
`/v1/user/${this.bunqAccount.userId}/card/${this.id}`,
{
[cardType]: updates
}
);
// Refresh card data
const updatedCard = await BunqCard.get(this.bunqAccount, this.id);
this.updateFromApiResponse(updatedCard);
}
/**
* Activate the card
*/
public async activate(activationCode: string, cardStatus: string = 'ACTIVE'): Promise<void> {
await this.update({
activation_code: activationCode,
status: cardStatus
});
}
/**
* Block the card
*/
public async block(reason: string = 'LOST'): Promise<void> {
await this.update({
status: 'BLOCKED',
cancellation_reason: reason
});
}
/**
* Cancel the card
*/
public async cancel(reason: string = 'USER_REQUEST'): Promise<void> {
await this.update({
status: 'CANCELLED',
cancellation_reason: reason
});
}
/**
* Update spending limit
*/
public async updateLimit(value: string, currency: string = 'EUR'): Promise<void> {
await this.update({
monetary_account_id: this.monetaryAccountIdFallback,
limit: {
value,
currency
}
});
}
/**
* Update PIN code
*/
public async updatePin(pinCode: string): Promise<void> {
await this.bunqAccount.apiContext.ensureValidSession();
await this.bunqAccount.getHttpClient().put(
`/v1/user/${this.bunqAccount.userId}/card/${this.id}/pin-change`,
{
pin_code: pinCode
}
);
}
/**
* Get card limits
*/
public async getLimits(): Promise<any> {
await this.bunqAccount.apiContext.ensureValidSession();
const response = await this.bunqAccount.getHttpClient().list(
`/v1/user/${this.bunqAccount.userId}/limit`
);
return response.Response || [];
}
/**
* Update mag stripe permissions
*/
public async updateMagStripePermission(expiryTime?: string): Promise<void> {
await this.update({
mag_stripe_permission: {
expiry_time: expiryTime
}
});
}
/**
* Update country permissions
*/
public async updateCountryPermissions(permissions: Array<{country: string, expiryTime?: string}>): Promise<void> {
await this.update({
country_permission: permissions
});
}
/**
* Link card to monetary account
*/
public async linkToAccount(monetaryAccountId: number): Promise<void> {
await this.update({
monetary_account_id: monetaryAccountId
});
}
/**
* Order a new card
*/
public static async order(
bunqAccount: BunqAccount,
options: {
secondLine: string;
nameOnCard: string;
type?: 'MAESTRO' | 'MASTERCARD';
productType?: string;
monetaryAccountId?: number;
}
): Promise<BunqCard> {
await bunqAccount.apiContext.ensureValidSession();
const cardData = {
second_line: options.secondLine,
name_on_card: options.nameOnCard,
type: options.type || 'MASTERCARD',
product_type: options.productType || 'MASTERCARD_DEBIT',
monetary_account_id: options.monetaryAccountId
};
const cardType = options.type === 'MASTERCARD' ? 'CardCredit' : 'CardDebit';
const response = await bunqAccount.getHttpClient().post(
`/v1/user/${bunqAccount.userId}/card`,
{
[cardType]: cardData
}
);
if (response.Response && response.Response[0] && response.Response[0].Id) {
return BunqCard.get(bunqAccount, response.Response[0].Id.id);
}
throw new Error('Failed to order card');
}
}