Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added terminal API endpoints #347

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@mollie/api-client",
"version": "3.7.0",
"version": "3.7.1",
"license": "BSD-3-Clause",
"description": "Official Mollie API client for Node",
"repository": {
Expand Down
6,264 changes: 6,264 additions & 0 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions src/binders/payments/parameters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,13 @@ export type CreateParameters = Pick<PaymentData, 'amount' | 'description' | 'red
* @see https://docs.mollie.com/reference/v2/payments-api/create-payment?path=customerReference#paysafecard
*/
customerReference?: string;
/**
* The unique identifier used for referring to a terminal. This ID is used for assigning the payment to a specific terminal and it can be retrieved via List terminals. For more information about
* point-of-sale payments, please check our guide [point-of-sale payments](https://docs.mollie.com/point-of-sale/overview).
*
* @see https://docs.mollie.com/reference/v2/payments-api/create-payment?path=terminalId#point-of-sale
*/
terminalId?: string;
/**
* Beneficiary name of the account holder. Only available if one-off payments are enabled on your account. Supplying this field will pre-fill the beneficiary name in the checkout screen.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type TransformingNetworkClient from '../../../communication/TransformingNetworkClient';
import {type IssuerData} from '../../../data/issuer/IssuerModel';
import { type IssuerData } from '../../../data/issuer/IssuerModel';
import type IssuerModel from '../../../data/issuer/IssuerModel';
import ApiError from '../../../errors/ApiError';
import renege from '../../../plumbing/renege';
Expand Down
47 changes: 47 additions & 0 deletions src/binders/terminals/TerminalsBinder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import type TransformingNetworkClient from '../../communication/TransformingNetworkClient';
import type Page from '../../data/page/Page';
import { type TerminalData } from '../../data/terminals/data';
import type Terminal from '../../data/terminals/Terminal';
import renege from '../../plumbing/renege';
import type Callback from '../../types/Callback';
import Binder from '../Binder';
import { type IterateParameters, type PageParameters } from './parameters';

const pathSegment = 'terminals';

export default class TerminalsBinder extends Binder<TerminalData, Terminal> {
constructor(protected readonly networkClient: TransformingNetworkClient) {
super();
}

/**
* @since 3.7.1
* @see https://docs.mollie.com/reference/v2/terminals-api/get-terminal
*/
public get(id: string): Promise<Terminal>;
public get(id: string, callback: Callback<Terminal>): void;
public get(id: string) {
if (renege(this, this.get, ...arguments)) return;
return this.networkClient.get<TerminalData, Terminal>(`${pathSegment}/${id}`);
}

/**
* @since 3.7.1
* @see https://docs.mollie.com/reference/v2/terminals-api/list-terminals
*/
public page(parameters?: PageParameters): Promise<Page<Terminal>>;
public page(parameters: PageParameters, callback: Callback<Page<Terminal>>): void;
public page(parameters: PageParameters = {}) {
if (renege(this, this.page, ...arguments)) return;
return this.networkClient.page<TerminalData, Terminal>(pathSegment, 'terminals', parameters).then(result => this.injectPaginationHelpers(result, this.page, parameters));
}

/**
* @since 3.7.1
* @see https://docs.mollie.com/reference/v2/terminals-api/list-terminals
*/
public iterate(parameters?: IterateParameters) {
const { valuesPerMinute, ...query } = parameters ?? {};
return this.networkClient.iterate<TerminalData, Terminal>(pathSegment, 'terminals', query, valuesPerMinute);
}
}
5 changes: 5 additions & 0 deletions src/binders/terminals/parameters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { type PaginationParameters, type ThrottlingParameter } from '../../types/parameters';

export type PageParameters = PaginationParameters;

export type IterateParameters = Omit<PageParameters, 'limit'> & ThrottlingParameter;
54 changes: 30 additions & 24 deletions src/createMollieClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,57 +6,59 @@ import TransformingNetworkClient, { Transformers } from './communication/Transfo
import type Options from './Options';

// Transformers
import { transform as transformPayment } from './data/payments/Payment';
import { transform as transformMethod } from './data/methods/Method';
import { transform as transformRefund } from './data/refunds/Refund';
import { transform as transformChargeback } from './data/chargebacks/Chargeback';
import { transform as transformCapture } from './data/payments/captures/Capture';
import { transform as transformCustomer } from './data/customers/Customer';
import { transform as transformMandate } from './data/customers/mandates/Mandate';
import { transform as transformSubscription } from './data/subscriptions/Subscription';
import { transform as transformIssuer } from './data/issuer/IssuerModel';
import { transform as transformMethod } from './data/methods/Method';
import { transform as transformOnboarding } from './data/onboarding/Onboarding';
import { transform as transformOrder } from './data/orders/Order';
import { transform as transformShipment } from './data/orders/shipments/Shipment';
import { transform as transformPermission } from './data/permissions/Permission';
import { transform as transformOrganization } from './data/organizations/Organizations';
import { transform as transformProfile } from './data/profiles/Profile';
import { transform as transformOnboarding } from './data/onboarding/Onboarding';
import { transform as transformPaymentLink } from './data/paymentLinks/PaymentLink';
import { transform as transformIssuer } from './data/issuer/IssuerModel';
import { transform as transformCapture } from './data/payments/captures/Capture';
import { transform as transformPayment } from './data/payments/Payment';
import { transform as transformPermission } from './data/permissions/Permission';
import { transform as transformProfile } from './data/profiles/Profile';
import { transform as transformRefund } from './data/refunds/Refund';
import { transform as transformSettlement } from './data/settlements/SettlementModel';
import { transform as transformSubscription } from './data/subscriptions/Subscription';
import { transform as transformTerminal } from './data/terminals/Terminal';

// Binders
import ApplePayBinder from './binders/applePay/ApplePayBinder';
import ChargebacksBinder from './binders/chargebacks/ChargebacksBinder';
import CustomersBinder from './binders/customers/CustomersBinder';
import CustomerMandatesBinder from './binders/customers/mandates/CustomerMandatesBinder';
import CustomerPaymentsBinder from './binders/customers/payments/CustomerPaymentsBinder';
import CustomersBinder from './binders/customers/CustomersBinder';
import CustomerSubscriptionsBinder from './binders/customers/subscriptions/CustomerSubscriptionsBinder';
import MethodsBinder from './binders/methods/MethodsBinder';
import OnboardingBinder from './binders/onboarding/OnboardingBinder';
import OrderLinesBinder from './binders/orders/orderlines/OrderLinesBinder';
import OrderPaymentsBinder from './binders/payments/orders/OrderPaymentsBinder';
import OrderRefundsBinder from './binders/refunds/orders/OrderRefundsBinder';
import OrdersBinder from './binders/orders/OrdersBinder';
import OrderShipmentsBinder from './binders/orders/shipments/OrderShipmentsBinder';
import OrganizationsBinder from './binders/organizations/OrganizationsBinder';
import PaymentLinksBinder from './binders/paymentLinks/PaymentLinksBinder';
import PaymentCapturesBinder from './binders/payments/captures/PaymentCapturesBinder';
import PaymentChargebacksBinder from './binders/payments/chargebacks/PaymentChargebacksBinder';
import PaymentLinksBinder from './binders/paymentLinks/PaymentLinksBinder';
import PaymentRefundsBinder from './binders/payments/refunds/PaymentRefundsBinder';
import OrderPaymentsBinder from './binders/payments/orders/OrderPaymentsBinder';
import PaymentsBinder from './binders/payments/PaymentsBinder';
import PaymentRefundsBinder from './binders/payments/refunds/PaymentRefundsBinder';
import PermissionsBinder from './binders/permissions/PermissionsBinder';
import ProfilesBinder from './binders/profiles/ProfilesBinder';
import ProfileMethodsBinder from './binders/profiles/methods/ProfileMethodsBinder';
import ProfileGiftcardIssuersBinder from './binders/profiles/giftcardIssuers/ProfileGiftcardIssuersBinder';
import ProfileMethodsBinder from './binders/profiles/methods/ProfileMethodsBinder';
import ProfilesBinder from './binders/profiles/ProfilesBinder';
import ProfileVoucherIssuersBinder from './binders/profiles/voucherIssuers/ProfileVoucherIssuersBinder';
import OrderRefundsBinder from './binders/refunds/orders/OrderRefundsBinder';
import RefundsBinder from './binders/refunds/RefundsBinder';
import SettlementPaymentsBinder from './binders/settlements/payments/SettlementPaymentsBinder';
import SettlementCapturesBinder from './binders/settlements/captures/SettlementCapturesBinder';
import SettlementRefundsBinder from './binders/settlements/refunds/SettlementRefundsBinder';
import SettlementChargebacksBinder from './binders/settlements/chargebacks/SettlementChargebacksBinder';
import SettlementPaymentsBinder from './binders/settlements/payments/SettlementPaymentsBinder';
import SettlementRefundsBinder from './binders/settlements/refunds/SettlementRefundsBinder';
import SettlementsBinder from './binders/settlements/SettlementsBinder';
import SubscriptionsBinder from './binders/subscriptions/SubscriptionsBinder';
import SubscriptionPaymentsBinder from './binders/subscriptions/payments/SubscriptionPaymentsBinder';
import SubscriptionsBinder from './binders/subscriptions/SubscriptionsBinder';
import TerminalsBinder from './binders/terminals/TerminalsBinder';

/**
* Create Mollie client.
Expand Down Expand Up @@ -95,7 +97,8 @@ export default function createMollieClient(options: Options) {
.add('onboarding', transformOnboarding)
.add('payment-link', transformPaymentLink)
.add('issuer', transformIssuer)
.add('settlement', transformSettlement),
.add('settlement', transformSettlement)
.add('terminal', transformTerminal),
);

return {
Expand Down Expand Up @@ -164,20 +167,23 @@ export default function createMollieClient(options: Options) {
settlementCaptures: new SettlementCapturesBinder(transformingNetworkClient),
settlementRefunds: new SettlementRefundsBinder(transformingNetworkClient),
settlementChargebacks: new SettlementChargebacksBinder(transformingNetworkClient),

// Terminals
terminals: new TerminalsBinder(transformingNetworkClient),
};
}

export { createMollieClient };

export { ApiMode, Locale, PaymentMethod, HistoricPaymentMethod, SequenceType } from './data/global';
export { CaptureEmbed } from './data/payments/captures/data';
export { MandateMethod, MandateStatus } from './data/customers/mandates/data';
export { ApiMode, HistoricPaymentMethod, Locale, PaymentMethod, SequenceType } from './data/global';
export { MethodImageSize, MethodInclude } from './data/methods/data';
export { OnboardingStatus } from './data/onboarding/data';
export { OrderEmbed, OrderStatus } from './data/orders/data';
export { OrderLineType } from './data/orders/orderlines/OrderLine';
export { CaptureEmbed } from './data/payments/captures/data';
export { PaymentEmbed, PaymentStatus } from './data/payments/data';
export { ProfileStatus } from './data/profiles/data';
export { RefundEmbed, RefundStatus } from './data/refunds/data';
export { SubscriptionStatus } from './data/subscriptions/data';
export { ProfileStatus } from './data/profiles/data';
export { OnboardingStatus } from './data/onboarding/data';
export { default as MollieApiError } from './errors/ApiError';
1 change: 1 addition & 0 deletions src/data/global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export enum PaymentMethod {
przelewy24 = 'przelewy24',
sofort = 'sofort',
voucher = 'voucher',
pointofsale = 'pointofsale',
}

export enum HistoricPaymentMethod {
Expand Down
1 change: 0 additions & 1 deletion src/data/methods/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ export enum MethodStatus {
rejected = 'rejected',
}


export enum MethodImageSize {
size1x = 'size1x',
size2x = 'size2x',
Expand Down
22 changes: 20 additions & 2 deletions src/data/payments/data.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
import type Nullable from '../../types/Nullable';
import { type ChargebackData } from '../chargebacks/Chargeback';
import { type Address, type Amount, type ApiMode, type CardAudience, type CardFailureReason, type CardLabel, type FeeRegion, type HistoricPaymentMethod, type Links, type Locale, type PaymentMethod, type SequenceType, type Url } from '../global';
import {
type Address,
type Amount,
type ApiMode,
type CardAudience,
type CardFailureReason,
type CardLabel,
type FeeRegion,
type HistoricPaymentMethod,
type Links,
type Locale,
type PaymentMethod,
type SequenceType,
type Url,
} from '../global';
import type Model from '../Model';
import { type RefundData } from '../refunds/data';
import { type CaptureData } from './captures/data'
import { type CaptureData } from './captures/data';

export interface PaymentData extends Model<'payment'> {
/**
Expand Down Expand Up @@ -324,6 +338,10 @@ interface PaymentLinks extends Links {
* @see https://docs.mollie.com/reference/v2/payments-api/get-payment?path=_links/order#response
*/
order?: Url;
/**
* The Dasboard URL of the payment.
*/
dashboard?: Url;
}

export interface BancontactDetails {
Expand Down
12 changes: 12 additions & 0 deletions src/data/terminals/Terminal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type TransformingNetworkClient from '../../communication/TransformingNetworkClient';
import type Seal from '../../types/Seal';
import { type TerminalData } from './data';
import TerminalHelper from './TerminalHelper';

type Terminal = Seal<Omit<TerminalData, '_links'>, TerminalHelper>;

export default Terminal;

export function transform(networkClient: TransformingNetworkClient, input: TerminalData): Terminal {
return Object.assign(Object.create(new TerminalHelper(networkClient, input._links)), input);
}
12 changes: 12 additions & 0 deletions src/data/terminals/TerminalHelper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type TransformingNetworkClient from '../../communication/TransformingNetworkClient';
import Helper from '../Helper';
import type Terminal from './Terminal';
import { type TerminalData } from './data';

export default class TerminalHelper extends Helper<TerminalData, Terminal> {
constructor(networkClient: TransformingNetworkClient, protected readonly links: TerminalData['_links']) {
super(networkClient, links);
}

// TODO: Wait for the _links.profile to be implemented in the API.
}
77 changes: 77 additions & 0 deletions src/data/terminals/data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { type Links } from '../global';
import type Model from '../Model';

export interface TerminalData extends Model<'terminal'> {
/**
* The profile the terminal is registered on, for example `pfl_v9hTwCvYqw`.
*
* @see https://docs.mollie.com/reference/v2/terminals-api/get-terminal?path=profileId#response
*/
profileId: string;
/**
* The status of the Terminal.
*
* Possible values:
* - `pending` The terminal device has been linked to your account, but has not yet been activated.
* This is the first state that the terminal gets, as soon as it’s ordered from us and assigned to your account.
* - `active` The terminal is fully configured and ready to accept payments.
* As soon as we configure the terminal for you, it will be moved to this state.
* - `inactive` The terminal has been deactivated, which can mean that you returned the device to us,
* or you requested to move it to another profile or organization.
*
* @see https://docs.mollie.com/reference/v2/terminals-api/get-terminal?path=status#response
*/
status: 'pending' | 'active' | 'inactive';
/**
* The brand of the terminal. For example, ‘PAX’.
*
* @see https://docs.mollie.com/reference/v2/terminals-api/get-terminal?path=brand#response
*/
brand: string;
/**
* The model of the terminal. For example for a PAX A920, this field’s value will be ‘A920’.
*
* @see https://docs.mollie.com/reference/v2/terminals-api/get-terminal?path=model#response
*/
model: string;
/**
* The serial number of the terminal. The serial number is provided at terminal creation time.
*
* @see https://docs.mollie.com/reference/v2/terminals-api/get-terminal?path=serialNumber#response
*/
serialNumber: string;
/**
* The currency which is set for the terminal, in [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) format.
* Please take into consideration that currently our terminals are bound to a specific currency, chosen during setup.
*
* @see https://docs.mollie.com/reference/v2/terminals-api/get-terminal?path=currency#response
*/
currency: string;
/**
* A short description of the terminal. The description can be used as an identifier for the terminal.
* Currently, the description is set when the terminal is initially configured. It will be visible in the dashboard as well as on the device itself.
*
* @see https://docs.mollie.com/reference/v2/terminals-api/get-terminal?path=description#response
*/
description: string;
/**
* The date on which the terminal was created, in [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) format.
*
* @see https://docs.mollie.com/reference/v2/terminals-api/get-terminal?path=createdAt#response
*/
createdAt: string;
/**
* The date on which the terminal had its last status change, in [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) format.
*
* @see https://docs.mollie.com/reference/v2/terminals-api/get-terminal?path=createdAt#response
*/
updatedAt: string;
/**
* An object with several URL objects relevant to the terminal. Every URL object will contain an `href` and a `type` field.
*
* @see https://docs.mollie.com/reference/v2/terminals-api/get-terminal?path=_links#response
*/
_links: TerminalLinks;
}

type TerminalLinks = Links;
23 changes: 23 additions & 0 deletions tests/integration/terminals.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import axios from 'axios';
import dotenv from 'dotenv';
import createMollieClient from '../..';

/**
* Overwrite the default XMLHttpRequestAdapter
*/
axios.defaults.adapter = 'http';

/**
* Load the API_KEY environment variable
*/
dotenv.config();

const mollieClient = createMollieClient({ apiKey: process.env.API_KEY });

describe('terminals', () => {
it('should list', async () => {
const terminals = await mollieClient.terminals.page();

expect(terminals).toBeDefined();
});
});
4 changes: 2 additions & 2 deletions tests/unit/resources/methods.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ describe('methods', () => {
mock.onGet(`/methods/${methodId}`).reply(200, response._embedded.methods[0], {});
mock.onGet('/methods/foo').reply(500, error, {});

it('should return a method instance', () =>
it('should return a method instance', () =>
methods.get(methodId).then(result => {
expect(result).toMatchSnapshot();
}));
Expand All @@ -35,7 +35,7 @@ describe('methods', () => {
});
});

it('should throw an error for non-existent IDs', () =>
it('should throw an error for non-existent IDs', () =>
methods
.get('foo')
.then(result => expect(result).toBeUndefined())
Expand Down