Skip to content

Commit

Permalink
feat: Add getPrices (#89)
Browse files Browse the repository at this point in the history
  • Loading branch information
luke-rogers committed Jun 21, 2023
1 parent ee831c5 commit d949469
Show file tree
Hide file tree
Showing 3 changed files with 180 additions and 16 deletions.
30 changes: 26 additions & 4 deletions src/__tests__/attributes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,28 +30,50 @@ describe('attributes', () => {
);
});

test('with checkout API server URL', () => {
test('with checkout API server URL v1', () => {
const instance = new PaddleSDK('foo', 'bar', 'ham');

expect(instance.vendorID).toBe('foo');
expect(instance.apiKey).toBe('bar');
expect(instance.publicKey).toBe('ham');
expect(instance.serverURL(true)).toBe(
expect(instance.serverURL('v1')).toBe(
'https://checkout.paddle.com/api/1.0'
);
});

test('with checkout API sandbox server URL', () => {
test('with checkout API sandbox server URL v1', () => {
const instance = new PaddleSDK('foo', 'bar', 'ham', { sandbox: true });

expect(instance.vendorID).toBe('foo');
expect(instance.apiKey).toBe('bar');
expect(instance.publicKey).toBe('ham');
expect(instance.serverURL(true)).toBe(
expect(instance.serverURL('v1')).toBe(
'https://sandbox-checkout.paddle.com/api/1.0'
);
});

test('with checkout API server URL v2', () => {
const instance = new PaddleSDK('foo', 'bar', 'ham');

expect(instance.vendorID).toBe('foo');
expect(instance.apiKey).toBe('bar');
expect(instance.publicKey).toBe('ham');
expect(instance.serverURL('v2')).toBe(
'https://checkout.paddle.com/api/2.0'
);
});

test('with checkout API sandbox server URL v2', () => {
const instance = new PaddleSDK('foo', 'bar', 'ham', { sandbox: true });

expect(instance.vendorID).toBe('foo');
expect(instance.apiKey).toBe('bar');
expect(instance.publicKey).toBe('ham');
expect(instance.serverURL('v2')).toBe(
'https://sandbox-checkout.paddle.com/api/2.0'
);
});

test('with custom server URL', () => {
const instance = new PaddleSDK('foo', 'bar', 'ham', {
server: 'https://custom.paddle.net',
Expand Down
98 changes: 98 additions & 0 deletions src/__tests__/prices.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import {
DEFAULT_ERROR,
VENDOR_API_KEY,
VENDOR_ID,
} from '../../utils/constants';
import nock, { SERVER } from '../../utils/nock';
import { PaddleSDK } from '../sdk';

describe('prices methods', () => {
let instance: PaddleSDK;

beforeEach(() => {
instance = new PaddleSDK(VENDOR_ID, VENDOR_API_KEY, '', {
server: SERVER,
});
});

describe('getPrices', () => {
const product1 = 123456,
product2 = 23456,
coupon1 = 'EXAMPLE10',
coupon2 = 'EXAMPLE5',
customerCountry = 'GB',
customerIp = '127.0.0.1';
const path = `/prices?product_ids=${product1}%2C${product2}`;

test('resolves on successful request', async () => {
// https://developer.paddle.com/api-reference/e268a91845971-get-prices
const body = {
success: true,
response: {
customer_country: customerCountry,
products: [
{
product_id: product1,
product_title: 'My Product 1',
currency: 'GBP',
vendor_set_prices_included_tax: true,
price: {
gross: 34.95,
net: 29.13,
tax: 5.83,
},
list_price: {
gross: 34.95,
net: 29.13,
tax: 5.83,
},
applied_coupon: [coupon1],
},
{
product_id: product2,
product_title: 'My Product 2',
currency: 'GBP',
vendor_set_prices_included_tax: true,
price: {
gross: 17.95,
net: 14.96,
tax: 2.99,
},
list_price: {
gross: 17.95,
net: 14.96,
tax: 2.99,
},
applied_coupon: [coupon2],
},
],
},
};

const scope = nock()
.get(
`${path}&coupons=${coupon1}%2C${coupon2}&customer_country=${customerCountry}&customer_ip=${customerIp}`
)
.reply(200, body);

const response = await instance.getPrices([product1, product2], {
coupons: [coupon1, coupon2],
customerCountry,
customerIp,
});

expect(response).toEqual(body.response);
expect(scope.isDone()).toBeTruthy();
});

test('rejects on error response', async () => {
const scope = nock().get(path).reply(400, DEFAULT_ERROR);

await expect(instance.getPrices([product1, product2])).rejects.toThrow(
'Request failed with status code 400'
);

expect(scope.isDone()).toBeTruthy();
});
});
});
68 changes: 56 additions & 12 deletions src/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,13 @@ import { VERSION } from './version';
const VENDOR_SANDBOX_URL = 'https://sandbox-vendors.paddle.com/api/2.0';
const VENDOR_SERVER_URL = 'https://vendors.paddle.com/api/2.0';

const CHECKOUT_SANDBOX_URL = 'https://sandbox-checkout.paddle.com/api/1.0';
const CHECKOUT_SERVER_URL = 'https://checkout.paddle.com/api/1.0';
const CHECKOUT_SANDBOX_V1_URL = 'https://sandbox-checkout.paddle.com/api/1.0';
const CHECKOUT_SERVER_V1_URL = 'https://checkout.paddle.com/api/1.0';

const CHECKOUT_SANDBOX_V2_URL = 'https://sandbox-checkout.paddle.com/api/2.0';
const CHECKOUT_SERVER_V2_URL = 'https://checkout.paddle.com/api/2.0';

type CheckoutAPIVersion = 'v1' | 'v2';

export interface Options {
/** Whether to use the sandbox server URL */
Expand Down Expand Up @@ -479,7 +484,38 @@ s * @example
*/
getOrderDetails(checkoutID: string) {
return this._request(`/order?checkout_id=${checkoutID}`, {
checkoutAPI: true,
checkoutAPIVersion: 'v1',
});
}

/**
* Get prices
*
* API documentation: https://developer.paddle.com/api-reference/e268a91845971-get-prices
*
* @example
* const result = await client.getPrices([123, 456]);
* const result = await client.getPrices([123, 456], { coupons: ['EXAMPLE'], customerCountry: 'GB', customerIp: '127.0.0.1' });
*/
getPrices(
productIDs: number[],
options?: {
coupons?: string[];
customerCountry?: string;
customerIp?: string;
}
) {
const { coupons, customerCountry, customerIp } = options || {};

const params = new URLSearchParams({
product_ids: productIDs.join(','),
...(Array.isArray(coupons) && { coupons: coupons.join(',') }),
...(customerCountry && { customer_country: customerCountry }),
...(customerIp && { customer_ip: customerIp }),
});

return this._request(`/prices?${params.toString()}`, {
checkoutAPIVersion: 'v2',
});
}

Expand Down Expand Up @@ -575,19 +611,27 @@ s * @example
/**
* Get the used server URL. Some of the requests go to Checkout server, while most will go to Vendor server.
*/
serverURL(checkoutAPI = false): string {
serverURL(checkoutAPIVersion?: CheckoutAPIVersion): string {
return (
(this.options && this.options.server) ||
(checkoutAPI &&
(this.options && this.options.sandbox
? CHECKOUT_SANDBOX_URL
: CHECKOUT_SERVER_URL)) ||
(checkoutAPIVersion && this.getCheckoutURL(checkoutAPIVersion)) ||
(this.options && this.options.sandbox
? VENDOR_SANDBOX_URL
: VENDOR_SERVER_URL)
);
}

private getCheckoutURL(checkoutAPIVersion: CheckoutAPIVersion): string {
if (this.options && this.options.sandbox) {
return checkoutAPIVersion === 'v1'
? CHECKOUT_SANDBOX_V1_URL
: CHECKOUT_SANDBOX_V2_URL;
}
return checkoutAPIVersion === 'v1'
? CHECKOUT_SERVER_V1_URL
: CHECKOUT_SERVER_V2_URL;
}

/**
* Execute a HTTP request
*
Expand All @@ -604,18 +648,18 @@ s * @example
body: requestBody,
headers,
form = true,
checkoutAPI = false,
checkoutAPIVersion = undefined,
}: {
body?: TBody;
headers?: object;
form?: boolean;
json?: boolean;
checkoutAPI?: boolean;
checkoutAPIVersion?: CheckoutAPIVersion;
} = {}
): Promise<TResponse> {
const url = this.serverURL(checkoutAPI) + path;
const url = this.serverURL(checkoutAPIVersion) + path;
// Requests to Checkout API are using only GET,
const method = checkoutAPI ? 'GET' : 'POST';
const method = checkoutAPIVersion ? 'GET' : 'POST';

const fullRequestBody = {
vendor_id: this.vendorID,
Expand Down

0 comments on commit d949469

Please sign in to comment.