Files
bunq/ts/bunq.classes.schedule.ts
Juergen Kunz f530fa639a update
2025-07-18 11:33:13 +00:00

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'
});
}
}