291 lines
7.0 KiB
TypeScript
291 lines
7.0 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 {
|
|
IBunqPaymentRequest,
|
|
IBunqPayment,
|
|
IBunqAmount,
|
|
IBunqAlias,
|
|
IBunqPaginationOptions
|
|
} from './bunq.interfaces.js';
|
|
|
|
export class BunqPayment {
|
|
private bunqAccount: BunqAccount;
|
|
private monetaryAccount: BunqMonetaryAccount;
|
|
private paymentData: IBunqPaymentRequest;
|
|
|
|
// Properties populated after creation
|
|
public id?: number;
|
|
public created?: string;
|
|
public updated?: string;
|
|
public status?: string;
|
|
|
|
constructor(
|
|
bunqAccount: BunqAccount,
|
|
monetaryAccount: BunqMonetaryAccount,
|
|
paymentData: IBunqPaymentRequest
|
|
) {
|
|
this.bunqAccount = bunqAccount;
|
|
this.monetaryAccount = monetaryAccount;
|
|
this.paymentData = paymentData;
|
|
}
|
|
|
|
/**
|
|
* Create the payment
|
|
*/
|
|
public async create(): Promise<number> {
|
|
await this.bunqAccount.apiContext.ensureValidSession();
|
|
|
|
const response = await this.bunqAccount.getHttpClient().post(
|
|
`/v1/user/${this.bunqAccount.userId}/monetary-account/${this.monetaryAccount.id}/payment`,
|
|
this.paymentData
|
|
);
|
|
|
|
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 payment');
|
|
}
|
|
|
|
/**
|
|
* Get payment details
|
|
*/
|
|
public async get(): Promise<IBunqPayment> {
|
|
if (!this.id) {
|
|
throw new Error('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}/payment/${this.id}`
|
|
);
|
|
|
|
if (response.Response && response.Response[0] && response.Response[0].Payment) {
|
|
return response.Response[0].Payment;
|
|
}
|
|
|
|
throw new Error('Payment not found');
|
|
}
|
|
|
|
/**
|
|
* List payments for a monetary account
|
|
*/
|
|
public static async list(
|
|
bunqAccount: BunqAccount,
|
|
monetaryAccountId: number,
|
|
options?: IBunqPaginationOptions
|
|
): Promise<IBunqPayment[]> {
|
|
await bunqAccount.apiContext.ensureValidSession();
|
|
|
|
const response = await bunqAccount.getHttpClient().list(
|
|
`/v1/user/${bunqAccount.userId}/monetary-account/${monetaryAccountId}/payment`,
|
|
options
|
|
);
|
|
|
|
const payments: IBunqPayment[] = [];
|
|
|
|
if (response.Response) {
|
|
for (const item of response.Response) {
|
|
if (item.Payment) {
|
|
payments.push(item.Payment);
|
|
}
|
|
}
|
|
}
|
|
|
|
return payments;
|
|
}
|
|
|
|
/**
|
|
* Create a payment builder
|
|
*/
|
|
public static builder(
|
|
bunqAccount: BunqAccount,
|
|
monetaryAccount: BunqMonetaryAccount
|
|
): PaymentBuilder {
|
|
return new PaymentBuilder(bunqAccount, monetaryAccount);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Builder class for creating payments
|
|
*/
|
|
export class PaymentBuilder {
|
|
private bunqAccount: BunqAccount;
|
|
private monetaryAccount: BunqMonetaryAccount;
|
|
private paymentData: Partial<IBunqPaymentRequest> = {};
|
|
|
|
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;
|
|
}
|
|
|
|
/**
|
|
* Set merchant reference
|
|
*/
|
|
public merchantReference(reference: string): this {
|
|
this.paymentData.merchant_reference = reference;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Set custom request ID (for idempotency)
|
|
*/
|
|
public customRequestId(requestId: string): this {
|
|
this.paymentData.request_reference_split_the_bill = requestId;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Allow bunq.to payments
|
|
*/
|
|
public allowBunqto(allow: boolean = true): this {
|
|
this.paymentData.allow_bunqto = allow;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Add attachments
|
|
*/
|
|
public attachments(attachmentIds: number[]): this {
|
|
this.paymentData.attachment = attachmentIds.map(id => ({ id }));
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Build and create the payment
|
|
*/
|
|
public async create(): Promise<BunqPayment> {
|
|
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');
|
|
}
|
|
|
|
const payment = new BunqPayment(
|
|
this.bunqAccount,
|
|
this.monetaryAccount,
|
|
this.paymentData as IBunqPaymentRequest
|
|
);
|
|
|
|
await payment.create();
|
|
return payment;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Batch payment class for creating multiple payments at once
|
|
*/
|
|
export class BunqBatchPayment {
|
|
private bunqAccount: BunqAccount;
|
|
private monetaryAccount: BunqMonetaryAccount;
|
|
private payments: IBunqPaymentRequest[] = [];
|
|
|
|
constructor(bunqAccount: BunqAccount, monetaryAccount: BunqMonetaryAccount) {
|
|
this.bunqAccount = bunqAccount;
|
|
this.monetaryAccount = monetaryAccount;
|
|
}
|
|
|
|
/**
|
|
* Add a payment to the batch
|
|
*/
|
|
public addPayment(payment: IBunqPaymentRequest): this {
|
|
this.payments.push(payment);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Create all payments in the batch
|
|
*/
|
|
public async create(): Promise<number> {
|
|
if (this.payments.length === 0) {
|
|
throw new Error('No payments in batch');
|
|
}
|
|
|
|
await this.bunqAccount.apiContext.ensureValidSession();
|
|
|
|
const response = await this.bunqAccount.getHttpClient().post(
|
|
`/v1/user/${this.bunqAccount.userId}/monetary-account/${this.monetaryAccount.id}/payment-batch`,
|
|
{
|
|
payments: this.payments
|
|
}
|
|
);
|
|
|
|
if (response.Response && response.Response[0] && response.Response[0].Id) {
|
|
return response.Response[0].Id.id;
|
|
}
|
|
|
|
throw new Error('Failed to create batch payment');
|
|
}
|
|
|
|
/**
|
|
* Get batch payment details
|
|
*/
|
|
public async get(batchId: 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}/payment-batch/${batchId}`
|
|
);
|
|
|
|
return response.Response;
|
|
}
|
|
} |