import * as plugins from './bunq.plugins.js'; import { BunqAccount } from './bunq.classes.account.js'; import { BunqMonetaryAccount } from './bunq.classes.monetaryaccount.js'; import { BunqPayment } from './bunq.classes.payment.js'; import type { IBunqAmount, IBunqAlias, IBunqSchedulePayment, IBunqSchedule } from './bunq.interfaces.js'; export interface ISchedulePaymentOptions { payment: { amount: IBunqAmount; counterparty_alias: IBunqAlias; description: string; attachment_id?: number; merchant_reference?: string; }; schedule: { time_start: string; time_end: string; recurrence_unit: 'ONCE' | 'HOURLY' | 'DAILY' | 'WEEKLY' | 'MONTHLY' | 'YEARLY'; recurrence_size: number; }; } export class BunqSchedulePayment { private bunqAccount: BunqAccount; constructor(bunqAccount: BunqAccount) { this.bunqAccount = bunqAccount; } /** * Create a scheduled payment */ public async create( monetaryAccount: BunqMonetaryAccount, options: ISchedulePaymentOptions ): Promise { await this.bunqAccount.apiContext.ensureValidSession(); const response = await this.bunqAccount.getHttpClient().post( `/v1/user/${this.bunqAccount.userId}/monetary-account/${monetaryAccount.id}/schedule-payment`, options ); if (response.Response && response.Response[0] && response.Response[0].Id) { return response.Response[0].Id.id; } throw new Error('Failed to create scheduled payment'); } /** * Get scheduled payment details */ public async get( monetaryAccount: BunqMonetaryAccount, scheduleId: number ): Promise { await this.bunqAccount.apiContext.ensureValidSession(); const response = await this.bunqAccount.getHttpClient().get( `/v1/user/${this.bunqAccount.userId}/monetary-account/${monetaryAccount.id}/schedule-payment/${scheduleId}` ); if (response.Response && response.Response[0] && response.Response[0].SchedulePayment) { return response.Response[0].SchedulePayment; } throw new Error('Scheduled payment not found'); } /** * List scheduled payments */ public async list( monetaryAccount: BunqMonetaryAccount, options?: { count?: number; older_id?: number; newer_id?: number; } ): Promise { await this.bunqAccount.apiContext.ensureValidSession(); const params = { count: options?.count || 10, older_id: options?.older_id, newer_id: options?.newer_id }; const response = await this.bunqAccount.getHttpClient().list( `/v1/user/${this.bunqAccount.userId}/monetary-account/${monetaryAccount.id}/schedule-payment`, params ); const schedules: IBunqSchedulePayment[] = []; if (response.Response) { for (const item of response.Response) { if (item.SchedulePayment) { schedules.push(item.SchedulePayment); } } } return schedules; } /** * Update scheduled payment */ public async update( monetaryAccount: BunqMonetaryAccount, scheduleId: number, updates: Partial ): Promise { await this.bunqAccount.apiContext.ensureValidSession(); await this.bunqAccount.getHttpClient().put( `/v1/user/${this.bunqAccount.userId}/monetary-account/${monetaryAccount.id}/schedule-payment/${scheduleId}`, updates ); } /** * Delete (cancel) scheduled payment */ public async delete( monetaryAccount: BunqMonetaryAccount, scheduleId: number ): Promise { await this.bunqAccount.apiContext.ensureValidSession(); await this.bunqAccount.getHttpClient().delete( `/v1/user/${this.bunqAccount.userId}/monetary-account/${monetaryAccount.id}/schedule-payment/${scheduleId}` ); } /** * Create a builder for scheduled payments */ public static builder( bunqAccount: BunqAccount, monetaryAccount: BunqMonetaryAccount ): SchedulePaymentBuilder { return new SchedulePaymentBuilder(bunqAccount, monetaryAccount); } } /** * Builder for creating scheduled payments */ export class SchedulePaymentBuilder { private bunqAccount: BunqAccount; private monetaryAccount: BunqMonetaryAccount; private paymentData: any = {}; private scheduleData: any = {}; constructor(bunqAccount: BunqAccount, monetaryAccount: BunqMonetaryAccount) { this.bunqAccount = bunqAccount; this.monetaryAccount = monetaryAccount; } /** * Set payment amount */ public amount(value: string, currency: string): SchedulePaymentBuilder { this.paymentData.amount = { value, currency }; return this; } /** * Set recipient by IBAN */ public toIban(iban: string, name?: string): SchedulePaymentBuilder { this.paymentData.counterparty_alias = { type: 'IBAN', value: iban, name: name || iban }; return this; } /** * Set recipient by email */ public toEmail(email: string, name?: string): SchedulePaymentBuilder { this.paymentData.counterparty_alias = { type: 'EMAIL', value: email, name: name || email }; return this; } /** * Set payment description */ public description(description: string): SchedulePaymentBuilder { this.paymentData.description = description; return this; } /** * Schedule once at specific time */ public scheduleOnce(dateTime: string): SchedulePaymentBuilder { this.scheduleData = { time_start: dateTime, time_end: dateTime, recurrence_unit: 'ONCE', recurrence_size: 1 }; return this; } /** * Schedule daily */ public scheduleDaily(startDate: string, endDate: string): SchedulePaymentBuilder { this.scheduleData = { time_start: startDate, time_end: endDate, recurrence_unit: 'DAILY', recurrence_size: 1 }; return this; } /** * Schedule weekly */ public scheduleWeekly(startDate: string, endDate: string, interval: number = 1): SchedulePaymentBuilder { this.scheduleData = { time_start: startDate, time_end: endDate, recurrence_unit: 'WEEKLY', recurrence_size: interval }; return this; } /** * Schedule monthly */ public scheduleMonthly(startDate: string, endDate: string, dayOfMonth?: number): SchedulePaymentBuilder { this.scheduleData = { time_start: startDate, time_end: endDate, recurrence_unit: 'MONTHLY', recurrence_size: 1 }; return this; } /** * Create the scheduled payment */ public async create(): Promise { if (!this.paymentData.amount || !this.paymentData.counterparty_alias || !this.paymentData.description) { throw new Error('Incomplete payment data'); } if (!this.scheduleData.time_start || !this.scheduleData.recurrence_unit) { throw new Error('Incomplete schedule data'); } const schedulePayment = new BunqSchedulePayment(this.bunqAccount); return schedulePayment.create(this.monetaryAccount, { payment: this.paymentData, schedule: this.scheduleData }); } }