Files
bunq/ts/bunq.classes.request.ts
Juergen Kunz 193524f15c update
2025-07-18 10:31:12 +00:00

419 lines
11 KiB
TypeScript

import * as plugins from './bunq.plugins';
import { BunqAccount } from './bunq.classes.account';
import { BunqMonetaryAccount } from './bunq.classes.monetaryaccount';
import {
IBunqRequestInquiry,
IBunqAmount,
IBunqAlias,
IBunqPaginationOptions
} from './bunq.interfaces';
export class BunqRequestInquiry {
private bunqAccount: BunqAccount;
private monetaryAccount: BunqMonetaryAccount;
// Request properties
public id?: number;
public created?: string;
public updated?: string;
public timeResponded?: string;
public timeExpiry?: string;
public monetaryAccountId?: number;
public amountInquired?: IBunqAmount;
public amountResponded?: IBunqAmount;
public userAliasCreated?: IBunqAlias;
public userAliasRevoked?: IBunqAlias;
public counterpartyAlias?: IBunqAlias;
public description?: string;
public merchantReference?: string;
public status?: string;
public minimumAge?: number;
public requireAddress?: string;
public bunqmeShareUrl?: string;
public redirectUrl?: string;
constructor(bunqAccount: BunqAccount, monetaryAccount: BunqMonetaryAccount) {
this.bunqAccount = bunqAccount;
this.monetaryAccount = monetaryAccount;
}
/**
* Create a new request inquiry
*/
public async create(options: {
amountInquired: IBunqAmount;
counterpartyAlias: IBunqAlias;
description: string;
allowBunqme?: boolean;
merchantReference?: string;
status?: 'PENDING' | 'REVOKED';
minimumAge?: number;
requireAddress?: 'BILLING' | 'SHIPPING' | 'BILLING_SHIPPING';
wantTip?: boolean;
allowAmountLower?: boolean;
allowAmountHigher?: boolean;
redirectUrl?: string;
eventId?: number;
}): Promise<number> {
await this.bunqAccount.apiContext.ensureValidSession();
const requestData = {
amount_inquired: options.amountInquired,
counterparty_alias: options.counterpartyAlias,
description: options.description,
allow_bunqme: options.allowBunqme,
merchant_reference: options.merchantReference,
status: options.status,
minimum_age: options.minimumAge,
require_address: options.requireAddress,
want_tip: options.wantTip,
allow_amount_lower: options.allowAmountLower,
allow_amount_higher: options.allowAmountHigher,
redirect_url: options.redirectUrl,
event_id: options.eventId
};
const response = await this.bunqAccount.getHttpClient().post(
`/v1/user/${this.bunqAccount.userId}/monetary-account/${this.monetaryAccount.id}/request-inquiry`,
requestData
);
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 request inquiry');
}
/**
* Get request inquiry details
*/
public async get(): Promise<IBunqRequestInquiry> {
if (!this.id) {
throw new Error('Request inquiry 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}/request-inquiry/${this.id}`
);
if (response.Response && response.Response[0] && response.Response[0].RequestInquiry) {
const data = response.Response[0].RequestInquiry;
this.updateFromApiResponse(data);
return data;
}
throw new Error('Request inquiry not found');
}
/**
* Update request inquiry
*/
public async update(updates: {
status?: 'REVOKED';
amountInquired?: IBunqAmount;
description?: string;
}): Promise<void> {
if (!this.id) {
throw new Error('Request inquiry ID not set');
}
await this.bunqAccount.apiContext.ensureValidSession();
await this.bunqAccount.getHttpClient().put(
`/v1/user/${this.bunqAccount.userId}/monetary-account/${this.monetaryAccount.id}/request-inquiry/${this.id}`,
updates
);
// Refresh data
await this.get();
}
/**
* Revoke the request inquiry
*/
public async revoke(): Promise<void> {
await this.update({ status: 'REVOKED' });
}
/**
* List request inquiries for a monetary account
*/
public static async list(
bunqAccount: BunqAccount,
monetaryAccountId: number,
options?: IBunqPaginationOptions
): Promise<IBunqRequestInquiry[]> {
await bunqAccount.apiContext.ensureValidSession();
const response = await bunqAccount.getHttpClient().list(
`/v1/user/${bunqAccount.userId}/monetary-account/${monetaryAccountId}/request-inquiry`,
options
);
const requests: IBunqRequestInquiry[] = [];
if (response.Response) {
for (const item of response.Response) {
if (item.RequestInquiry) {
requests.push(item.RequestInquiry);
}
}
}
return requests;
}
/**
* Update properties from API response
*/
private updateFromApiResponse(data: any): void {
this.id = data.id;
this.created = data.created;
this.updated = data.updated;
this.timeResponded = data.time_responded;
this.timeExpiry = data.time_expiry;
this.monetaryAccountId = data.monetary_account_id;
this.amountInquired = data.amount_inquired;
this.amountResponded = data.amount_responded;
this.userAliasCreated = data.user_alias_created;
this.userAliasRevoked = data.user_alias_revoked;
this.counterpartyAlias = data.counterparty_alias;
this.description = data.description;
this.merchantReference = data.merchant_reference;
this.status = data.status;
this.minimumAge = data.minimum_age;
this.requireAddress = data.require_address;
this.bunqmeShareUrl = data.bunqme_share_url;
this.redirectUrl = data.redirect_url;
}
/**
* Create a builder for request inquiries
*/
public static builder(
bunqAccount: BunqAccount,
monetaryAccount: BunqMonetaryAccount
): RequestInquiryBuilder {
return new RequestInquiryBuilder(bunqAccount, monetaryAccount);
}
}
/**
* Builder class for creating request inquiries
*/
export class RequestInquiryBuilder {
private bunqAccount: BunqAccount;
private monetaryAccount: BunqMonetaryAccount;
private options: any = {};
constructor(bunqAccount: BunqAccount, monetaryAccount: BunqMonetaryAccount) {
this.bunqAccount = bunqAccount;
this.monetaryAccount = monetaryAccount;
}
/**
* Set the amount
*/
public amount(value: string, currency: string = 'EUR'): this {
this.options.amountInquired = { value, currency };
return this;
}
/**
* Set the counterparty by IBAN
*/
public fromIban(iban: string, name?: string): this {
this.options.counterpartyAlias = {
type: 'IBAN',
value: iban,
name
};
return this;
}
/**
* Set the counterparty by email
*/
public fromEmail(email: string, name?: string): this {
this.options.counterpartyAlias = {
type: 'EMAIL',
value: email,
name
};
return this;
}
/**
* Set the counterparty by phone number
*/
public fromPhoneNumber(phoneNumber: string, name?: string): this {
this.options.counterpartyAlias = {
type: 'PHONE_NUMBER',
value: phoneNumber,
name
};
return this;
}
/**
* Set the description
*/
public description(description: string): this {
this.options.description = description;
return this;
}
/**
* Allow bunq.me
*/
public allowBunqme(allow: boolean = true): this {
this.options.allowBunqme = allow;
return this;
}
/**
* Set merchant reference
*/
public merchantReference(reference: string): this {
this.options.merchantReference = reference;
return this;
}
/**
* Set minimum age requirement
*/
public minimumAge(age: number): this {
this.options.minimumAge = age;
return this;
}
/**
* Require address
*/
public requireAddress(type: 'BILLING' | 'SHIPPING' | 'BILLING_SHIPPING'): this {
this.options.requireAddress = type;
return this;
}
/**
* Allow tips
*/
public allowTips(allow: boolean = true): this {
this.options.wantTip = allow;
return this;
}
/**
* Allow lower amount
*/
public allowLowerAmount(allow: boolean = true): this {
this.options.allowAmountLower = allow;
return this;
}
/**
* Allow higher amount
*/
public allowHigherAmount(allow: boolean = true): this {
this.options.allowAmountHigher = allow;
return this;
}
/**
* Set redirect URL
*/
public redirectUrl(url: string): this {
this.options.redirectUrl = url;
return this;
}
/**
* Create the request inquiry
*/
public async create(): Promise<BunqRequestInquiry> {
if (!this.options.amountInquired) {
throw new Error('Amount is required');
}
if (!this.options.counterpartyAlias) {
throw new Error('Counterparty is required');
}
if (!this.options.description) {
throw new Error('Description is required');
}
const request = new BunqRequestInquiry(this.bunqAccount, this.monetaryAccount);
await request.create(this.options);
return request;
}
}
/**
* Request response class for responding to payment requests
*/
export class BunqRequestResponse {
private bunqAccount: BunqAccount;
private monetaryAccount: BunqMonetaryAccount;
constructor(bunqAccount: BunqAccount, monetaryAccount: BunqMonetaryAccount) {
this.bunqAccount = bunqAccount;
this.monetaryAccount = monetaryAccount;
}
/**
* Accept a request
*/
public async accept(
requestResponseId: number,
amountResponded?: IBunqAmount,
description?: string
): Promise<number> {
await this.bunqAccount.apiContext.ensureValidSession();
const response = await this.bunqAccount.getHttpClient().put(
`/v1/user/${this.bunqAccount.userId}/monetary-account/${this.monetaryAccount.id}/request-response/${requestResponseId}`,
{
amount_responded: amountResponded,
status: 'ACCEPTED',
description: description
}
);
if (response.Response && response.Response[0] && response.Response[0].Id) {
return response.Response[0].Id.id;
}
throw new Error('Failed to accept request');
}
/**
* Reject a request
*/
public async reject(requestResponseId: number): Promise<void> {
await this.bunqAccount.apiContext.ensureValidSession();
await this.bunqAccount.getHttpClient().put(
`/v1/user/${this.bunqAccount.userId}/monetary-account/${this.monetaryAccount.id}/request-response/${requestResponseId}`,
{
status: 'REJECTED'
}
);
}
/**
* List incoming payment requests
*/
public async listIncoming(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}/request-response`,
options
);
return response.Response || [];
}
}