Skip to content

Commit c5f3c45

Browse files
feat: Add support for non-catalog discounts (#191)
1 parent e00574b commit c5f3c45

File tree

7 files changed

+110
-1
lines changed

7 files changed

+110
-1
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ adding additional type guards.
2424

2525
### Added
2626

27-
- Added support for new payment methods `blik`, `mb_way`, `pix` and `upi`. See [related changelog](https://developer.paddle.com/changelog/2025/blik-mbway-payment-methods).
27+
- Added support for new payment methods `blik`, `mb_way`, `pix` and `upi`. See [related changelog](https://developer.paddle.com/changelog/2025/blik-mbway-payment-methods?utm_source=dx&utm_medium=paddle-node-sdk).
28+
- Non-catalog discounts on Transactions, see [changelog](https://developer.paddle.com/changelog/2025/custom-discounts?utm_source=dx&utm_medium=paddle-node-sdk)
2829
- Support `retained_fee` field on totals objects to show the fees retained by Paddle for the adjustment.
2930

3031
### Changed

src/__tests__/resources/transactions.test.ts

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import {
2424
ReviseTransactionRequestBody,
2525
TransactionsResource,
2626
UpdateTransactionRequestBody,
27+
NonCatalogDiscount,
28+
TransactionPreviewRequestBody,
2729
} from '../../resources/index.js';
2830
import { QueryParameters } from '../../internal/base/index.js';
2931
import { convertToSnakeCase } from '../../internal/index.js';
@@ -108,6 +110,33 @@ describe('TransactionsResource', () => {
108110
expect(convertToSnakeCase(CreateTransactionMock)).toEqual(CreateTransactionExpectation);
109111
});
110112

113+
test('create includes NonCatalogDiscount with custom_data and restrict_to', async () => {
114+
const paddleInstance = getPaddleTestClient();
115+
paddleInstance.post = jest.fn().mockResolvedValue(TransactionMockResponse);
116+
117+
const transactionsResource = new TransactionsResource(paddleInstance);
118+
119+
const discount: NonCatalogDiscount = {
120+
amount: '250',
121+
description: 'NCD for create',
122+
type: 'flat',
123+
recur: false,
124+
maximum_recurring_intervals: null,
125+
custom_data: { internal_reference: 'create_ref' },
126+
restrict_to: ['pri_123'],
127+
};
128+
129+
const body: CreateTransactionRequestBody = {
130+
...CreateTransactionMock,
131+
discountId: null,
132+
discount,
133+
};
134+
135+
await transactionsResource.create(body);
136+
137+
expect(paddleInstance.post).toHaveBeenCalledWith(`/transactions?`, body);
138+
});
139+
111140
test('should update an existing transaction', async () => {
112141
const transactionId = TransactionMock.id;
113142
const transactionToBeUpdated: UpdateTransactionRequestBody = UpdateTransactionMock;
@@ -123,6 +152,34 @@ describe('TransactionsResource', () => {
123152
expect(convertToSnakeCase(UpdateTransactionMock)).toEqual(UpdateTransactionExpectation);
124153
});
125154

155+
test('update includes NonCatalogDiscount with custom_data and restrict_to', async () => {
156+
const transactionId = TransactionMock.id;
157+
const paddleInstance = getPaddleTestClient();
158+
paddleInstance.patch = jest.fn().mockResolvedValue(TransactionMockResponse);
159+
160+
const transactionsResource = new TransactionsResource(paddleInstance);
161+
162+
const discount: NonCatalogDiscount = {
163+
amount: '300',
164+
description: 'NCD for update',
165+
type: 'percentage',
166+
recur: true,
167+
maximum_recurring_intervals: 5,
168+
custom_data: { internal_reference: 'update_ref' },
169+
restrict_to: ['pri_456', 'pri_789'],
170+
};
171+
172+
const body: UpdateTransactionRequestBody = {
173+
...UpdateTransactionMock,
174+
discountId: null,
175+
discount,
176+
};
177+
178+
await transactionsResource.update(transactionId, body);
179+
180+
expect(paddleInstance.patch).toHaveBeenCalledWith(`/transactions/${transactionId}?`, body);
181+
});
182+
126183
test('should get an link to download invoice PDF for an existing transaction', async () => {
127184
const transactionId = TransactionMock.id;
128185

@@ -147,6 +204,32 @@ describe('TransactionsResource', () => {
147204
expect(updatedTransaction).toBeDefined();
148205
});
149206

207+
test('preview accepts NonCatalogDiscount with custom_data and restrict_to', async () => {
208+
const paddleInstance = getPaddleTestClient();
209+
paddleInstance.post = jest.fn().mockResolvedValue(TransactionPreviewMockResponse);
210+
211+
const transactionsResource = new TransactionsResource(paddleInstance);
212+
213+
const discount: NonCatalogDiscount = {
214+
amount: '150',
215+
description: 'NCD for preview',
216+
type: 'flat',
217+
recur: false,
218+
maximum_recurring_intervals: null,
219+
custom_data: { internal_reference: 'preview_ref' },
220+
restrict_to: ['pri_123'],
221+
};
222+
223+
const body: TransactionPreviewRequestBody = {
224+
...PreviewTransactionMock,
225+
discount,
226+
};
227+
228+
await transactionsResource.preview(body);
229+
230+
expect(paddleInstance.post).toHaveBeenCalledWith(`/transactions/preview`, body);
231+
});
232+
150233
test('should be able to revise an existing transaction', async () => {
151234
const transactionId = TransactionMock.id;
152235
const transactionToBeRevised: ReviseTransactionRequestBody = ReviseTransactionMock;

src/resources/transactions/operations/create-transaction-request-body.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
type ITransactionsTimePeriod,
1313
} from '../../../types/index.js';
1414
import { type CollectionMode, type CurrencyCode, type TransactionStatus } from '../../../enums/index.js';
15+
import { NonCatalogDiscount } from './non-catalog-discount.js';
1516

1617
export interface CreateTransactionRequestBody {
1718
items: ITransactionItemWithNonCatalogPrice[];
@@ -26,4 +27,5 @@ export interface CreateTransactionRequestBody {
2627
billingDetails?: IBillingDetailsCreate | null;
2728
billingPeriod?: ITransactionsTimePeriod | null;
2829
checkout?: ITransactionCheckout;
30+
discount?: NonCatalogDiscount | null;
2931
}

src/resources/transactions/operations/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ export * from './update-transaction-request-body.js';
1313
export * from './transaction-preview-request-body.js';
1414
export * from './get-transaction-invoice-pdf-query-parameters.js';
1515
export * from './revise-transaction-request-body.js';
16+
export * from './non-catalog-discount.js';
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* ! Autogenerated code !
3+
* Do not make changes to this file.
4+
* Changes may be overwritten as part of auto-generation.
5+
*/
6+
7+
import { DiscountType } from '../../../enums/index.js';
8+
import { type ICustomData } from '../../../types/index.js';
9+
10+
export interface NonCatalogDiscount {
11+
amount: string;
12+
description: string;
13+
type: DiscountType;
14+
recur?: boolean;
15+
maximum_recurring_intervals?: number | null;
16+
custom_data?: ICustomData | null;
17+
restrict_to?: string[] | null;
18+
}

src/resources/transactions/operations/transaction-preview-request-body.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import { type CountryCode, type CurrencyCode } from '../../../enums/index.js';
88
import { type ITransactionItemPreviewRequest } from '../../../types/index.js';
9+
import { NonCatalogDiscount } from './non-catalog-discount.js';
910

1011
export interface IAddressPreviewResponse {
1112
postal_code?: string | null;
@@ -27,4 +28,5 @@ export interface TransactionPreviewRequestBody {
2728
customerIpAddress?: string | null;
2829
address?: IAddressPreview | null;
2930
ignoreTrials?: boolean | null;
31+
discount?: NonCatalogDiscount | null;
3032
}

src/resources/transactions/operations/update-transaction-request-body.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
type ITransactionItemWithNonCatalogPrice,
1313
type ITransactionsTimePeriod,
1414
} from '../../../types/index.js';
15+
import { NonCatalogDiscount } from './non-catalog-discount.js';
1516

1617
export interface UpdateTransactionRequestBody {
1718
status?: TransactionStatus;
@@ -26,4 +27,5 @@ export interface UpdateTransactionRequestBody {
2627
billingPeriod?: ITransactionsTimePeriod | null;
2728
items?: ITransactionItemWithNonCatalogPrice[];
2829
checkout?: ITransactionCheckout | null;
30+
discount?: NonCatalogDiscount | null;
2931
}

0 commit comments

Comments
 (0)