398 lines
10 KiB
TypeScript
398 lines
10 KiB
TypeScript
import * as plugins from './bunq.plugins.js';
|
|
import { BunqAccount } from './bunq.classes.account.js';
|
|
import { BunqMonetaryAccount } from './bunq.classes.monetaryaccount.js';
|
|
import type {
|
|
IBunqScheduledPaymentRequest,
|
|
IBunqAmount,
|
|
IBunqAlias,
|
|
IBunqPaginationOptions
|
|
} from './bunq.interfaces.js';
|
|
|
|
export interface IScheduleOptions {
|
|
timeStart: string;
|
|
timeEnd?: string;
|
|
recurrenceUnit: 'ONCE' | 'HOURLY' | 'DAILY' | 'WEEKLY' | 'MONTHLY' | 'YEARLY';
|
|
recurrenceSize: number;
|
|
}
|
|
|
|
export class BunqScheduledPayment {
|
|
private bunqAccount: BunqAccount;
|
|
private monetaryAccount: BunqMonetaryAccount;
|
|
|
|
// Schedule properties
|
|
public id?: number;
|
|
public created?: string;
|
|
public updated?: string;
|
|
public status?: string;
|
|
|
|
constructor(bunqAccount: BunqAccount, monetaryAccount: BunqMonetaryAccount) {
|
|
this.bunqAccount = bunqAccount;
|
|
this.monetaryAccount = monetaryAccount;
|
|
}
|
|
|
|
/**
|
|
* Create a scheduled payment
|
|
*/
|
|
public async create(paymentData: IBunqScheduledPaymentRequest): Promise<number> {
|
|
await this.bunqAccount.apiContext.ensureValidSession();
|
|
|
|
const response = await this.bunqAccount.getHttpClient().post(
|
|
`/v1/user/${this.bunqAccount.userId}/monetary-account/${this.monetaryAccount.id}/schedule-payment`,
|
|
{
|
|
payment: {
|
|
amount: paymentData.amount,
|
|
counterparty_alias: paymentData.counterparty_alias,
|
|
description: paymentData.description,
|
|
attachment: paymentData.attachment,
|
|
merchant_reference: paymentData.merchant_reference,
|
|
allow_bunqto: paymentData.allow_bunqto
|
|
},
|
|
schedule: paymentData.schedule
|
|
}
|
|
);
|
|
|
|
if (response.Response && response.Response[0] && response.Response[0].Id) {
|
|
this.id = response.Response[0].Id.id;
|
|
return this.id;
|
|
}
|
|
|
|
throw new Error('Failed to create scheduled payment');
|
|
}
|
|
|
|
/**
|
|
* Get scheduled payment details
|
|
*/
|
|
public async get(): Promise<any> {
|
|
if (!this.id) {
|
|
throw new Error('Scheduled payment ID not set');
|
|
}
|
|
|
|
await this.bunqAccount.apiContext.ensureValidSession();
|
|
|
|
const response = await this.bunqAccount.getHttpClient().get(
|
|
`/v1/user/${this.bunqAccount.userId}/monetary-account/${this.monetaryAccount.id}/schedule-payment/${this.id}`
|
|
);
|
|
|
|
if (response.Response && response.Response[0]) {
|
|
return response.Response[0].SchedulePayment;
|
|
}
|
|
|
|
throw new Error('Scheduled payment not found');
|
|
}
|
|
|
|
/**
|
|
* Update scheduled payment
|
|
*/
|
|
public async update(updates: any): Promise<void> {
|
|
if (!this.id) {
|
|
throw new Error('Scheduled payment ID not set');
|
|
}
|
|
|
|
await this.bunqAccount.apiContext.ensureValidSession();
|
|
|
|
await this.bunqAccount.getHttpClient().put(
|
|
`/v1/user/${this.bunqAccount.userId}/monetary-account/${this.monetaryAccount.id}/schedule-payment/${this.id}`,
|
|
updates
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Cancel scheduled payment
|
|
*/
|
|
public async cancel(): Promise<void> {
|
|
if (!this.id) {
|
|
throw new Error('Scheduled payment ID not set');
|
|
}
|
|
|
|
await this.bunqAccount.apiContext.ensureValidSession();
|
|
|
|
await this.bunqAccount.getHttpClient().delete(
|
|
`/v1/user/${this.bunqAccount.userId}/monetary-account/${this.monetaryAccount.id}/schedule-payment/${this.id}`
|
|
);
|
|
}
|
|
|
|
/**
|
|
* List scheduled payments
|
|
*/
|
|
public static async list(
|
|
bunqAccount: BunqAccount,
|
|
monetaryAccountId: number,
|
|
options?: IBunqPaginationOptions
|
|
): Promise<any[]> {
|
|
await bunqAccount.apiContext.ensureValidSession();
|
|
|
|
const response = await bunqAccount.getHttpClient().list(
|
|
`/v1/user/${bunqAccount.userId}/monetary-account/${monetaryAccountId}/schedule-payment`,
|
|
options
|
|
);
|
|
|
|
return response.Response || [];
|
|
}
|
|
|
|
/**
|
|
* Create a builder for scheduled payments
|
|
*/
|
|
public static builder(
|
|
bunqAccount: BunqAccount,
|
|
monetaryAccount: BunqMonetaryAccount
|
|
): ScheduledPaymentBuilder {
|
|
return new ScheduledPaymentBuilder(bunqAccount, monetaryAccount);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Builder class for creating scheduled payments
|
|
*/
|
|
export class ScheduledPaymentBuilder {
|
|
private bunqAccount: BunqAccount;
|
|
private monetaryAccount: BunqMonetaryAccount;
|
|
private paymentData: Partial<IBunqScheduledPaymentRequest> = {};
|
|
|
|
constructor(bunqAccount: BunqAccount, monetaryAccount: BunqMonetaryAccount) {
|
|
this.bunqAccount = bunqAccount;
|
|
this.monetaryAccount = monetaryAccount;
|
|
}
|
|
|
|
/**
|
|
* Set the amount
|
|
*/
|
|
public amount(value: string, currency: string = 'EUR'): this {
|
|
this.paymentData.amount = { value, currency };
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Set the counterparty by IBAN
|
|
*/
|
|
public toIban(iban: string, name?: string): this {
|
|
this.paymentData.counterparty_alias = {
|
|
type: 'IBAN',
|
|
value: iban,
|
|
name
|
|
};
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Set the counterparty by email
|
|
*/
|
|
public toEmail(email: string, name?: string): this {
|
|
this.paymentData.counterparty_alias = {
|
|
type: 'EMAIL',
|
|
value: email,
|
|
name
|
|
};
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Set the counterparty by phone number
|
|
*/
|
|
public toPhoneNumber(phoneNumber: string, name?: string): this {
|
|
this.paymentData.counterparty_alias = {
|
|
type: 'PHONE_NUMBER',
|
|
value: phoneNumber,
|
|
name
|
|
};
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Set the description
|
|
*/
|
|
public description(description: string): this {
|
|
this.paymentData.description = description;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Schedule once at a specific time
|
|
*/
|
|
public scheduleOnce(timeStart: string): this {
|
|
this.paymentData.schedule = {
|
|
time_start: timeStart,
|
|
recurrence_unit: 'ONCE',
|
|
recurrence_size: 1
|
|
};
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Schedule hourly
|
|
*/
|
|
public scheduleHourly(timeStart: string, timeEnd?: string, every: number = 1): this {
|
|
this.paymentData.schedule = {
|
|
time_start: timeStart,
|
|
time_end: timeEnd,
|
|
recurrence_unit: 'HOURLY',
|
|
recurrence_size: every
|
|
};
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Schedule daily
|
|
*/
|
|
public scheduleDaily(timeStart: string, timeEnd?: string, every: number = 1): this {
|
|
this.paymentData.schedule = {
|
|
time_start: timeStart,
|
|
time_end: timeEnd,
|
|
recurrence_unit: 'DAILY',
|
|
recurrence_size: every
|
|
};
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Schedule weekly
|
|
*/
|
|
public scheduleWeekly(timeStart: string, timeEnd?: string, every: number = 1): this {
|
|
this.paymentData.schedule = {
|
|
time_start: timeStart,
|
|
time_end: timeEnd,
|
|
recurrence_unit: 'WEEKLY',
|
|
recurrence_size: every
|
|
};
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Schedule monthly
|
|
*/
|
|
public scheduleMonthly(timeStart: string, timeEnd?: string, every: number = 1): this {
|
|
this.paymentData.schedule = {
|
|
time_start: timeStart,
|
|
time_end: timeEnd,
|
|
recurrence_unit: 'MONTHLY',
|
|
recurrence_size: every
|
|
};
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Schedule yearly
|
|
*/
|
|
public scheduleYearly(timeStart: string, timeEnd?: string, every: number = 1): this {
|
|
this.paymentData.schedule = {
|
|
time_start: timeStart,
|
|
time_end: timeEnd,
|
|
recurrence_unit: 'YEARLY',
|
|
recurrence_size: every
|
|
};
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Set custom schedule
|
|
*/
|
|
public schedule(options: IScheduleOptions): this {
|
|
this.paymentData.schedule = {
|
|
time_start: options.timeStart,
|
|
time_end: options.timeEnd,
|
|
recurrence_unit: options.recurrenceUnit,
|
|
recurrence_size: options.recurrenceSize
|
|
};
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Create the scheduled payment
|
|
*/
|
|
public async create(): Promise<BunqScheduledPayment> {
|
|
if (!this.paymentData.amount) {
|
|
throw new Error('Amount is required');
|
|
}
|
|
if (!this.paymentData.counterparty_alias) {
|
|
throw new Error('Counterparty is required');
|
|
}
|
|
if (!this.paymentData.description) {
|
|
throw new Error('Description is required');
|
|
}
|
|
if (!this.paymentData.schedule) {
|
|
throw new Error('Schedule is required');
|
|
}
|
|
|
|
const scheduledPayment = new BunqScheduledPayment(this.bunqAccount, this.monetaryAccount);
|
|
await scheduledPayment.create(this.paymentData as IBunqScheduledPaymentRequest);
|
|
return scheduledPayment;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Scheduled instance class for managing individual occurrences
|
|
*/
|
|
export class BunqScheduledInstance {
|
|
private bunqAccount: BunqAccount;
|
|
private monetaryAccount: BunqMonetaryAccount;
|
|
private schedulePaymentId: number;
|
|
|
|
public id?: number;
|
|
public state?: string;
|
|
public timeStart?: string;
|
|
public timeEnd?: string;
|
|
public errorMessage?: string;
|
|
public scheduledPayment?: any;
|
|
public resultObject?: any;
|
|
|
|
constructor(
|
|
bunqAccount: BunqAccount,
|
|
monetaryAccount: BunqMonetaryAccount,
|
|
schedulePaymentId: number
|
|
) {
|
|
this.bunqAccount = bunqAccount;
|
|
this.monetaryAccount = monetaryAccount;
|
|
this.schedulePaymentId = schedulePaymentId;
|
|
}
|
|
|
|
/**
|
|
* List scheduled instances
|
|
*/
|
|
public async list(options?: IBunqPaginationOptions): Promise<any[]> {
|
|
await this.bunqAccount.apiContext.ensureValidSession();
|
|
|
|
const response = await this.bunqAccount.getHttpClient().list(
|
|
`/v1/user/${this.bunqAccount.userId}/monetary-account/${this.monetaryAccount.id}/schedule-payment/${this.schedulePaymentId}/schedule-instance`,
|
|
options
|
|
);
|
|
|
|
return response.Response || [];
|
|
}
|
|
|
|
/**
|
|
* Get a specific scheduled instance
|
|
*/
|
|
public async get(instanceId: number): Promise<any> {
|
|
await this.bunqAccount.apiContext.ensureValidSession();
|
|
|
|
const response = await this.bunqAccount.getHttpClient().get(
|
|
`/v1/user/${this.bunqAccount.userId}/monetary-account/${this.monetaryAccount.id}/schedule-payment/${this.schedulePaymentId}/schedule-instance/${instanceId}`
|
|
);
|
|
|
|
if (response.Response && response.Response[0]) {
|
|
return response.Response[0].ScheduleInstance;
|
|
}
|
|
|
|
throw new Error('Scheduled instance not found');
|
|
}
|
|
|
|
/**
|
|
* Update a scheduled instance
|
|
*/
|
|
public async update(instanceId: number, updates: any): Promise<void> {
|
|
await this.bunqAccount.apiContext.ensureValidSession();
|
|
|
|
await this.bunqAccount.getHttpClient().put(
|
|
`/v1/user/${this.bunqAccount.userId}/monetary-account/${this.monetaryAccount.id}/schedule-payment/${this.schedulePaymentId}/schedule-instance/${instanceId}`,
|
|
updates
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Cancel a scheduled instance
|
|
*/
|
|
public async cancel(instanceId: number): Promise<void> {
|
|
await this.update(instanceId, {
|
|
state: 'CANCELLED'
|
|
});
|
|
}
|
|
} |