import * as plugins from './bunq.plugins.js'; import { BunqAccount } from './bunq.classes.account.js'; import { BunqMonetaryAccount } from './bunq.classes.monetaryaccount.js'; import { 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 { 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 { 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 { 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 { 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 { 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 = {}; 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 { 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 { 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 { 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 { 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 { await this.update(instanceId, { state: 'CANCELLED' }); } }