Skip to content

Commit

Permalink
feat(API Sync): Added Get Credit note and Subscription update with no…
Browse files Browse the repository at this point in the history
…n catalog price (#43)
  • Loading branch information
vijayasingam-paddle authored Sep 16, 2024
1 parent 7b77e4e commit c7688e4
Show file tree
Hide file tree
Showing 26 changed files with 208 additions and 16 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,22 @@ When we make [non-breaking changes](https://developer.paddle.com/api-reference/a

This means when upgrading minor versions of the SDK, you may notice type errors. You can safely ignore these or fix by adding additional type guards.

## 1.6.0 - 2024-09-16

### Added

- Added `adjustments.getCreditNotePDF()` to [get a credit note for an adjustment](https://developer.paddle.com/api-reference/adjustments/get-credit-note-pdf?utm_source=dx&utm_medium=paddle-node-sdk)
- Added `disposition` query parameter to `adjustments.getCreditNotePDF()` and `transactions.getInvoicePDF()` operations, see [related changelog](https://developer.paddle.com/changelog/2024/invoice-pdf-open-in-browser?utm_source=dx&utm_medium=paddle-node-sdk).
- Added pagination support to `notificationSettings.list()` operation, see [related changelog](https://developer.paddle.com/changelog/2024/notification-settings-pagination?utm_source=dx&utm_medium=paddle-node-sdk).
- Added support for Non-catalog products and prices to the `subscriptions.update()` and `subscriptions.previewUpdate()` operations, see [related changelog](https://developer.paddle.com/changelog/2024/add-custom-items-subscription?utm_source=dx&utm_medium=paddle-node-sdk).

### Fixed

- Marked `notification_id` as optional in `IEventsResponse` interface.
- Fixed a bug where query parameters with false values were not passed correctly to the API.

---

## 1.5.1 - 2024-09-10

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@paddle/paddle-node-sdk",
"version": "1.5.1",
"version": "1.6.0",
"description": "A Node.js SDK that you can use to integrate Paddle Billing with applications written in server-side JavaScript.",
"main": "./dist/cjs/index.js",
"module": "./dist/esm/index.js",
Expand Down
14 changes: 14 additions & 0 deletions src/__tests__/resources/adjustments.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import { AdjustmentsResource, ListAdjustmentQueryParameters } from '../../resources';
import { getPaddleTestClient } from '../helpers/test-client';
import {
AdjustmentMock,
AdjustmentMockResponse,
CreateAdjustmentExpectation,
CreateAdjustmentMock,
Expand Down Expand Up @@ -61,4 +62,17 @@ describe('AdjustmentsResource', () => {

expect(convertToSnakeCase(CreateAdjustmentMock)).toEqual(CreateAdjustmentExpectation);
});

test('should get an link to download credit note PDF for an adjustment', async () => {
const adjustmentId = AdjustmentMock.id;

const paddleInstance = getPaddleTestClient();
paddleInstance.get = jest.fn().mockResolvedValue(AdjustmentMockResponse);

const adjustmentResponse = new AdjustmentsResource(paddleInstance);
const creditNotePDF = await adjustmentResponse.getCreditNotePDF(adjustmentId);

expect(paddleInstance.get).toBeCalledWith(`/adjustments/${adjustmentId}/credit-note?`);
expect(creditNotePDF).toBeDefined();
});
});
2 changes: 1 addition & 1 deletion src/__tests__/resources/notification-settings.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ describe('NotificationSettingsResource', () => {
const notificationsResource = new NotificationSettingsResource(paddleInstance);
const notifications = await notificationsResource.list();

expect(paddleInstance.get).toBeCalledWith('/notification-settings');
expect(paddleInstance.get).toBeCalledWith('/notification-settings?');
expect(notifications.length).toBe(1);
});

Expand Down
15 changes: 15 additions & 0 deletions src/__tests__/resources/subscriptions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,21 @@ describe('SubscriptionsResource', () => {
expect(convertToSnakeCase(UpdateSubscriptionMock)).toEqual(UpdateSubscriptionExpectation);
});

test('should update an existing subscription with non-catalog price', async () => {
const subscriptionId = SubscriptionMock.id;
const subscriptionToBeUpdated: UpdateSubscriptionRequestBody = UpdateSubscriptionMock;

const paddleInstance = getPaddleTestClient();
paddleInstance.patch = jest.fn().mockResolvedValue(SubscriptionMockResponse);

const subscriptionsResource = new SubscriptionsResource(paddleInstance);
const updatedSubscription = await subscriptionsResource.update(subscriptionId, subscriptionToBeUpdated);

expect(paddleInstance.patch).toBeCalledWith(`/subscriptions/${subscriptionId}`, subscriptionToBeUpdated);
expect(updatedSubscription).toBeDefined();
expect(convertToSnakeCase(UpdateSubscriptionMock)).toEqual(UpdateSubscriptionExpectation);
});

test('should preview update an existing subscription', async () => {
const subscriptionId = SubscriptionMock.id;
const subscriptionToBeUpdated: UpdateSubscriptionRequestBody = UpdateSubscriptionMock;
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/resources/transactions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ describe('TransactionsResource', () => {
const transactionsResource = new TransactionsResource(paddleInstance);
const updatedTransaction = await transactionsResource.getInvoicePDF(transactionId);

expect(paddleInstance.get).toBeCalledWith(`/transactions/${transactionId}/invoice`);
expect(paddleInstance.get).toBeCalledWith(`/transactions/${transactionId}/invoice?`);
expect(updatedTransaction).toBeDefined();
});

Expand Down
15 changes: 15 additions & 0 deletions src/entities/adjustment/adjustment-credit-note-pdf.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* ! Autogenerated code !
* Do not make changes to this file.
* Changes may be overwritten as part of auto-generation.
*/

import { type IAdjustmentCreditNotePDF } from '../../types';

export class AdjustmentCreditNotePDF {
public readonly url: string;

constructor(adjustment: IAdjustmentCreditNotePDF) {
this.url = adjustment.url;
}
}
1 change: 1 addition & 0 deletions src/entities/adjustment/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ export * from './adjustment-item';
export * from './adjustment';
export * from './adjustment-collection';
export * from './adjustment-item-totals';
export * from './adjustment-credit-note-pdf';
7 changes: 7 additions & 0 deletions src/enums/shared/disposition.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* ! Autogenerated code !
* Do not make changes to this file.
* Changes may be overwritten as part of auto-generation.
*/

export type Disposition = 'attachment' | 'inline';
1 change: 1 addition & 0 deletions src/enums/shared/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ export * from './error-code';
export * from './payment-type';
export * from './catalog-type';
export * from './available-payment-methods';
export * from './disposition';
6 changes: 5 additions & 1 deletion src/internal/base/query-parameters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,17 @@ function convertCamelCaseToSnakeCase(input: string) {
});
}

function isValidValue<T>(value: T[Extract<keyof T, string>]) {
return value !== undefined && value !== null && value !== '';
}

export class QueryParameters<T> {
constructor(private readonly queryParameters: T) {}
public toQueryString(): string {
const urlSearchParam = new URLSearchParams();
for (const key in this.queryParameters) {
const value = this.queryParameters[key];
if (key && value) {
if (key && isValidValue<T>(value)) {
urlSearchParam.append(convertCamelCaseToSnakeCase(key), `${value}`);
}
}
Expand Down
30 changes: 27 additions & 3 deletions src/resources/adjustments/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,20 @@
* Changes may be overwritten as part of auto-generation.
*/

import { AdjustmentCollection, Adjustment } from '../../entities';
import { Adjustment, AdjustmentCollection, AdjustmentCreditNotePDF } from '../../entities';
import { type ErrorResponse, type Response } from '../../internal';
import { BaseResource, QueryParameters } from '../../internal/base';
import { type CreateAdjustmentRequestBody, type ListAdjustmentQueryParameters } from './operations';
import { BaseResource, PathParameters, QueryParameters } from '../../internal/base';
import {
type CreateAdjustmentRequestBody,
type ListAdjustmentQueryParameters,
type GetAdjustmentCreditNoteQueryParameters,
} from './operations';
import { type IAdjustmentResponse } from '../../types';

const AdjustmentPaths = {
list: '/adjustments',
create: '/adjustments',
getCreditNotePDF: '/adjustments/{adjustment_id}/credit-note',
} as const;

export * from './operations';
Expand All @@ -33,4 +38,23 @@ export class AdjustmentsResource extends BaseResource {

return new Adjustment(data);
}

public async getCreditNotePDF(
adjustmentId: string,
queryParams?: GetAdjustmentCreditNoteQueryParameters,
): Promise<AdjustmentCreditNotePDF> {
const urlWithPathParams = new PathParameters(AdjustmentPaths.getCreditNotePDF, {
adjustment_id: adjustmentId,
}).deriveUrl();

const queryParameters = new QueryParameters(queryParams);

const response = await this.client.get<undefined, Response<AdjustmentCreditNotePDF> | ErrorResponse>(
urlWithPathParams + queryParameters.toQueryString(),
);

const data = this.handleResponse<AdjustmentCreditNotePDF>(response);

return new AdjustmentCreditNotePDF(data);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* ! Autogenerated code !
* Do not make changes to this file.
* Changes may be overwritten as part of auto-generation.
*/

import { type Disposition } from '../../../enums';

export interface GetAdjustmentCreditNoteQueryParameters {
disposition?: Disposition;
}
1 change: 1 addition & 0 deletions src/resources/adjustments/operations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@

export * from './list-adjustment-query-parameters';
export * from './create-adjustment-request-body';
export * from './get-adjustment-credit-note-query-parameters';
14 changes: 10 additions & 4 deletions src/resources/notification-settings/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@
* Changes may be overwritten as part of auto-generation.
*/

import { BaseResource, PathParameters } from '../../internal/base';
import { BaseResource, PathParameters, QueryParameters } from '../../internal/base';
import { type ErrorResponse, type Response } from '../../internal';
import { NotificationSettings } from '../../entities';
import { type INotificationSettingsResponse } from '../../types';
import { type CreateNotificationSettingsRequestBody, type UpdateNotificationSettingsRequestBody } from './operations';
import {
type CreateNotificationSettingsRequestBody,
type ListNotificationSettingsQueryParameters,
type UpdateNotificationSettingsRequestBody,
} from './operations';

const NotificationSettingsPaths = {
list: '/notification-settings',
Expand All @@ -21,9 +25,11 @@ const NotificationSettingsPaths = {
export * from './operations';

export class NotificationSettingsResource extends BaseResource {
public async list(): Promise<NotificationSettings[]> {
public async list(queryParams?: ListNotificationSettingsQueryParameters): Promise<NotificationSettings[]> {
const queryParameters = new QueryParameters(queryParams);

const response = await this.client.get<undefined, Response<INotificationSettingsResponse[]> | ErrorResponse>(
NotificationSettingsPaths.list,
NotificationSettingsPaths.list + queryParameters.toQueryString(),
);

const data = this.handleResponse<INotificationSettingsResponse[]>(response);
Expand Down
1 change: 1 addition & 0 deletions src/resources/notification-settings/operations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@

export * from './create-notification-settings-request-body';
export * from './update-notification-settings-request-body';
export * from './list-notification-settings-query-parameters';
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* ! Autogenerated code !
* Do not make changes to this file.
* Changes may be overwritten as part of auto-generation.
*/

export interface ListNotificationSettingsQueryParameters {
after?: string;
perPage?: number;
orderBy?: string;
active?: boolean;
}
9 changes: 7 additions & 2 deletions src/resources/transactions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { BaseResource, PathParameters, QueryParameters } from '../../internal/ba
import {
type CreateTransactionQueryParameters,
type CreateTransactionRequestBody,
type GetTransactionInvoicePdfQueryParameters,
type GetTransactionQueryParameters,
type ListTransactionQueryParameters,
type TransactionPreviewRequestBody,
Expand Down Expand Up @@ -87,13 +88,17 @@ export class TransactionsResource extends BaseResource {
return new Transaction(data);
}

public async getInvoicePDF(transactionId: string): Promise<TransactionInvoicePDF> {
public async getInvoicePDF(
transactionId: string,
queryParams?: GetTransactionInvoicePdfQueryParameters,
): Promise<TransactionInvoicePDF> {
const queryParameters = new QueryParameters(queryParams);
const urlWithPathParams = new PathParameters(TransactionPaths.getInvoicePDF, {
transaction_id: transactionId,
}).deriveUrl();

const response = await this.client.get<undefined, Response<ITransactionInvoicePDF> | ErrorResponse>(
urlWithPathParams,
urlWithPathParams + queryParameters.toQueryString(),
);

const data = this.handleResponse<ITransactionInvoicePDF>(response);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* ! Autogenerated code !
* Do not make changes to this file.
* Changes may be overwritten as part of auto-generation.
*/

import { type Disposition } from '../../../enums';

export interface GetTransactionInvoicePdfQueryParameters {
disposition?: Disposition;
}
1 change: 1 addition & 0 deletions src/resources/transactions/operations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ export * from './create-transaction-request-body';
export * from './get-transaction-query-parameters';
export * from './update-transaction-request-body';
export * from './transaction-preview-request-body';
export * from './get-transaction-invoice-pdf-query-parameters';
9 changes: 9 additions & 0 deletions src/types/adjustment/adjustment-credit-note-pdf.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* ! Autogenerated code !
* Do not make changes to this file.
* Changes may be overwritten as part of auto-generation.
*/

export interface IAdjustmentCreditNotePDF {
url: string;
}
1 change: 1 addition & 0 deletions src/types/adjustment/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export * from './adjustments-time-period-response';
export * from './adjustments-proration-response';
export * from './adjustment-item-response';
export * from './adjustment-response';
export * from './adjustment-credit-note-pdf';
2 changes: 1 addition & 1 deletion src/types/events/events-response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {

export interface IEventsResponse<T = object> {
event_id: string;
notification_id: string;
notification_id: string | null;
event_type: string;
occurred_at: string;
data: T;
Expand Down
1 change: 1 addition & 0 deletions src/types/subscription/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ export * from './subscription-response';
export * from './subscription-preview-response';
export * from './subscription-preview-update-summary';
export * from './subscription-result-response';
export * from './subscription-update-non-catalog-price-request';
16 changes: 14 additions & 2 deletions src/types/subscription/subscription-update-item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,20 @@
* Do not make changes to this file.
* Changes may be overwritten as part of auto-generation.
*/
import { type ISubscriptionUpdateItemCreateWithPriceRequest } from './subscription-update-non-catalog-price-request';

export interface ISubscriptionUpdateItem {
interface ISubscriptionUpdateBaseItem {
quantity: number;
}

interface ISubscriptionUpdateItemFromCatalog extends ISubscriptionUpdateBaseItem {
priceId: string;
quantity?: number | null;
price?: never;
}

interface ISubscriptionUpdateItemCreateWithPrice extends ISubscriptionUpdateBaseItem {
priceId?: never;
price: ISubscriptionUpdateItemCreateWithPriceRequest;
}

export type ISubscriptionUpdateItem = ISubscriptionUpdateItemFromCatalog | ISubscriptionUpdateItemCreateWithPrice;
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* ! Autogenerated code !
* Do not make changes to this file.
* Changes may be overwritten as part of auto-generation.
*/

import { type CreatePriceRequestBody, type CreateProductRequestBody } from '../../resources';

interface ISubscriptionUpdateItemCreateWithPriceBaseRequest
extends Omit<CreatePriceRequestBody, 'type' | 'productId'> {}

interface ISubscriptionUpdateItemCreateWithProductId extends ISubscriptionUpdateItemCreateWithPriceBaseRequest {
productId: string;
product?: never;
}

interface ISubscriptionUpdateItemCreateWithProduct extends ISubscriptionUpdateItemCreateWithPriceBaseRequest {
productId?: never;
product: Omit<CreateProductRequestBody, 'type'>;
}

export type ISubscriptionUpdateItemCreateWithPriceRequest =
| ISubscriptionUpdateItemCreateWithProductId
| ISubscriptionUpdateItemCreateWithProduct;

0 comments on commit c7688e4

Please sign in to comment.