Compare commits

..

27 Commits
v0.1.0 ... main

Author SHA1 Message Date
f47523f56d 0.3.1 2021-10-23 16:09:05 -06:00
70da150599 bugfix: add missing subscription properties 2021-10-23 16:08:47 -06:00
3d18aa00de docs: add dispute and reversal webhooks to quickstart 2021-10-19 00:01:27 -06:00
825e70df06 0.3.0 2021-10-17 12:55:27 -06:00
6ed6b9615a refactor: move Product.categories into own package (to reduce rarely-used bloat) 2021-10-17 12:55:20 -06:00
d487d30447 0.2.2 2021-10-17 01:04:52 -06:00
5a5f8ad9c6 docs: improve readability 2021-10-17 01:04:49 -06:00
d7f0adb69d docs: fix header formatting 2021-10-17 00:54:00 -06:00
c361837b1c 0.2.1 2021-10-17 00:51:19 -06:00
6e8aa2e09f docs: ToC, more detail & examples 2021-10-17 00:51:12 -06:00
7466e8a28e bugfix: correct typo in sandbox url var 2021-10-17 00:50:54 -06:00
7803b052e5 0.2.0 2021-10-16 23:26:55 -06:00
233ce8313e chore: update LICENSE in package.json 2021-10-16 23:26:44 -06:00
2abfd7fc5e feature: enable 'live' API mode 2021-10-16 23:17:49 -06:00
5fe43c4a48 feature: add Order.{createRequest,details,capture} 2021-10-16 23:11:47 -06:00
19cfcabc27 docs: notes on cancelling subscription 2021-10-16 17:26:04 -06:00
595076ae54 docs: add notes on webhook and email address security 2021-10-16 17:04:32 -06:00
4824418609
docs: add link to official repo 2021-10-12 23:08:07 -06:00
72deaa66ae docs: update webhook event_type info 2021-10-12 02:25:56 -06:00
e02686c676 docs: update info on return_url 2021-10-12 01:43:47 -06:00
c1ad8a490a chore: console.log => console.info 2021-10-12 01:24:18 -06:00
0a9d277317 feature!: more CRUD, also renamed .get to .details to match PayPal docs 2021-10-12 01:24:06 -06:00
82d225cafc bugfix: test Product.list and set paging to max size 2021-10-11 18:30:05 -06:00
0b5e0ab292 feature: add Product.list and Plan.list 2021-10-11 18:24:17 -06:00
1c941cb104 feature: more descriptive error message 2021-10-11 17:53:02 -06:00
38361ffe1e refactor!: rename id => request_id as appropriate 2021-10-11 17:05:25 -06:00
fc6eb5371a bugfix: postinstall -> prepare 2021-10-09 17:17:38 -06:00
16 changed files with 2089 additions and 551 deletions

627
README.md
View File

@ -1,37 +1,400 @@
# @root/paypal-checkout
# [@root/paypal-checkout](https://git.rootprojects.org/root/paypal-checkout.js)
In contrast to the official PayPal Checkout SDK - which is auto-generated code
with lots of abstraction without much value - this is very little abstraction,
but specificially designed to be (mostly) idiomatic JavaScript / Node.js. \
(excuse the `snake_case` - that's how the PayPal REST API is designed).
```bash
npm install --save @root/paypal-checkout
```
```js
"use strict";
require("dotenv").config({ path: ".env" });
let PPC = require("@root/paypal-checkout");
PPC.init({
client_id: "xxxx",
client_secret: "****",
});
PPC.Subscriptions.create({
})
```
![](https://i.imgur.com/brFTseM.png "PayPal Checkout API Flow")
<img src="https://www.paypalobjects.com/webstatic/en_US/i/buttons/checkout-logo-large.png" alt="Check out with PayPal" />
The Good Documentation™ for the PayPal API (a.k.a. PayPal Checkout SDK) is the
"REST API". See
- <https://developer.paypal.com/docs/api/orders/v2/> (one-time payments)
- <https://developer.paypal.com/docs/api/subscriptions/v1/> (recurring
subscriptions)
- <https://www.paypal.com/webapps/mpp/logos-buttons> (the buttons)
# Table of Contents
- Install
- QuickStart
- Orders (One-Time Purchases)
- PayPal Checkout Buttons
- REST API Overview
- Orders & Subscriptions
- Enums
- Redirects
- Webhooks
- Security & Notes
- Detailed Examples & Glossary
# Install
```bash
npm install --save @root/paypal-checkout
```
Optional, for Type Linting and Auto-Complete
```bash
npm install --save @root/paypal-checkout-product-categories
```
# Quick Start
If you just want to create a "Buy Now" or "Checkout with PayPal" type of button,
here's the gist of what you need to do:
## Order (One-Time Purchase)
1. Initialize the API
```js
"use strict";
require("dotenv").config({ path: ".env" });
let PPC = require("@root/paypal-checkout");
PPC.init(
process.env.PAYPAL_CLIENT_ID || "xxxx",
process.env.PAYPAL_CLIENT_SECRET || "****",
"sandbox" || "live",
{
// default query params for endpoints that use them
prefer: "return=representation",
total_required: true,
page_size: 20,
}
);
```
2. Create a "Buy Now" link (for Approval)
```js
// See https://developer.paypal.com/docs/api/orders/v2/#orders_create
let myApiUrl = "https://example.com";
let myOrderId = "local-db-id-for-user-purchasing-product";
let order = await PPC.Order.createRequest({
application_context: {
// What to show on PayPal's Pay Now page
brand_name: "Bliss via The Root Group, LLC",
shipping_preference: "NO_SHIPPING",
landing_page: "LOGIN",
user_action: PPC.Order.user_actions.PAY_NOW,
return_url: `${myApiUrl}/api/redirects/paypal-checkout/return`,
cancel_url: `${myApiUrl}/api/redirects/paypal-checkout/cancel`,
},
purchase_units: [
{
request_id: "default",
custom_id: myOrderId,
// shown in PayPal Checkout Flow UI
description: "1 year of pure Bliss",
// on the charge (credit card) statement
soft_descriptor: "Bliss",
amount: {
currency_code: "USD",
value: "10.00",
},
},
],
});
console.info(
"Approve URL:",
order.links.find(function (link) {
return "approve" === link.rel;
}).href
);
```
3. Handle the redirect: Verify & Capture
```js
app.get("/api/redirects/paypal-checkout/return", async function (req, res) {
let orderId = req.query.token;
// verify that the user has paid
await PPC.Order.details(orderId)
.then(async function (order) {
console.info("Deliver the Product to:", order.payer.email_address);
if ("APPROVED" !== order.status) {
throw new Error("spoofed redirect or cancelled order");
}
// take the money
let capture = await PPC.Order.capture(order.id, {
final_capture: true,
});
})
.catch(next);
});
```
4. [Set](https://developer.paypal.com/developer/applications) and Handle the
[`PAYMENT.CAPTURE.COMPLETED`, `PAYMENT.CAPTURE.REVERSED`, and `CUSTOMER.DISPUTE.CREATED`](https://developer.paypal.com/docs/api-basics/notifications/webhooks/event-names/)
WebHooks
```js
// Set webhook at https://developer.paypal.com/developer/applications
// Descriptions at https://developer.paypal.com/docs/api-basics/notifications/webhooks/event-names/
app.get("/api/webhooks/paypal-checkout/:secret", async function (req, res) {
let crypto = require("crypto");
let secret = process.env.PAYPAL_WEBHOOK_SECRET || "";
let guess = req.params.secret;
if (
!secret ||
secret.length !== guess.length ||
!crypto.timingSafeEqual(Buffer.from(guess), Buffer.from(secret))
) {
next(new Error("bad webhook secret value"));
return;
}
let event = req.body;
switch (event.event_type) {
case "PAYMENT.CAPTURE.COMPLETED":
{
let orderId = event.supplementary_data.related_ids.order_id;
let localDbId = event.custom_id;
console.info(
`Confirm that PayPal Order ${orderId} for ${localDbId} has been paid.`
);
}
break;
case "PAYMENT.CAPTURE.REVERSED":
{
// deduct from user's account
}
break;
case "CUSTOMER.DISPUTE.CREATED":
{
// TODO send email to merchant (myself) to check out the dispute
}
break;
case "CUSTOMER.DISPUTE.CREATED":
{
// TODO send email to merchant (myself) to review the dispute status
}
break;
default:
console.log("Ignoring", event.event_type);
res.json({ sucess: true });
return;
}
});
```
## PayPal Checkout Buttons
- <https://www.paypal.com/webapps/mpp/logos-buttons> <== THE ONE YOU WANT
- <img src="https://www.paypalobjects.com/webstatic/en_US/i/buttons/checkout-logo-large.png" alt="Check out with PayPal" />
- <https://developer.paypal.com/docs/checkout/>
- <https://www.paypal.com/buttons/>
# API Overview
## Init
```js
PayPal.init(client_id, client_secret, "sandbox", defaults);
PayPal.request({ method, url, headers, json });
```
### No Dependencies Needed
If you'd like to keep your code super lightweight, you don't even need an SDK -
you can just use simple HTTP requests:
```js
let qs = require("querystring");
let request = require("@root/request");
let paypalApi = "https://api-m.sandbox.paypal.com";
async function PayPalRequest(
endpoint = "/v2/checkout/orders",
query = { page_size: 20 },
body = { purchase_units: [] },
requestId // optional id for certain requests
) {
let search = qs.stringify(query);
return await request({
url: `${paypalApi}${endpoint}?${search}`,
auth: {
user: process.env.PAYPAL_CLIENT_ID,
pass: process.env.PAYPAL_CLIENT_SECRET,
},
headers: {
"PayPal-Request-Id": requestId,
},
json: body,
}).then(function (resp) {
if (rsep.status < 200 || resp.status >= 300) {
throw new Error("BAD RESPONSE");
}
return resp.toJSON().body;
});
}
```
## Subscriptions (Recurring Payments)
See https://developer.paypal.com/docs/api/subscriptions/v1/#subscriptions
```txt
// Webhook 'event_type':
PayPal.Product.create({ ... }); // CATALOG.PRODUCT.CREATED
PayPal.Product.list();
PayPal.Product.details(id);
PayPal.Product.update(id, { description }); // CATALOG.PRODUCT.UPDATED
PayPal.Plan.create({ ... }); // BILLING.PLAN.CREATED
PayPal.Plan.list();
PayPal.Plan.details(id);
PayPal.Plan.update(id, { description }); // BILLING.PLAN.UPDATED
PayPal.Subscription.createRequest({ ... }); // BILLING.SUBSCRIPTION.CREATED
// subscription.links[rel="approve"].href // BILLING.SUBSCRIPTION.ACTIVATED
// PAYMENT.SALE.COMPLETED
PayPal.Subscription.details(id);
PayPal.Subscription.cancel(id, { reason });
```
## Orders (One-Time Payments)
```txt
// Webhook 'event_type':
PayPal.Order.createRequest({ purchase_units }); // CHECKOUT.ORDER.APPROVED
PayPal.Order.capture(id, { final_capture }); // PAYMENT.CAPTURE.COMPLETED
```
See also:
- <https://developer.paypal.com/docs/api/orders/v2/#orders_create>
- <https://developer.paypal.com/docs/api/orders/v2/#definition-purchase_unit_request>
- <https://developer.paypal.com/docs/api/orders/v2/#definition-order_application_context>
## Enums (optional)
For assistance with Type Linting and Auto-Complete, all of the PayPal Checkout
enums (ALL CAPS strings that have a limit set of allow values such as `PAY_NOW`
and `CONTINUE`) are available in code.
They are defined like this:
```js
Order.user_actions = {
CONTINUE: "CONTINUE",
PAY_NOW: "PAY_NOW",
};
```
You can inspect them simply like this:
```js
console.log(Order.user_actions);
```
Here's the full list:
```js
PayPal.Order.intents;
PayPal.Order.user_actions;
PayPal.Order.shipping_preferences;
PayPal.Plan.intervals;
PayPal.Plan.tenures;
PayPal.Product.categories; // See note below
PayPal.Product.types;
PayPal.Subscription.actions;
PayPal.Subscription.payee_preferences;
PayPal.Subscription.payer_selections;
PayPal.Subscription.shipping_preferences;
```
The one exception is `PayPal.Product.categories` which provides only a limited
set of generic values for simple products and services if
`@root/paypal-checkout-product-categories` is not installed.
## Redirects
- `return_url`
- `cancel_url`
### `return_url`
**_Order_** and **_Subscription_** requests have a return `return_url` will be
called with some or all of the following params:
```txt
# Order
https://example.com/redirects/paypal-checkout/return
?token=XXXXXXXXXXXXXXXXX
&PayerID=XXXXXXXXXXXXX
```
- `token` is the **_Order ID_**
- `PayerID` is... exactly what it seems (no idea how you can access the Payer
object though)
```txt
# Subscrption
https://example.com/redirects/paypal-checkout/return
?subscription_id=XXXXXXXXXXXXXX
&ba_token=BA-00000000000000000
&token=XXXXXXXXXXXXXXXXX
```
- `subscription_id` refers to both the **_Subscription ID_** and the
`billing_agreement_id` of the corresponding **_Payments_**.
- `ba_token` (deprecated) refers to `/v1/payments/billing-agreements/:ba_token`
- `token` refers to the **_Order ID_** (perhaps created as part of the setup fee
or first billing cycle payment).
### `cancel_url`
The `cancel_url` will have the same query params as the `return_url`.
Also, PayPal presents the raw `cancel_url` and will NOT update the order or
subscription status. It's up to you to confirm with the user and change the
status to `CANCELLED`.
## Webhooks
Webhooks can be set up in the Application section of the Dashboard:
- <https://developer.paypal.com/developer/applications>
You'll see a list of applications. Click on one to access the webhooks.
**Security**: You must put a `secret` or `token` or your webhook URLs - PayPal
provides no measure of authentication (and otherwise an attacker could just send
random crap to your webhooks making it look like they've paid for all sorts of
things).
# Security
#### User email addresses
Emails addresses available through the PayPal Checkout API guaranteed to have
been verified by PayPal.
See:
- [Is `resource.subscriber.email_address` verified by PayPal?](https://twitter.com/paypaldev/status/1448238655743488008)
- [How do I receive money through PayPal?](https://www.paypal.com/us/smarthelp/article/how-do-i-receive-money-through-paypal-faq1750)
# Notes
My discussions with Twitter Support (@paypaldev):
- <https://twitter.com/search?q=(from%3Acoolaj86)%20(to%3Apaypaldev)&src=typed_query>
Note: Just about everything in the PayPal SDK that uses `ALL_CAPS` is a
`constant`/`enum` representing an option you can pick from limited number of
@ -40,7 +403,7 @@ options.
Sandbox accounts (for creating fake purchases) can be managed at:
<https://developer.paypal.com/developer/accounts>
Note on Auth + Capture:
## Auth vs Capture
> Authorization and capture enables you to authorize fund availability but delay
> fund capture. This can be useful for merchants who have a delayed order
@ -57,9 +420,221 @@ Note on Auth + Capture:
> - <https://developer.paypal.com/docs/admin/auth-capture/>
> - <https://developer.paypal.com/docs/api/payments/v2/#authorizations_capture>
Buttons:
You can auth once and capture multiple times (unless you set `final_capture`).
- <https://www.paypal.com/webapps/mpp/logos-buttons> <== THE ONE YOU WANT
- <img src="https://www.paypalobjects.com/webstatic/en_US/i/buttons/checkout-logo-large.png" alt="Check out with PayPal" />
- <https://developer.paypal.com/docs/checkout/>
- <https://www.paypal.com/buttons/>
# Examples
### Subscription.createRequest({ ... })
See
https://developer.paypal.com/docs/subscriptions/integrate/#use-the-subscriptions-api
```js
await Subscription.createRequest({
plan_id: plan.id,
//start_time: "2018-11-01T00:00:00Z", (must be in the future)
//quantity: "20",
//shipping_amount: { currency_code: "USD", value: "10.00" },
subscriber: {
name: { given_name: "James", surname: "Doe" },
email_address: "customer@example.com",
/*
shipping_address: {
name: { full_name: "James Doe" },
address: {
address_line_1: "123 Sesame Street",
address_line_2: "Building 17",
admin_area_2: "San Jose",
admin_area_1: "CA",
postal_code: "95131",
country_code: "US",
},
},
*/
},
application_context: {
brand_name: "Bliss via The Root Group, LLC",
locale: "en-US",
shipping_preference: Subscription.shipping_preferences.NO_SHIPPING,
user_action: Subscription.actions.SUBSCRIBE_NOW,
payment_method: {
payer_selected: Subscription.payer_selections.PAYPAL,
payee_preferred:
Subscription.payee_preferences.IMMEDIATE_PAYMENT_REQUIRED,
},
return_url:
"https://example.com/api/paypal-checkout/return?my_token=abc123",
cancel_url:
"https://example.com/api/paypal-checkout/cancel?my_token=abc123",
},
});
console.info("Subscription (Before Approval):");
console.info(JSON.stringify(subscription, null, 2));
console.info();
console.info(
"Approve URL:",
subscription.links.find(function (link) {
return "approve" === link.rel;
}).href
);
```
# Glossary
## Webhook Event: CHECKOUT.ORDER.APPROVED
```json
{
"id": "WH-1V203642KU442722T-3S346483MF8733038",
"event_version": "1.0",
"create_time": "2021-10-17T05:04:22.404Z",
"resource_type": "checkout-order",
"resource_version": "2.0",
"event_type": "CHECKOUT.ORDER.APPROVED",
"summary": "An order has been approved by buyer",
"resource": {
"create_time": "2021-10-17T05:03:26Z",
"purchase_units": [
{
"reference_id": "{purchase-unit-id}",
"amount": {
"currency_code": "USD",
"value": "10.00"
},
"payee": {
"email_address": "sb-a9xvi8075587@business.example.com",
"merchant_id": "4RXRQC77UD53U",
"display_data": {
"brand_name": "Bliss via The Root Group, LLC"
}
},
"description": "1 year of pure Bliss",
"custom_id": "{my-local-db-purchase-id}",
"soft_descriptor": "Bliss"
}
],
"links": [
{
"href": "https://api.sandbox.paypal.com/v2/checkout/orders/4K5112848U951142F",
"rel": "self",
"method": "GET"
},
{
"href": "https://api.sandbox.paypal.com/v2/checkout/orders/4K5112848U951142F",
"rel": "update",
"method": "PATCH"
},
{
"href": "https://api.sandbox.paypal.com/v2/checkout/orders/4K5112848U951142F/capture",
"rel": "capture",
"method": "POST"
}
],
"id": "4K5112848U951142F",
"intent": "CAPTURE",
"payer": {
"name": {
"given_name": "John",
"surname": "Doe"
},
"email_address": "sb-ka5d18075586@personal.example.com",
"payer_id": "YTENGYR8PAF9A",
"address": {
"country_code": "US"
}
},
"status": "APPROVED"
},
"links": [
{
"href": "https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-1V203642KU442722T-3S346483MF8733038",
"rel": "self",
"method": "GET"
},
{
"href": "https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-1V203642KU442722T-3S346483MF8733038/resend",
"rel": "resend",
"method": "POST"
}
]
}
```
## Webhook Event: PAYMENT.CAPTURE.COMPLETED
```json
{
"id": "WH-3UT90572MR669760L-7LL94124G5389840D",
"event_version": "1.0",
"create_time": "2021-10-17T05:05:03.389Z",
"resource_type": "capture",
"resource_version": "2.0",
"event_type": "PAYMENT.CAPTURE.COMPLETED",
"summary": "Payment completed for $ 10.0 USD",
"resource": {
"amount": {
"value": "10.00",
"currency_code": "USD"
},
"seller_protection": {
"dispute_categories": ["ITEM_NOT_RECEIVED", "UNAUTHORIZED_TRANSACTION"],
"status": "ELIGIBLE"
},
"supplementary_data": {
"related_ids": {
"order_id": "4K5112848U951142F"
}
},
"update_time": "2021-10-17T05:04:29Z",
"create_time": "2021-10-17T05:04:29Z",
"final_capture": true,
"seller_receivable_breakdown": {
"paypal_fee": {
"value": "0.84",
"currency_code": "USD"
},
"gross_amount": {
"value": "10.00",
"currency_code": "USD"
},
"net_amount": {
"value": "9.16",
"currency_code": "USD"
}
},
"custom_id": "{my-local-db-purchase-id}",
"links": [
{
"method": "GET",
"rel": "self",
"href": "https://api.sandbox.paypal.com/v2/payments/captures/5VK462069F664902F"
},
{
"method": "POST",
"rel": "refund",
"href": "https://api.sandbox.paypal.com/v2/payments/captures/5VK462069F664902F/refund"
},
{
"method": "GET",
"rel": "up",
"href": "https://api.sandbox.paypal.com/v2/checkout/orders/4K5112848U951142F"
}
],
"id": "5VK462069F664902F",
"status": "COMPLETED"
},
"links": [
{
"href": "https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-3UT90572MR669760L-7LL94124G5389840D",
"rel": "self",
"method": "GET"
},
{
"href": "https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-3UT90572MR669760L-7LL94124G5389840D/resend",
"rel": "resend",
"method": "POST"
}
]
}
```

7
package-lock.json generated
View File

@ -1,14 +1,13 @@
{
"name": "@root/paypal-checkout",
"version": "0.1.0",
"version": "0.3.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@root/paypal-checkout",
"version": "0.1.0",
"hasInstallScript": true,
"license": "MPL-2.0",
"version": "0.3.1",
"license": "SEE LICENSE IN LICENSE",
"dependencies": {
"@root/request": "^1.7.0"
},

View File

@ -1,20 +1,28 @@
{
"name": "@root/paypal-checkout",
"version": "0.1.0",
"version": "0.3.1",
"description": "A more sensible, human-generated wrapper for the PayPal Checkout REST API",
"main": "paypal-checkout.js",
"files": ["lib"],
"files": [
"lib"
],
"scripts": {
"postinstall": "node utils/make-categories.js",
"test": "node test.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/therootcompany/paypal-checkout.js.git"
},
"keywords": ["paypal", "checkout", "sdk", "rest", "api", "subscriptions"],
"author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)",
"license": "MPL-2.0",
"keywords": [
"paypal",
"checkout",
"sdk",
"rest",
"api",
"subscriptions"
],
"author": "AJ ONeal <aj@therootcompany.com> (https://therootcompany.com/)",
"license": "SEE LICENSE IN LICENSE",
"bugs": {
"url": "https://github.com/therootcompany/paypal-checkout.js/issues"
},

View File

@ -1,19 +1,46 @@
"use strict";
let qs = require("querystring");
let request = require("@root/request");
let PayPal = {};
PayPal.init = function (id, secret) {
PayPal.__sandboxUrl = "https://api-m.sandbox.paypal.com";
PayPal.__baseUrl = PayPal.__sandboxUrl;
PayPal.__id = id;
PayPal.__secret = secret;
PayPal.init = function (client_id, client_secret, env, opts) {
if (!opts) {
opts = {};
}
if (!("total_required" in opts)) {
opts.total_required = true;
}
if (!opts.page_size) {
opts.page_size = 20;
}
if (!opts.prefer) {
opts.prefer = "return=representation";
}
PayPal.__sandboxApiBaseUrl = "https://api-m.sandbox.paypal.com";
PayPal.__liveApiBaseUrl = "https://api.paypal.com";
if ("live" === env) {
PayPal.__baseUrl = PayPal.__liveApiBaseUrl;
} else {
PayPal.__baseUrl = PayPal.__sandboxApiBaseUrl;
console.debug("[PayPal Checkout] ENVIRONMENT=sandbox");
}
PayPal.__id = client_id;
PayPal.__secret = client_secret;
PayPal.__defaultQuery = {
page_size: opts.page_size,
total_required: opts.total_required,
page: 1,
};
PayPal.__prefer = opts.prefer;
};
PayPal.request = async function _paypalRequest(reqObj) {
let headers = {};
if (reqObj.id) {
if (reqObj.request_id) {
// Optional and if passed, helps identify idempotent requests
headers["PayPal-Request-Id"] = reqObj.id;
headers["PayPal-Request-Id"] = reqObj.request_id;
}
// ex: https://api-m.sandbox.paypal.com/v1/billing/subscriptions
reqObj.url = `${PayPal.__baseUrl}${reqObj.url}`;
@ -24,6 +51,30 @@ PayPal.request = async function _paypalRequest(reqObj) {
};
return await request(reqObj).then(sanitize);
};
PayPal._patch = function (obj) {
let ops = [];
Object.keys(obj).forEach(function (k) {
let val = obj[k];
if ("undefined" === typeof val) {
return;
}
let op = "replace";
if (null === val) {
op = "delete";
val = undefined;
}
ops.push({
path: `/${k}`,
op: op,
value: val,
});
});
return ops;
};
function justBody(resp) {
return resp.body;
@ -46,7 +97,15 @@ function sanitize(resp) {
function must201or200(resp) {
if (![200, 201].includes(resp.statusCode)) {
let err = new Error("bad response");
let err = new Error("[@root/paypal-checkout] bad response");
err.response = resp;
throw err;
}
return resp;
}
function must204or200(resp) {
if (![200, 204].includes(resp.statusCode)) {
let err = new Error("[@root/paypal-checkout] bad response");
err.response = resp;
throw err;
}
@ -61,6 +120,80 @@ function enumify(obj) {
}
*/
let shipping_preferences = {
GET_FROM_FILE: "GET_FROM_FILE", // provided, or selectable from PayPal addresses
SET_PROVIDED_ADDRESS: "SET_PROVIDED_ADDRESS", // user can't change it here
NO_SHIPPING: "NO_SHIPPING", // duh
};
let Order = {};
Order.intents = {
CAPTURE: "CAPTURE",
AUTHORIZE: "AUTHORIZE",
};
Order.user_actions = {
CONTINUE: "CONTINUE",
PAY_NOW: "PAY_NOW",
};
Order.shipping_preferences = shipping_preferences;
// See
// https://developer.paypal.com/docs/api/orders/v2/#orders_create
// https://developer.paypal.com/docs/api/orders/v2/#definition-purchase_unit_request
// https://developer.paypal.com/docs/api/orders/v2/#definition-order_application_context
Order.createRequest = async function (order) {
if (!order.intent) {
order.intent = Order.intents.CAPTURE;
}
if (!order.purchase_units?.length) {
throw new Error("must have 'purchase_units'");
}
/*
{
intent: "CAPTURE",
purchase_units: [
{
amount: {
currency_code: "USD",
value: "100.00",
},
},
],
}
*/
return await PayPal.request({
method: "POST",
url: `/v2/checkout/orders`,
json: order,
})
.then(must201or200)
.then(justBody);
};
Order.details = async function (id) {
return await PayPal.request({
url: `/v2/checkout/orders/${id}`,
json: true,
})
.then(must201or200) // 200
.then(justBody);
};
/**
* Captures (finalizes) an approved order.
* @param {String} id
* @param {any} body
*/
Order.capture = async function (id, { note_to_payer, final_capture }) {
return await PayPal.request({
method: "POST",
url: `/v2/checkout/orders/${id}/capture`,
json: { note_to_payer, final_capture },
})
.then(must201or200)
.then(justBody);
};
let Product = {};
// SaaS would be type=SERVICE, category=SOFTWARE
@ -73,19 +206,25 @@ Product.__typeNames = Object.keys(Product.types);
// Documented under "categories" at
// https://developer.paypal.com/docs/api/catalog-products/v1/
Product.categories = require("./lib/categories.json");
Product.__categoryNames = Object.keys(Product.categories);
/*
Product.categories = {
SOFTWARE: "SOFTWARE",
PHYSICAL_GOOD: "PHYSICAL_GOOD",
DIGITAL_MEDIA_BOOKS_MOVIES_MUSIC: "DIGITAL_MEDIA_BOOKS_MOVIES_MUSIC",
DIGITAL_GAMES: "DIGITAL_GAMES",
};
*/
Product.create = async function _createSubscription({
id,
// Optionally load the full list
// (for those that want the type linting)
try {
// the full list
Product.categories = require("@root/paypal-checkout-product-categories");
} catch {
// the short list
Product.categories = {
SOFTWARE: "SOFTWARE",
PHYSICAL_GOOD: "PHYSICAL_GOOD",
DIGITAL_MEDIA_BOOKS_MOVIES_MUSIC: "DIGITAL_MEDIA_BOOKS_MOVIES_MUSIC",
DIGITAL_GAMES: "DIGITAL_GAMES",
};
}
Product.__categoryNames = Object.keys(Product.categories);
Product.create = async function _createProduct({
request_id,
name,
description,
type,
@ -93,8 +232,8 @@ Product.create = async function _createSubscription({
image_url,
home_url,
}) {
if (id) {
if (!id.startsWith("PROD-")) {
if (request_id) {
if (!request_id.startsWith("PROD-")) {
console.warn(`Warn: product ID should start with "PROD-"`);
}
}
@ -108,7 +247,7 @@ Product.create = async function _createSubscription({
return await PayPal.request({
method: "POST",
url: "/v1/catalogs/products",
id: id,
request_id: request_id,
json: {
// ex: "Video Streaming Service"
name: name,
@ -128,6 +267,48 @@ Product.create = async function _createSubscription({
.then(justBody);
};
Product.list = async function _listProducts(query = {}) {
query = Object.assign({}, PayPal.__defaultQuery, query);
let search = qs.stringify(query);
return await PayPal.request({
url: `/v1/catalogs/products?${search}`,
json: true,
})
.then(must201or200)
.then(justBody);
};
Product.details = async function _showProductDetails(id) {
return await PayPal.request({
url: `/v1/catalogs/products/${id}`,
json: true,
})
.then(must201or200)
.then(justBody);
};
/**
* Update product info
* @param id
* @param {{
* description: string,
* category: string,
* image_url: string,
* home_url: string,
* }}
*/
Product.update = async function _updateProduct(
id,
{ description, category, image_url, home_url }
) {
let body = PayPal._patch({ description, category, image_url, home_url });
return await PayPal.request({
method: "PATCH",
url: `/v1/catalogs/products/${id}`,
json: body,
}).then(must204or200);
};
let Plan = {};
Plan.intervals = {
DAY: "DAY",
@ -135,6 +316,7 @@ Plan.intervals = {
MONTH: "MONTH",
YEAR: "YEAR",
};
Plan.tenures = {
TRIAL: "TRIAL",
REGULAR: "REGULAR",
@ -142,7 +324,7 @@ Plan.tenures = {
// See https://developer.paypal.com/docs/api/subscriptions/v1/
Plan.create = async function _createPlan({
id,
request_id,
status = "ACTIVE",
product_id,
name,
@ -152,19 +334,20 @@ Plan.create = async function _createPlan({
taxes, // optional
quantity_supported = false,
}) {
let headers = {};
if (id) {
if (!id.startsWith("PLAN-")) {
if (request_id) {
if (!request_id.startsWith("PLAN-")) {
// ex: PLAN-18062020-001
console.warn(`Warn: plan ID should start with "PLAN-"`);
}
}
headers["Prefer"] = "return=representation";
return await PayPal.request({
method: "POST",
url: "/v1/billing/plans",
id: id,
headers: headers,
request_id: request_id,
// TODO should we make this the default?
headers: {
Prefer: "return=representation",
},
json: {
// ex: "PROD-6XB24663H4094933M"
product_id: product_id,
@ -200,16 +383,56 @@ Plan.create = async function _createPlan({
.then(justBody);
};
Plan.list = async function _listPlans(query = {}) {
query = Object.assign({}, PayPal.__defaultQuery, query);
let search = qs.stringify(query);
return await PayPal.request({
url: `/v1/billing/plans?${search}`,
json: true,
})
.then(must201or200)
.then(justBody);
};
Plan.details = async function _showPlanDetails(id) {
return await PayPal.request({
url: `/v1/billing/plans/${id}`,
json: true,
})
.then(must201or200)
.then(justBody);
};
/**
* Update plan info
* @param id
* @param {{
* description: string,
* payment_preferences.auto_bill_outstandin: boolean,
* taxes.percentage: string,
* payment_preferences.payment_failure_threshold: number,
* payment_preferences.setup_fee: string,
* payment_preferences.setup_fee_failure_action: string,
* }}
*/
Plan.update = async function _updatePlan(
id,
// TODO handle nested keys (ex: 'taxes.percentage')
{ description /*, payment_preferences, taxes*/ }
) {
return await PayPal.request({
method: "PATCH",
url: `/v1/billing/plans/${id}`,
json: PayPal._patch({ description }),
}).then(must204or200);
};
let Subscription = {};
Subscription.actions = {
CONTINUE: "CONTINUE",
SUBSCRIBE_NOW: "SUBSCRIBE_NOW",
};
Subscription.shipping_preferences = {
GET_FROM_FILE: "GET_FROM_FILE", // provided, or selectable from PayPal addresses
SET_PROVIDED_ADDRESS: "SET_PROVIDED_ADDRESS", // user can't change it here
NO_SHIPPING: "NO_SHIPPING", // duh
};
Subscription.shipping_preferences = shipping_preferences;
Subscription.payer_selections = {
PAYPAL: "PAYPAL",
};
@ -218,19 +441,22 @@ Subscription.payee_preferences = {
IMMEDIATE_PAYMENT_REQUIRED: "IMMEDIATE_PAYMENT_REQUIRED",
};
// See https://developer.paypal.com/docs/api/subscriptions/v1/#subscriptions_create
Subscription.createRequest = async function _createSubscription({
id,
request_id,
plan_id,
start_time,
quantity,
shipping_amount,
subscriber,
application_context,
custom_id,
plan,
}) {
return await PayPal.request({
method: "POST",
url: "/v1/billing/subscriptions",
id: id,
request_id: request_id,
json: {
// ex: "P-5ML4271244454362WXNWU5NQ"
plan_id: plan_id,
@ -273,13 +499,15 @@ Subscription.createRequest = async function _createSubscription({
}
*/
application_context: application_context,
custom_id: custom_id,
plan: plan,
},
})
.then(must201or200)
.then(justBody);
};
Subscription.get = async function _getSubscription(id) {
Subscription.details = async function _getSubscription(id) {
return await PayPal.request({
url: `/v1/billing/subscriptions/${id}`,
json: true,
@ -288,8 +516,26 @@ Subscription.get = async function _getSubscription(id) {
.then(justBody);
};
/**
* Cancel a subscription (prevent future auto billing)
* @param id
* @param {{
* reason: string
* }}
*/
Subscription.cancel = async function _showProductDetails(id, { reason }) {
return await PayPal.request({
method: "POST",
url: `/v1/catalogs/products/${id}/cancel`,
json: { reason },
})
.then(must201or200)
.then(justBody);
};
module.exports.init = PayPal.init;
module.exports.request = PayPal.request;
module.exports.Order = Order;
module.exports.Plan = Plan;
module.exports.Product = Product;
module.exports.Subscription = Subscription;

View File

@ -102,7 +102,7 @@ async function test() {
*/
},
application_context: {
brand_name: "root",
brand_name: "Bliss via The Root Group, LLC",
locale: "en-US",
shipping_preference: Subscription.shipping_preferences.NO_SHIPPING,
user_action: Subscription.actions.SUBSCRIBE_NOW,
@ -141,7 +141,7 @@ async function test() {
});
process.stdin.pause();
let s = await Subscription.get(subscription.id);
let s = await Subscription.details(subscription.id);
console.info("Subscription: (After Approval)");
console.info(JSON.stringify(s, null, 2));
console.info();

60
tests/crud.js Normal file
View File

@ -0,0 +1,60 @@
"use strict";
require("dotenv").config({ path: ".env" });
require("dotenv").config({ path: ".env.secret" });
if (!process.env.PAYPAL_CLIENT_ID) {
console.error(
"Please copy example.env to .env and update the values from the PayPal API Dashboard at https://developer.paypal.com/developer/applications"
);
process.exit(1);
}
let PayPal = require("../");
let { Plan, Product /*, Subscription*/ } = PayPal;
async function test() {
let products = await Product.list();
console.info();
console.info("Products:", products.products.length);
//console.info(JSON.stringify(products, null, 2));
if (products.products.length) {
let product = await Product.details(products.products[0].id);
console.info("Product 0:");
console.info(JSON.stringify(product, null, 2));
await Product.update(product.id, {
description: `Product Description 10${Math.random()}`,
});
}
let plans = await Plan.list();
console.info();
console.info("Plans:", plans.plans.length);
//console.info(JSON.stringify(plans, null, 2));
if (plans.plans.length) {
let plan = await Plan.details(plans.plans[0].id);
console.info("Plan 0:");
console.info(JSON.stringify(plan, null, 2));
await Plan.update(plan.id, {
description: `Plan Description 20${Math.random()}`,
});
}
console.info();
}
if (require.main === module) {
PayPal.init(
process.env.PAYPAL_CLIENT_ID,
process.env.PAYPAL_CLIENT_SECRET,
"sandbox"
);
test().catch(function (err) {
console.error("Something bad happened:");
console.error(JSON.stringify(err, null, 2));
});
}

88
tests/order.js Normal file
View File

@ -0,0 +1,88 @@
"use strict";
require("dotenv").config({ path: ".env" });
require("dotenv").config({ path: ".env.secret" });
if (!process.env.PAYPAL_CLIENT_ID) {
console.error(
"Please copy example.env to .env and update the values from the PayPal API Dashboard at https://developer.paypal.com/developer/applications"
);
process.exit(1);
}
let PayPal = require("../");
let { Order } = PayPal;
async function test() {
let ppcOrder = await Order.createRequest({
application_context: {
brand_name: "Bliss via The Root Group, LLC",
shipping_preference: "NO_SHIPPING",
// ("checkout with paypal") or "BILLING" (credit card) or NO_PREFERENCE
landing_page: "LOGIN",
user_action: "PAY_NOW",
return_url: `https://example.com/api/redirects/paypal-checkout/return`,
cancel_url: `https://example.com/api/redirects/paypal-checkout/cancel`,
},
purchase_units: [
{
request_id: 0,
custom_id: "xxxx", // Our own (User x Product) ID
description: "1 year of pure Bliss", // shown in PayPal Checkout Flow UI
soft_descriptor: "Bliss", // on the charge (credit card) statement
amount: {
currency_code: "USD",
value: "10.00",
},
},
],
});
console.info();
console.info("Order:");
console.info(JSON.stringify(ppcOrder, null, 2));
// wait for user to click URL and accept
await new Promise(function (resolve) {
console.info();
console.info("Please approve the order at the following URL:");
console.info();
console.info(
"Approve URL:",
ppcOrder.links.find(function (link) {
return "approve" === link.rel;
}).href
);
console.info("Username:", process.env.PAYPAL_SANDBOX_EMAIL);
console.info("Password:", process.env.PAYPAL_SANDBOX_PASSWORD);
console.info();
console.info("Did you approve it? Hit the <any> key to continue...");
console.info();
process.stdin.once("data", resolve);
});
process.stdin.pause();
let ppcCapture = await Order.capture(ppcOrder.id, {
note_to_payer: undefined,
final_order: true,
});
console.info();
console.info("Capture:");
console.info(JSON.stringify(ppcCapture, null, 2));
console.info();
}
if (require.main === module) {
PayPal.init(
process.env.PAYPAL_CLIENT_ID,
process.env.PAYPAL_CLIENT_SECRET,
"sandbox"
);
test().catch(function (err) {
console.error("Something bad happened:");
console.error(err);
console.error(JSON.stringify(err, null, 2));
});
}

View File

@ -1,475 +0,0 @@
// Documented under "categories" at
// https://developer.paypal.com/docs/api/catalog-products/v1/
/*
// To scrape the full list from the site:
var categories = [];
var $c = $$('.dax-def-label code').find(function ($el) {
if ("category" === $el.innerText.toLowerCase()) {
return $el;
}
});
$c.closest('div').nextElementSibling.querySelectorAll('li').forEach(function ($el) {
categories.push($el.querySelector('code').innerText);
});
console.log(JSON.stringify(categories));
*/
let categories = [
"AC_REFRIGERATION_REPAIR",
"ACADEMIC_SOFTWARE",
"ACCESSORIES",
"ACCOUNTING",
"ADULT",
"ADVERTISING",
"AFFILIATED_AUTO_RENTAL",
"AGENCIES",
"AGGREGATORS",
"AGRICULTURAL_COOPERATIVE_FOR_MAIL_ORDER",
"AIR_CARRIERS_AIRLINES",
"AIRLINES",
"AIRPORTS_FLYING_FIELDS",
"ALCOHOLIC_BEVERAGES",
"AMUSEMENT_PARKS_CARNIVALS",
"ANIMATION",
"ANTIQUES",
"APPLIANCES",
"AQUARIAMS_SEAQUARIUMS_DOLPHINARIUMS",
"ARCHITECTURAL_ENGINEERING_AND_SURVEYING_SERVICES",
"ART_AND_CRAFT_SUPPLIES",
"ART_DEALERS_AND_GALLERIES",
"ARTIFACTS_GRAVE_RELATED_AND_NATIVE_AMERICAN_CRAFTS",
"ARTS_AND_CRAFTS",
"ARTS_CRAFTS_AND_COLLECTIBLES",
"AUDIO_BOOKS",
"AUTO_ASSOCIATIONS_CLUBS",
"AUTO_DEALER_USED_ONLY",
"AUTO_RENTALS",
"AUTO_SERVICE",
"AUTOMATED_FUEL_DISPENSERS",
"AUTOMOBILE_ASSOCIATIONS",
"AUTOMOTIVE",
"AUTOMOTIVE_REPAIR_SHOPS_NON_DEALER",
"AUTOMOTIVE_TOP_AND_BODY_SHOPS",
"AVIATION",
"BABIES_CLOTHING_AND_SUPPLIES",
"BABY",
"BANDS_ORCHESTRAS_ENTERTAINERS",
"BARBIES",
"BATH_AND_BODY",
"BATTERIES",
"BEAN_BABIES",
"BEAUTY",
"BEAUTY_AND_FRAGRANCES",
"BED_AND_BATH",
"BICYCLE_SHOPS_SALES_AND_SERVICE",
"BICYCLES_AND_ACCESSORIES",
"BILLIARD_POOL_ESTABLISHMENTS",
"BOAT_DEALERS",
"BOAT_RENTALS_AND_LEASING",
"BOATING_SAILING_AND_ACCESSORIES",
"BOOKS",
"BOOKS_AND_MAGAZINES",
"BOOKS_MANUSCRIPTS",
"BOOKS_PERIODICALS_AND_NEWSPAPERS",
"BOWLING_ALLEYS",
"BULLETIN_BOARD",
"BUS_LINE",
"BUS_LINES_CHARTERS_TOUR_BUSES",
"BUSINESS",
"BUSINESS_AND_SECRETARIAL_SCHOOLS",
"BUYING_AND_SHOPPING_SERVICES_AND_CLUBS",
"CABLE_SATELLITE_AND_OTHER_PAY_TELEVISION_AND_RADIO_SERVICES",
"CABLE_SATELLITE_AND_OTHER_PAY_TV_AND_RADIO",
"CAMERA_AND_PHOTOGRAPHIC_SUPPLIES",
"CAMERAS",
"CAMERAS_AND_PHOTOGRAPHY",
"CAMPER_RECREATIONAL_AND_UTILITY_TRAILER_DEALERS",
"CAMPING_AND_OUTDOORS",
"CAMPING_AND_SURVIVAL",
"CAR_AND_TRUCK_DEALERS",
"CAR_AND_TRUCK_DEALERS_USED_ONLY",
"CAR_AUDIO_AND_ELECTRONICS",
"CAR_RENTAL_AGENCY",
"CATALOG_MERCHANT",
"CATALOG_RETAIL_MERCHANT",
"CATERING_SERVICES",
"CHARITY",
"CHECK_CASHIER",
"CHILD_CARE_SERVICES",
"CHILDREN_BOOKS",
"CHIROPODISTS_PODIATRISTS",
"CHIROPRACTORS",
"CIGAR_STORES_AND_STANDS",
"CIVIC_SOCIAL_FRATERNAL_ASSOCIATIONS",
"CIVIL_SOCIAL_FRAT_ASSOCIATIONS",
"CLOTHING",
"CLOTHING_ACCESSORIES_AND_SHOES",
"CLOTHING_RENTAL",
"COFFEE_AND_TEA",
"COIN_OPERATED_BANKS_AND_CASINOS",
"COLLECTIBLES",
"COLLECTION_AGENCY",
"COLLEGES_AND_UNIVERSITIES",
"COMMERCIAL_EQUIPMENT",
"COMMERCIAL_FOOTWEAR",
"COMMERCIAL_PHOTOGRAPHY",
"COMMERCIAL_PHOTOGRAPHY_ART_AND_GRAPHICS",
"COMMERCIAL_SPORTS_PROFESSIONA",
"COMMODITIES_AND_FUTURES_EXCHANGE",
"COMPUTER_AND_DATA_PROCESSING_SERVICES",
"COMPUTER_HARDWARE_AND_SOFTWARE",
"COMPUTER_MAINTENANCE_REPAIR_AND_SERVICES_NOT_ELSEWHERE_CLAS",
"CONSTRUCTION",
"CONSTRUCTION_MATERIALS_NOT_ELSEWHERE_CLASSIFIED",
"CONSULTING_SERVICES",
"CONSUMER_CREDIT_REPORTING_AGENCIES",
"CONVALESCENT_HOMES",
"COSMETIC_STORES",
"COUNSELING_SERVICES_DEBT_MARRIAGE_PERSONAL",
"COUNTERFEIT_CURRENCY_AND_STAMPS",
"COUNTERFEIT_ITEMS",
"COUNTRY_CLUBS",
"COURIER_SERVICES",
"COURIER_SERVICES_AIR_AND_GROUND_AND_FREIGHT_FORWARDERS",
"COURT_COSTS_ALIMNY_CHILD_SUPT",
"COURT_COSTS_INCLUDING_ALIMONY_AND_CHILD_SUPPORT_COURTS_OF_LAW",
"CREDIT_CARDS",
"CREDIT_UNION",
"CULTURE_AND_RELIGION",
"DAIRY_PRODUCTS_STORES",
"DANCE_HALLS_STUDIOS_AND_SCHOOLS",
"DECORATIVE",
"DENTAL",
"DENTISTS_AND_ORTHODONTISTS",
"DEPARTMENT_STORES",
"DESKTOP_PCS",
"DEVICES",
"DIECAST_TOYS_VEHICLES",
"DIGITAL_GAMES",
"DIGITAL_MEDIA_BOOKS_MOVIES_MUSIC",
"DIRECT_MARKETING",
"DIRECT_MARKETING_CATALOG_MERCHANT",
"DIRECT_MARKETING_INBOUND_TELE",
"DIRECT_MARKETING_OUTBOUND_TELE",
"DIRECT_MARKETING_SUBSCRIPTION",
"DISCOUNT_STORES",
"DOOR_TO_DOOR_SALES",
"DRAPERY_WINDOW_COVERING_AND_UPHOLSTERY",
"DRINKING_PLACES",
"DRUGSTORE",
"DURABLE_GOODS",
"ECOMMERCE_DEVELOPMENT",
"ECOMMERCE_SERVICES",
"EDUCATIONAL_AND_TEXTBOOKS",
"ELECTRIC_RAZOR_STORES",
"ELECTRICAL_AND_SMALL_APPLIANCE_REPAIR",
"ELECTRICAL_CONTRACTORS",
"ELECTRICAL_PARTS_AND_EQUIPMENT",
"ELECTRONIC_CASH",
"ELEMENTARY_AND_SECONDARY_SCHOOLS",
"EMPLOYMENT",
"ENTERTAINERS",
"ENTERTAINMENT_AND_MEDIA",
"EQUIP_TOOL_FURNITURE_AND_APPLIANCE_RENTAL_AND_LEASING",
"ESCROW",
"EVENT_AND_WEDDING_PLANNING",
"EXERCISE_AND_FITNESS",
"EXERCISE_EQUIPMENT",
"EXTERMINATING_AND_DISINFECTING_SERVICES",
"FABRICS_AND_SEWING",
"FAMILY_CLOTHING_STORES",
"FASHION_JEWELRY",
"FAST_FOOD_RESTAURANTS",
"FICTION_AND_NONFICTION",
"FINANCE_COMPANY",
"FINANCIAL_AND_INVESTMENT_ADVICE",
"FINANCIAL_INSTITUTIONS_MERCHANDISE_AND_SERVICES",
"FIREARM_ACCESSORIES",
"FIREARMS_WEAPONS_AND_KNIVES",
"FIREPLACE_AND_FIREPLACE_SCREENS",
"FIREWORKS",
"FISHING",
"FLORISTS",
"FLOWERS",
"FOOD_DRINK_AND_NUTRITION",
"FOOD_PRODUCTS",
"FOOD_RETAIL_AND_SERVICE",
"FRAGRANCES_AND_PERFUMES",
"FREEZER_AND_LOCKER_MEAT_PROVISIONERS",
"FUEL_DEALERS_FUEL_OIL_WOOD_AND_COAL",
"FUEL_DEALERS_NON_AUTOMOTIVE",
"FUNERAL_SERVICES_AND_CREMATORIES",
"FURNISHING_AND_DECORATING",
"FURNITURE",
"FURRIERS_AND_FUR_SHOPS",
"GADGETS_AND_OTHER_ELECTRONICS",
"GAMBLING",
"GAME_SOFTWARE",
"GAMES",
"GARDEN_SUPPLIES",
"GENERAL",
"GENERAL_CONTRACTORS",
"GENERAL_GOVERNMENT",
"GENERAL_SOFTWARE",
"GENERAL_TELECOM",
"GIFTS_AND_FLOWERS",
"GLASS_PAINT_AND_WALLPAPER_STORES",
"GLASSWARE_CRYSTAL_STORES",
"GOVERNMENT",
"GOVERNMENT_IDS_AND_LICENSES",
"GOVERNMENT_LICENSED_ON_LINE_CASINOS_ON_LINE_GAMBLING",
"GOVERNMENT_OWNED_LOTTERIES",
"GOVERNMENT_SERVICES",
"GRAPHIC_AND_COMMERCIAL_DESIGN",
"GREETING_CARDS",
"GROCERY_STORES_AND_SUPERMARKETS",
"HARDWARE_AND_TOOLS",
"HARDWARE_EQUIPMENT_AND_SUPPLIES",
"HAZARDOUS_RESTRICTED_AND_PERISHABLE_ITEMS",
"HEALTH_AND_BEAUTY_SPAS",
"HEALTH_AND_NUTRITION",
"HEALTH_AND_PERSONAL_CARE",
"HEARING_AIDS_SALES_AND_SUPPLIES",
"HEATING_PLUMBING_AC",
"HIGH_RISK_MERCHANT",
"HIRING_SERVICES",
"HOBBIES_TOYS_AND_GAMES",
"HOME_AND_GARDEN",
"HOME_AUDIO",
"HOME_DECOR",
"HOME_ELECTRONICS",
"HOSPITALS",
"HOTELS_MOTELS_INNS_RESORTS",
"HOUSEWARES",
"HUMAN_PARTS_AND_REMAINS",
"HUMOROUS_GIFTS_AND_NOVELTIES",
"HUNTING",
"IDS_LICENSES_AND_PASSPORTS",
"ILLEGAL_DRUGS_AND_PARAPHERNALIA",
"INDUSTRIAL",
"INDUSTRIAL_AND_MANUFACTURING_SUPPLIES",
"INSURANCE_AUTO_AND_HOME",
"INSURANCE_DIRECT",
"INSURANCE_LIFE_AND_ANNUITY",
"INSURANCE_SALES_UNDERWRITING",
"INSURANCE_UNDERWRITING_PREMIUMS",
"INTERNET_AND_NETWORK_SERVICES",
"INTRA_COMPANY_PURCHASES",
"LABORATORIES_DENTAL_MEDICAL",
"LANDSCAPING",
"LANDSCAPING_AND_HORTICULTURAL_SERVICES",
"LAUNDRY_CLEANING_SERVICES",
"LEGAL",
"LEGAL_SERVICES_AND_ATTORNEYS",
"LOCAL_DELIVERY_SERVICE",
"LOCKSMITH",
"LODGING_AND_ACCOMMODATIONS",
"LOTTERY_AND_CONTESTS",
"LUGGAGE_AND_LEATHER_GOODS",
"LUMBER_AND_BUILDING_MATERIALS",
"MAGAZINES",
"MAINTENANCE_AND_REPAIR_SERVICES",
"MAKEUP_AND_COSMETICS",
"MANUAL_CASH_DISBURSEMENTS",
"MASSAGE_PARLORS",
"MEDICAL",
"MEDICAL_AND_PHARMACEUTICAL",
"MEDICAL_CARE",
"MEDICAL_EQUIPMENT_AND_SUPPLIES",
"MEDICAL_SERVICES",
"MEETING_PLANNERS",
"MEMBERSHIP_CLUBS_AND_ORGANIZATIONS",
"MEMBERSHIP_COUNTRY_CLUBS_GOLF",
"MEMORABILIA",
"MEN_AND_BOY_CLOTHING_AND_ACCESSORY_STORES",
"MEN_CLOTHING",
"MERCHANDISE",
"METAPHYSICAL",
"MILITARIA",
"MILITARY_AND_CIVIL_SERVICE_UNIFORMS",
"MISC._AUTOMOTIVE_AIRCRAFT_AND_FARM_EQUIPMENT_DEALERS",
"MISC._GENERAL_MERCHANDISE",
"MISCELLANEOUS_GENERAL_SERVICES",
"MISCELLANEOUS_REPAIR_SHOPS_AND_RELATED_SERVICES",
"MODEL_KITS",
"MONEY_TRANSFER_MEMBER_FINANCIAL_INSTITUTION",
"MONEY_TRANSFER_MERCHANT",
"MOTION_PICTURE_THEATERS",
"MOTOR_FREIGHT_CARRIERS_AND_TRUCKING",
"MOTOR_HOME_AND_RECREATIONAL_VEHICLE_RENTAL",
"MOTOR_HOMES_DEALERS",
"MOTOR_VEHICLE_SUPPLIES_AND_NEW_PARTS",
"MOTORCYCLE_DEALERS",
"MOTORCYCLES",
"MOVIE",
"MOVIE_TICKETS",
"MOVING_AND_STORAGE",
"MULTI_LEVEL_MARKETING",
"MUSIC_CDS_CASSETTES_AND_ALBUMS",
"MUSIC_STORE_INSTRUMENTS_AND_SHEET_MUSIC",
"NETWORKING",
"NEW_AGE",
"NEW_PARTS_AND_SUPPLIES_MOTOR_VEHICLE",
"NEWS_DEALERS_AND_NEWSTANDS",
"NON_DURABLE_GOODS",
"NON_FICTION",
"NON_PROFIT_POLITICAL_AND_RELIGION",
"NONPROFIT",
"NOVELTIES",
"OEM_SOFTWARE",
"OFFICE_SUPPLIES_AND_EQUIPMENT",
"ONLINE_DATING",
"ONLINE_GAMING",
"ONLINE_GAMING_CURRENCY",
"ONLINE_SERVICES",
"OOUTBOUND_TELEMARKETING_MERCH",
"OPHTHALMOLOGISTS_OPTOMETRIST",
"OPTICIANS_AND_DISPENSING",
"ORTHOPEDIC_GOODS_PROSTHETICS",
"OSTEOPATHS",
"OTHER",
"PACKAGE_TOUR_OPERATORS",
"PAINTBALL",
"PAINTS_VARNISHES_AND_SUPPLIES",
"PARKING_LOTS_AND_GARAGES",
"PARTS_AND_ACCESSORIES",
"PAWN_SHOPS",
"PAYCHECK_LENDER_OR_CASH_ADVANCE",
"PERIPHERALS",
"PERSONALIZED_GIFTS",
"PET_SHOPS_PET_FOOD_AND_SUPPLIES",
"PETROLEUM_AND_PETROLEUM_PRODUCTS",
"PETS_AND_ANIMALS",
"PHOTOFINISHING_LABORATORIES_PHOTO_DEVELOPING",
"PHOTOGRAPHIC_STUDIOS_PORTRAITS",
"PHOTOGRAPHY",
"PHYSICAL_GOOD",
"PICTURE_VIDEO_PRODUCTION",
"PIECE_GOODS_NOTIONS_AND_OTHER_DRY_GOODS",
"PLANTS_AND_SEEDS",
"PLUMBING_AND_HEATING_EQUIPMENTS_AND_SUPPLIES",
"POLICE_RELATED_ITEMS",
"POLITICAL_ORGANIZATIONS",
"POSTAL_SERVICES_GOVERNMENT_ONLY",
"POSTERS",
"PREPAID_AND_STORED_VALUE_CARDS",
"PRESCRIPTION_DRUGS",
"PROMOTIONAL_ITEMS",
"PUBLIC_WAREHOUSING_AND_STORAGE",
"PUBLISHING_AND_PRINTING",
"PUBLISHING_SERVICES",
"RADAR_DECTORS",
"RADIO_TELEVISION_AND_STEREO_REPAIR",
"REAL_ESTATE",
"REAL_ESTATE_AGENT",
"REAL_ESTATE_AGENTS_AND_MANAGERS_RENTALS",
"RELIGION_AND_SPIRITUALITY_FOR_PROFIT",
"RELIGIOUS",
"RELIGIOUS_ORGANIZATIONS",
"REMITTANCE",
"RENTAL_PROPERTY_MANAGEMENT",
"RESIDENTIAL",
"RETAIL",
"RETAIL_FINE_JEWELRY_AND_WATCHES",
"REUPHOLSTERY_AND_FURNITURE_REPAIR",
"RINGS",
"ROOFING_SIDING_SHEET_METAL",
"RUGS_AND_CARPETS",
"SCHOOLS_AND_COLLEGES",
"SCIENCE_FICTION",
"SCRAPBOOKING",
"SCULPTURES",
"SECURITIES_BROKERS_AND_DEALERS",
"SECURITY_AND_SURVEILLANCE",
"SECURITY_AND_SURVEILLANCE_EQUIPMENT",
"SECURITY_BROKERS_AND_DEALERS",
"SEMINARS",
"SERVICE_STATIONS",
"SERVICES",
"SEWING_NEEDLEWORK_FABRIC_AND_PIECE_GOODS_STORES",
"SHIPPING_AND_PACKING",
"SHOE_REPAIR_HAT_CLEANING",
"SHOE_STORES",
"SHOES",
"SNOWMOBILE_DEALERS",
"SOFTWARE",
"SPECIALTY_AND_MISC._FOOD_STORES",
"SPECIALTY_CLEANING_POLISHING_AND_SANITATION_PREPARATIONS",
"SPECIALTY_OR_RARE_PETS",
"SPORT_GAMES_AND_TOYS",
"SPORTING_AND_RECREATIONAL_CAMPS",
"SPORTING_GOODS",
"SPORTS_AND_OUTDOORS",
"SPORTS_AND_RECREATION",
"STAMP_AND_COIN",
"STATIONARY_PRINTING_AND_WRITING_PAPER",
"STENOGRAPHIC_AND_SECRETARIAL_SUPPORT_SERVICES",
"STOCKS_BONDS_SECURITIES_AND_RELATED_CERTIFICATES",
"STORED_VALUE_CARDS",
"SUPPLIES",
"SUPPLIES_AND_TOYS",
"SURVEILLANCE_EQUIPMENT",
"SWIMMING_POOLS_AND_SPAS",
"SWIMMING_POOLS_SALES_SUPPLIES_SERVICES",
"TAILORS_AND_ALTERATIONS",
"TAX_PAYMENTS",
"TAX_PAYMENTS_GOVERNMENT_AGENCIES",
"TAXICABS_AND_LIMOUSINES",
"TELECOMMUNICATION_SERVICES",
"TELEPHONE_CARDS",
"TELEPHONE_EQUIPMENT",
"TELEPHONE_SERVICES",
"THEATER",
"TIRE_RETREADING_AND_REPAIR",
"TOLL_OR_BRIDGE_FEES",
"TOOLS_AND_EQUIPMENT",
"TOURIST_ATTRACTIONS_AND_EXHIBITS",
"TOWING_SERVICE",
"TOYS_AND_GAMES",
"TRADE_AND_VOCATIONAL_SCHOOLS",
"TRADEMARK_INFRINGEMENT",
"TRAILER_PARKS_AND_CAMPGROUNDS",
"TRAINING_SERVICES",
"TRANSPORTATION_SERVICES",
"TRAVEL",
"TRUCK_AND_UTILITY_TRAILER_RENTALS",
"TRUCK_STOP",
"TYPESETTING_PLATE_MAKING_AND_RELATED_SERVICES",
"USED_MERCHANDISE_AND_SECONDHAND_STORES",
"USED_PARTS_MOTOR_VEHICLE",
"UTILITIES",
"UTILITIES_ELECTRIC_GAS_WATER_SANITARY",
"VARIETY_STORES",
"VEHICLE_SALES",
"VEHICLE_SERVICE_AND_ACCESSORIES",
"VIDEO_EQUIPMENT",
"VIDEO_GAME_ARCADES_ESTABLISH",
"VIDEO_GAMES_AND_SYSTEMS",
"VIDEO_TAPE_RENTAL_STORES",
"VINTAGE_AND_COLLECTIBLE_VEHICLES",
"VINTAGE_AND_COLLECTIBLES",
"VITAMINS_AND_SUPPLEMENTS",
"VOCATIONAL_AND_TRADE_SCHOOLS",
"WATCH_CLOCK_AND_JEWELRY_REPAIR",
"WEB_HOSTING_AND_DESIGN",
"WELDING_REPAIR",
"WHOLESALE_CLUBS",
"WHOLESALE_FLORIST_SUPPLIERS",
"WHOLESALE_PRESCRIPTION_DRUGS",
"WILDLIFE_PRODUCTS",
"WIRE_TRANSFER",
"WIRE_TRANSFER_AND_MONEY_ORDER",
"WOMEN_ACCESSORY_SPECIALITY",
"WOMEN_CLOTHING",
];
let Fs = require("fs");
let categoriesMap = categories.reduce(function (obj, name) {
obj[name] = name;
return obj;
}, {});
Fs.mkdirSync(__dirname + "/../lib", { recursive: true });
Fs.writeFileSync(
__dirname + "/../lib/categories.json",
JSON.stringify(categoriesMap, null, 2),
"utf8"
);

1
vendor/product-categories/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
categories.js

498
vendor/product-categories/README.md vendored Normal file
View File

@ -0,0 +1,498 @@
# [@root/paypal-checkout-product-categories](https://github.com/therootcompany/paypal-checkout.js/tree/main/vendor/product-categories/)
Providing for those who like type linting, auto-complete, and want the full list
of all PayPal Checkout categories (though these are not PayPal-specific - they
are common across the industry).
(this was removed from `@root/paypal-checkout` because it added a lot of package
weight for something that very few people will need or use)
## License
SPDX: `(CC0-1.0 OR MIT)`
| 🧑 Personal & Evaluation | 🧑‍💻 Professional | 🧑‍💼 Business | 🏢 Enterprise Support |
| :----------------------: | :----------------: | :------------: | :-------------------: |
| Free | Free | Free | N/A |
## Install
```bash
npm install --save @root/paypal-checkout-product-categories
```
## Usage
When installed, these will automatically be loaded into
`@rootl/paypal-checkout`.
```js
"use strict";
let PayPalCheckout = require("@root/paypal-checkout");
PayPalCheckout.Product.categories.SOFTWARE; // "SOFTWARE"
```
They can also be used standalone:
```js
"use strict";
let ProductCategories = require("@root/paypal-checkout-product-categories");
ProductCategories.SOFTWARE; // "SOFTWARE"
```
## Full list
Scraped from <https://developer.paypal.com/docs/api/catalog-products/v1/>.
```txt
AC_REFRIGERATION_REPAIR
ACADEMIC_SOFTWARE
ACCESSORIES
ACCOUNTING
ADULT
ADVERTISING
AFFILIATED_AUTO_RENTAL
AGENCIES
AGGREGATORS
AGRICULTURAL_COOPERATIVE_FOR_MAIL_ORDER
AIR_CARRIERS_AIRLINES
AIRLINES
AIRPORTS_FLYING_FIELDS
ALCOHOLIC_BEVERAGES
AMUSEMENT_PARKS_CARNIVALS
ANIMATION
ANTIQUES
APPLIANCES
AQUARIAMS_SEAQUARIUMS_DOLPHINARIUMS
ARCHITECTURAL_ENGINEERING_AND_SURVEYING_SERVICES
ART_AND_CRAFT_SUPPLIES
ART_DEALERS_AND_GALLERIES
ARTIFACTS_GRAVE_RELATED_AND_NATIVE_AMERICAN_CRAFTS
ARTS_AND_CRAFTS
ARTS_CRAFTS_AND_COLLECTIBLES
AUDIO_BOOKS
AUTO_ASSOCIATIONS_CLUBS
AUTO_DEALER_USED_ONLY
AUTO_RENTALS
AUTO_SERVICE
AUTOMATED_FUEL_DISPENSERS
AUTOMOBILE_ASSOCIATIONS
AUTOMOTIVE
AUTOMOTIVE_REPAIR_SHOPS_NON_DEALER
AUTOMOTIVE_TOP_AND_BODY_SHOPS
AVIATION
BABIES_CLOTHING_AND_SUPPLIES
BABY
BANDS_ORCHESTRAS_ENTERTAINERS
BARBIES
BATH_AND_BODY
BATTERIES
BEAN_BABIES
BEAUTY
BEAUTY_AND_FRAGRANCES
BED_AND_BATH
BICYCLE_SHOPS_SALES_AND_SERVICE
BICYCLES_AND_ACCESSORIES
BILLIARD_POOL_ESTABLISHMENTS
BOAT_DEALERS
BOAT_RENTALS_AND_LEASING
BOATING_SAILING_AND_ACCESSORIES
BOOKS
BOOKS_AND_MAGAZINES
BOOKS_MANUSCRIPTS
BOOKS_PERIODICALS_AND_NEWSPAPERS
BOWLING_ALLEYS
BULLETIN_BOARD
BUS_LINE
BUS_LINES_CHARTERS_TOUR_BUSES
BUSINESS
BUSINESS_AND_SECRETARIAL_SCHOOLS
BUYING_AND_SHOPPING_SERVICES_AND_CLUBS
CABLE_SATELLITE_AND_OTHER_PAY_TELEVISION_AND_RADIO_SERVICES
CABLE_SATELLITE_AND_OTHER_PAY_TV_AND_RADIO
CAMERA_AND_PHOTOGRAPHIC_SUPPLIES
CAMERAS
CAMERAS_AND_PHOTOGRAPHY
CAMPER_RECREATIONAL_AND_UTILITY_TRAILER_DEALERS
CAMPING_AND_OUTDOORS
CAMPING_AND_SURVIVAL
CAR_AND_TRUCK_DEALERS
CAR_AND_TRUCK_DEALERS_USED_ONLY
CAR_AUDIO_AND_ELECTRONICS
CAR_RENTAL_AGENCY
CATALOG_MERCHANT
CATALOG_RETAIL_MERCHANT
CATERING_SERVICES
CHARITY
CHECK_CASHIER
CHILD_CARE_SERVICES
CHILDREN_BOOKS
CHIROPODISTS_PODIATRISTS
CHIROPRACTORS
CIGAR_STORES_AND_STANDS
CIVIC_SOCIAL_FRATERNAL_ASSOCIATIONS
CIVIL_SOCIAL_FRAT_ASSOCIATIONS
CLOTHING
CLOTHING_ACCESSORIES_AND_SHOES
CLOTHING_RENTAL
COFFEE_AND_TEA
COIN_OPERATED_BANKS_AND_CASINOS
COLLECTIBLES
COLLECTION_AGENCY
COLLEGES_AND_UNIVERSITIES
COMMERCIAL_EQUIPMENT
COMMERCIAL_FOOTWEAR
COMMERCIAL_PHOTOGRAPHY
COMMERCIAL_PHOTOGRAPHY_ART_AND_GRAPHICS
COMMERCIAL_SPORTS_PROFESSIONA
COMMODITIES_AND_FUTURES_EXCHANGE
COMPUTER_AND_DATA_PROCESSING_SERVICES
COMPUTER_HARDWARE_AND_SOFTWARE
COMPUTER_MAINTENANCE_REPAIR_AND_SERVICES_NOT_ELSEWHERE_CLAS
CONSTRUCTION
CONSTRUCTION_MATERIALS_NOT_ELSEWHERE_CLASSIFIED
CONSULTING_SERVICES
CONSUMER_CREDIT_REPORTING_AGENCIES
CONVALESCENT_HOMES
COSMETIC_STORES
COUNSELING_SERVICES_DEBT_MARRIAGE_PERSONAL
COUNTERFEIT_CURRENCY_AND_STAMPS
COUNTERFEIT_ITEMS
COUNTRY_CLUBS
COURIER_SERVICES
COURIER_SERVICES_AIR_AND_GROUND_AND_FREIGHT_FORWARDERS
COURT_COSTS_ALIMNY_CHILD_SUPT
COURT_COSTS_INCLUDING_ALIMONY_AND_CHILD_SUPPORT_COURTS_OF_LAW
CREDIT_CARDS
CREDIT_UNION
CULTURE_AND_RELIGION
DAIRY_PRODUCTS_STORES
DANCE_HALLS_STUDIOS_AND_SCHOOLS
DECORATIVE
DENTAL
DENTISTS_AND_ORTHODONTISTS
DEPARTMENT_STORES
DESKTOP_PCS
DEVICES
DIECAST_TOYS_VEHICLES
DIGITAL_GAMES
DIGITAL_MEDIA_BOOKS_MOVIES_MUSIC
DIRECT_MARKETING
DIRECT_MARKETING_CATALOG_MERCHANT
DIRECT_MARKETING_INBOUND_TELE
DIRECT_MARKETING_OUTBOUND_TELE
DIRECT_MARKETING_SUBSCRIPTION
DISCOUNT_STORES
DOOR_TO_DOOR_SALES
DRAPERY_WINDOW_COVERING_AND_UPHOLSTERY
DRINKING_PLACES
DRUGSTORE
DURABLE_GOODS
ECOMMERCE_DEVELOPMENT
ECOMMERCE_SERVICES
EDUCATIONAL_AND_TEXTBOOKS
ELECTRIC_RAZOR_STORES
ELECTRICAL_AND_SMALL_APPLIANCE_REPAIR
ELECTRICAL_CONTRACTORS
ELECTRICAL_PARTS_AND_EQUIPMENT
ELECTRONIC_CASH
ELEMENTARY_AND_SECONDARY_SCHOOLS
EMPLOYMENT
ENTERTAINERS
ENTERTAINMENT_AND_MEDIA
EQUIP_TOOL_FURNITURE_AND_APPLIANCE_RENTAL_AND_LEASING
ESCROW
EVENT_AND_WEDDING_PLANNING
EXERCISE_AND_FITNESS
EXERCISE_EQUIPMENT
EXTERMINATING_AND_DISINFECTING_SERVICES
FABRICS_AND_SEWING
FAMILY_CLOTHING_STORES
FASHION_JEWELRY
FAST_FOOD_RESTAURANTS
FICTION_AND_NONFICTION
FINANCE_COMPANY
FINANCIAL_AND_INVESTMENT_ADVICE
FINANCIAL_INSTITUTIONS_MERCHANDISE_AND_SERVICES
FIREARM_ACCESSORIES
FIREARMS_WEAPONS_AND_KNIVES
FIREPLACE_AND_FIREPLACE_SCREENS
FIREWORKS
FISHING
FLORISTS
FLOWERS
FOOD_DRINK_AND_NUTRITION
FOOD_PRODUCTS
FOOD_RETAIL_AND_SERVICE
FRAGRANCES_AND_PERFUMES
FREEZER_AND_LOCKER_MEAT_PROVISIONERS
FUEL_DEALERS_FUEL_OIL_WOOD_AND_COAL
FUEL_DEALERS_NON_AUTOMOTIVE
FUNERAL_SERVICES_AND_CREMATORIES
FURNISHING_AND_DECORATING
FURNITURE
FURRIERS_AND_FUR_SHOPS
GADGETS_AND_OTHER_ELECTRONICS
GAMBLING
GAME_SOFTWARE
GAMES
GARDEN_SUPPLIES
GENERAL
GENERAL_CONTRACTORS
GENERAL_GOVERNMENT
GENERAL_SOFTWARE
GENERAL_TELECOM
GIFTS_AND_FLOWERS
GLASS_PAINT_AND_WALLPAPER_STORES
GLASSWARE_CRYSTAL_STORES
GOVERNMENT
GOVERNMENT_IDS_AND_LICENSES
GOVERNMENT_LICENSED_ON_LINE_CASINOS_ON_LINE_GAMBLING
GOVERNMENT_OWNED_LOTTERIES
GOVERNMENT_SERVICES
GRAPHIC_AND_COMMERCIAL_DESIGN
GREETING_CARDS
GROCERY_STORES_AND_SUPERMARKETS
HARDWARE_AND_TOOLS
HARDWARE_EQUIPMENT_AND_SUPPLIES
HAZARDOUS_RESTRICTED_AND_PERISHABLE_ITEMS
HEALTH_AND_BEAUTY_SPAS
HEALTH_AND_NUTRITION
HEALTH_AND_PERSONAL_CARE
HEARING_AIDS_SALES_AND_SUPPLIES
HEATING_PLUMBING_AC
HIGH_RISK_MERCHANT
HIRING_SERVICES
HOBBIES_TOYS_AND_GAMES
HOME_AND_GARDEN
HOME_AUDIO
HOME_DECOR
HOME_ELECTRONICS
HOSPITALS
HOTELS_MOTELS_INNS_RESORTS
HOUSEWARES
HUMAN_PARTS_AND_REMAINS
HUMOROUS_GIFTS_AND_NOVELTIES
HUNTING
IDS_LICENSES_AND_PASSPORTS
ILLEGAL_DRUGS_AND_PARAPHERNALIA
INDUSTRIAL
INDUSTRIAL_AND_MANUFACTURING_SUPPLIES
INSURANCE_AUTO_AND_HOME
INSURANCE_DIRECT
INSURANCE_LIFE_AND_ANNUITY
INSURANCE_SALES_UNDERWRITING
INSURANCE_UNDERWRITING_PREMIUMS
INTERNET_AND_NETWORK_SERVICES
INTRA_COMPANY_PURCHASES
LABORATORIES_DENTAL_MEDICAL
LANDSCAPING
LANDSCAPING_AND_HORTICULTURAL_SERVICES
LAUNDRY_CLEANING_SERVICES
LEGAL
LEGAL_SERVICES_AND_ATTORNEYS
LOCAL_DELIVERY_SERVICE
LOCKSMITH
LODGING_AND_ACCOMMODATIONS
LOTTERY_AND_CONTESTS
LUGGAGE_AND_LEATHER_GOODS
LUMBER_AND_BUILDING_MATERIALS
MAGAZINES
MAINTENANCE_AND_REPAIR_SERVICES
MAKEUP_AND_COSMETICS
MANUAL_CASH_DISBURSEMENTS
MASSAGE_PARLORS
MEDICAL
MEDICAL_AND_PHARMACEUTICAL
MEDICAL_CARE
MEDICAL_EQUIPMENT_AND_SUPPLIES
MEDICAL_SERVICES
MEETING_PLANNERS
MEMBERSHIP_CLUBS_AND_ORGANIZATIONS
MEMBERSHIP_COUNTRY_CLUBS_GOLF
MEMORABILIA
MEN_AND_BOY_CLOTHING_AND_ACCESSORY_STORES
MEN_CLOTHING
MERCHANDISE
METAPHYSICAL
MILITARIA
MILITARY_AND_CIVIL_SERVICE_UNIFORMS
MISC._AUTOMOTIVE_AIRCRAFT_AND_FARM_EQUIPMENT_DEALERS
MISC._GENERAL_MERCHANDISE
MISCELLANEOUS_GENERAL_SERVICES
MISCELLANEOUS_REPAIR_SHOPS_AND_RELATED_SERVICES
MODEL_KITS
MONEY_TRANSFER_MEMBER_FINANCIAL_INSTITUTION
MONEY_TRANSFER_MERCHANT
MOTION_PICTURE_THEATERS
MOTOR_FREIGHT_CARRIERS_AND_TRUCKING
MOTOR_HOME_AND_RECREATIONAL_VEHICLE_RENTAL
MOTOR_HOMES_DEALERS
MOTOR_VEHICLE_SUPPLIES_AND_NEW_PARTS
MOTORCYCLE_DEALERS
MOTORCYCLES
MOVIE
MOVIE_TICKETS
MOVING_AND_STORAGE
MULTI_LEVEL_MARKETING
MUSIC_CDS_CASSETTES_AND_ALBUMS
MUSIC_STORE_INSTRUMENTS_AND_SHEET_MUSIC
NETWORKING
NEW_AGE
NEW_PARTS_AND_SUPPLIES_MOTOR_VEHICLE
NEWS_DEALERS_AND_NEWSTANDS
NON_DURABLE_GOODS
NON_FICTION
NON_PROFIT_POLITICAL_AND_RELIGION
NONPROFIT
NOVELTIES
OEM_SOFTWARE
OFFICE_SUPPLIES_AND_EQUIPMENT
ONLINE_DATING
ONLINE_GAMING
ONLINE_GAMING_CURRENCY
ONLINE_SERVICES
OOUTBOUND_TELEMARKETING_MERCH
OPHTHALMOLOGISTS_OPTOMETRIST
OPTICIANS_AND_DISPENSING
ORTHOPEDIC_GOODS_PROSTHETICS
OSTEOPATHS
OTHER
PACKAGE_TOUR_OPERATORS
PAINTBALL
PAINTS_VARNISHES_AND_SUPPLIES
PARKING_LOTS_AND_GARAGES
PARTS_AND_ACCESSORIES
PAWN_SHOPS
PAYCHECK_LENDER_OR_CASH_ADVANCE
PERIPHERALS
PERSONALIZED_GIFTS
PET_SHOPS_PET_FOOD_AND_SUPPLIES
PETROLEUM_AND_PETROLEUM_PRODUCTS
PETS_AND_ANIMALS
PHOTOFINISHING_LABORATORIES_PHOTO_DEVELOPING
PHOTOGRAPHIC_STUDIOS_PORTRAITS
PHOTOGRAPHY
PHYSICAL_GOOD
PICTURE_VIDEO_PRODUCTION
PIECE_GOODS_NOTIONS_AND_OTHER_DRY_GOODS
PLANTS_AND_SEEDS
PLUMBING_AND_HEATING_EQUIPMENTS_AND_SUPPLIES
POLICE_RELATED_ITEMS
POLITICAL_ORGANIZATIONS
POSTAL_SERVICES_GOVERNMENT_ONLY
POSTERS
PREPAID_AND_STORED_VALUE_CARDS
PRESCRIPTION_DRUGS
PROMOTIONAL_ITEMS
PUBLIC_WAREHOUSING_AND_STORAGE
PUBLISHING_AND_PRINTING
PUBLISHING_SERVICES
RADAR_DECTORS
RADIO_TELEVISION_AND_STEREO_REPAIR
REAL_ESTATE
REAL_ESTATE_AGENT
REAL_ESTATE_AGENTS_AND_MANAGERS_RENTALS
RELIGION_AND_SPIRITUALITY_FOR_PROFIT
RELIGIOUS
RELIGIOUS_ORGANIZATIONS
REMITTANCE
RENTAL_PROPERTY_MANAGEMENT
RESIDENTIAL
RETAIL
RETAIL_FINE_JEWELRY_AND_WATCHES
REUPHOLSTERY_AND_FURNITURE_REPAIR
RINGS
ROOFING_SIDING_SHEET_METAL
RUGS_AND_CARPETS
SCHOOLS_AND_COLLEGES
SCIENCE_FICTION
SCRAPBOOKING
SCULPTURES
SECURITIES_BROKERS_AND_DEALERS
SECURITY_AND_SURVEILLANCE
SECURITY_AND_SURVEILLANCE_EQUIPMENT
SECURITY_BROKERS_AND_DEALERS
SEMINARS
SERVICE_STATIONS
SERVICES
SEWING_NEEDLEWORK_FABRIC_AND_PIECE_GOODS_STORES
SHIPPING_AND_PACKING
SHOE_REPAIR_HAT_CLEANING
SHOE_STORES
SHOES
SNOWMOBILE_DEALERS
SOFTWARE
SPECIALTY_AND_MISC._FOOD_STORES
SPECIALTY_CLEANING_POLISHING_AND_SANITATION_PREPARATIONS
SPECIALTY_OR_RARE_PETS
SPORT_GAMES_AND_TOYS
SPORTING_AND_RECREATIONAL_CAMPS
SPORTING_GOODS
SPORTS_AND_OUTDOORS
SPORTS_AND_RECREATION
STAMP_AND_COIN
STATIONARY_PRINTING_AND_WRITING_PAPER
STENOGRAPHIC_AND_SECRETARIAL_SUPPORT_SERVICES
STOCKS_BONDS_SECURITIES_AND_RELATED_CERTIFICATES
STORED_VALUE_CARDS
SUPPLIES
SUPPLIES_AND_TOYS
SURVEILLANCE_EQUIPMENT
SWIMMING_POOLS_AND_SPAS
SWIMMING_POOLS_SALES_SUPPLIES_SERVICES
TAILORS_AND_ALTERATIONS
TAX_PAYMENTS
TAX_PAYMENTS_GOVERNMENT_AGENCIES
TAXICABS_AND_LIMOUSINES
TELECOMMUNICATION_SERVICES
TELEPHONE_CARDS
TELEPHONE_EQUIPMENT
TELEPHONE_SERVICES
THEATER
TIRE_RETREADING_AND_REPAIR
TOLL_OR_BRIDGE_FEES
TOOLS_AND_EQUIPMENT
TOURIST_ATTRACTIONS_AND_EXHIBITS
TOWING_SERVICE
TOYS_AND_GAMES
TRADE_AND_VOCATIONAL_SCHOOLS
TRADEMARK_INFRINGEMENT
TRAILER_PARKS_AND_CAMPGROUNDS
TRAINING_SERVICES
TRANSPORTATION_SERVICES
TRAVEL
TRUCK_AND_UTILITY_TRAILER_RENTALS
TRUCK_STOP
TYPESETTING_PLATE_MAKING_AND_RELATED_SERVICES
USED_MERCHANDISE_AND_SECONDHAND_STORES
USED_PARTS_MOTOR_VEHICLE
UTILITIES
UTILITIES_ELECTRIC_GAS_WATER_SANITARY
VARIETY_STORES
VEHICLE_SALES
VEHICLE_SERVICE_AND_ACCESSORIES
VIDEO_EQUIPMENT
VIDEO_GAME_ARCADES_ESTABLISH
VIDEO_GAMES_AND_SYSTEMS
VIDEO_TAPE_RENTAL_STORES
VINTAGE_AND_COLLECTIBLE_VEHICLES
VINTAGE_AND_COLLECTIBLES
VITAMINS_AND_SUPPLEMENTS
VOCATIONAL_AND_TRADE_SCHOOLS
WATCH_CLOCK_AND_JEWELRY_REPAIR
WEB_HOSTING_AND_DESIGN
WELDING_REPAIR
WHOLESALE_CLUBS
WHOLESALE_FLORIST_SUPPLIERS
WHOLESALE_PRESCRIPTION_DRUGS
WILDLIFE_PRODUCTS
WIRE_TRANSFER
WIRE_TRANSFER_AND_MONEY_ORDER
WOMEN_ACCESSORY_SPECIALITY
WOMEN_CLOTHING
```

45
vendor/product-categories/build.js vendored Normal file
View File

@ -0,0 +1,45 @@
// Documented under "categories" at
// https://developer.paypal.com/docs/api/catalog-products/v1/
/*
// To scrape the full list from the site:
var categories = [];
var $c = $$('.dax-def-label code').find(function ($el) {
if ("category" === $el.innerText.toLowerCase()) {
return $el;
}
});
$c.closest('div').nextElementSibling.querySelectorAll('li').forEach(function ($el) {
categories.push($el.querySelector('code').innerText);
});
console.info(JSON.stringify(categories));
*/
let Fs = require("fs");
let Path = require("path");
let categories = Fs.readFileSync(Path.join(__dirname, "categories.txt"), 'utf8')
.split(/[\n\r\s]/)
.filter(Boolean);
let categoriesMap = categories.reduce(function (obj, name) {
obj[name] = name;
return obj;
}, {});
//Fs.mkdirSync(Path.join(__dirname, "../lib"), { recursive: true });
let categoriesJson = JSON.stringify(categoriesMap, null, 2).replace(
/"(\w+)":.*/g,
"$1: \"\","
);
Fs.writeFileSync(
Path.join(__dirname, "categories.js"),
`"use strict";
module.exports = ${categoriesJson};
// set the value to be the same string as the key
Object.keys(module.exports).forEach(function (k) {
module.exports[k] = k;
});
`,
"utf8"
);

446
vendor/product-categories/categories.txt vendored Normal file
View File

@ -0,0 +1,446 @@
AC_REFRIGERATION_REPAIR
ACADEMIC_SOFTWARE
ACCESSORIES
ACCOUNTING
ADULT
ADVERTISING
AFFILIATED_AUTO_RENTAL
AGENCIES
AGGREGATORS
AGRICULTURAL_COOPERATIVE_FOR_MAIL_ORDER
AIR_CARRIERS_AIRLINES
AIRLINES
AIRPORTS_FLYING_FIELDS
ALCOHOLIC_BEVERAGES
AMUSEMENT_PARKS_CARNIVALS
ANIMATION
ANTIQUES
APPLIANCES
AQUARIAMS_SEAQUARIUMS_DOLPHINARIUMS
ARCHITECTURAL_ENGINEERING_AND_SURVEYING_SERVICES
ART_AND_CRAFT_SUPPLIES
ART_DEALERS_AND_GALLERIES
ARTIFACTS_GRAVE_RELATED_AND_NATIVE_AMERICAN_CRAFTS
ARTS_AND_CRAFTS
ARTS_CRAFTS_AND_COLLECTIBLES
AUDIO_BOOKS
AUTO_ASSOCIATIONS_CLUBS
AUTO_DEALER_USED_ONLY
AUTO_RENTALS
AUTO_SERVICE
AUTOMATED_FUEL_DISPENSERS
AUTOMOBILE_ASSOCIATIONS
AUTOMOTIVE
AUTOMOTIVE_REPAIR_SHOPS_NON_DEALER
AUTOMOTIVE_TOP_AND_BODY_SHOPS
AVIATION
BABIES_CLOTHING_AND_SUPPLIES
BABY
BANDS_ORCHESTRAS_ENTERTAINERS
BARBIES
BATH_AND_BODY
BATTERIES
BEAN_BABIES
BEAUTY
BEAUTY_AND_FRAGRANCES
BED_AND_BATH
BICYCLE_SHOPS_SALES_AND_SERVICE
BICYCLES_AND_ACCESSORIES
BILLIARD_POOL_ESTABLISHMENTS
BOAT_DEALERS
BOAT_RENTALS_AND_LEASING
BOATING_SAILING_AND_ACCESSORIES
BOOKS
BOOKS_AND_MAGAZINES
BOOKS_MANUSCRIPTS
BOOKS_PERIODICALS_AND_NEWSPAPERS
BOWLING_ALLEYS
BULLETIN_BOARD
BUS_LINE
BUS_LINES_CHARTERS_TOUR_BUSES
BUSINESS
BUSINESS_AND_SECRETARIAL_SCHOOLS
BUYING_AND_SHOPPING_SERVICES_AND_CLUBS
CABLE_SATELLITE_AND_OTHER_PAY_TELEVISION_AND_RADIO_SERVICES
CABLE_SATELLITE_AND_OTHER_PAY_TV_AND_RADIO
CAMERA_AND_PHOTOGRAPHIC_SUPPLIES
CAMERAS
CAMERAS_AND_PHOTOGRAPHY
CAMPER_RECREATIONAL_AND_UTILITY_TRAILER_DEALERS
CAMPING_AND_OUTDOORS
CAMPING_AND_SURVIVAL
CAR_AND_TRUCK_DEALERS
CAR_AND_TRUCK_DEALERS_USED_ONLY
CAR_AUDIO_AND_ELECTRONICS
CAR_RENTAL_AGENCY
CATALOG_MERCHANT
CATALOG_RETAIL_MERCHANT
CATERING_SERVICES
CHARITY
CHECK_CASHIER
CHILD_CARE_SERVICES
CHILDREN_BOOKS
CHIROPODISTS_PODIATRISTS
CHIROPRACTORS
CIGAR_STORES_AND_STANDS
CIVIC_SOCIAL_FRATERNAL_ASSOCIATIONS
CIVIL_SOCIAL_FRAT_ASSOCIATIONS
CLOTHING
CLOTHING_ACCESSORIES_AND_SHOES
CLOTHING_RENTAL
COFFEE_AND_TEA
COIN_OPERATED_BANKS_AND_CASINOS
COLLECTIBLES
COLLECTION_AGENCY
COLLEGES_AND_UNIVERSITIES
COMMERCIAL_EQUIPMENT
COMMERCIAL_FOOTWEAR
COMMERCIAL_PHOTOGRAPHY
COMMERCIAL_PHOTOGRAPHY_ART_AND_GRAPHICS
COMMERCIAL_SPORTS_PROFESSIONA
COMMODITIES_AND_FUTURES_EXCHANGE
COMPUTER_AND_DATA_PROCESSING_SERVICES
COMPUTER_HARDWARE_AND_SOFTWARE
COMPUTER_MAINTENANCE_REPAIR_AND_SERVICES_NOT_ELSEWHERE_CLAS
CONSTRUCTION
CONSTRUCTION_MATERIALS_NOT_ELSEWHERE_CLASSIFIED
CONSULTING_SERVICES
CONSUMER_CREDIT_REPORTING_AGENCIES
CONVALESCENT_HOMES
COSMETIC_STORES
COUNSELING_SERVICES_DEBT_MARRIAGE_PERSONAL
COUNTERFEIT_CURRENCY_AND_STAMPS
COUNTERFEIT_ITEMS
COUNTRY_CLUBS
COURIER_SERVICES
COURIER_SERVICES_AIR_AND_GROUND_AND_FREIGHT_FORWARDERS
COURT_COSTS_ALIMNY_CHILD_SUPT
COURT_COSTS_INCLUDING_ALIMONY_AND_CHILD_SUPPORT_COURTS_OF_LAW
CREDIT_CARDS
CREDIT_UNION
CULTURE_AND_RELIGION
DAIRY_PRODUCTS_STORES
DANCE_HALLS_STUDIOS_AND_SCHOOLS
DECORATIVE
DENTAL
DENTISTS_AND_ORTHODONTISTS
DEPARTMENT_STORES
DESKTOP_PCS
DEVICES
DIECAST_TOYS_VEHICLES
DIGITAL_GAMES
DIGITAL_MEDIA_BOOKS_MOVIES_MUSIC
DIRECT_MARKETING
DIRECT_MARKETING_CATALOG_MERCHANT
DIRECT_MARKETING_INBOUND_TELE
DIRECT_MARKETING_OUTBOUND_TELE
DIRECT_MARKETING_SUBSCRIPTION
DISCOUNT_STORES
DOOR_TO_DOOR_SALES
DRAPERY_WINDOW_COVERING_AND_UPHOLSTERY
DRINKING_PLACES
DRUGSTORE
DURABLE_GOODS
ECOMMERCE_DEVELOPMENT
ECOMMERCE_SERVICES
EDUCATIONAL_AND_TEXTBOOKS
ELECTRIC_RAZOR_STORES
ELECTRICAL_AND_SMALL_APPLIANCE_REPAIR
ELECTRICAL_CONTRACTORS
ELECTRICAL_PARTS_AND_EQUIPMENT
ELECTRONIC_CASH
ELEMENTARY_AND_SECONDARY_SCHOOLS
EMPLOYMENT
ENTERTAINERS
ENTERTAINMENT_AND_MEDIA
EQUIP_TOOL_FURNITURE_AND_APPLIANCE_RENTAL_AND_LEASING
ESCROW
EVENT_AND_WEDDING_PLANNING
EXERCISE_AND_FITNESS
EXERCISE_EQUIPMENT
EXTERMINATING_AND_DISINFECTING_SERVICES
FABRICS_AND_SEWING
FAMILY_CLOTHING_STORES
FASHION_JEWELRY
FAST_FOOD_RESTAURANTS
FICTION_AND_NONFICTION
FINANCE_COMPANY
FINANCIAL_AND_INVESTMENT_ADVICE
FINANCIAL_INSTITUTIONS_MERCHANDISE_AND_SERVICES
FIREARM_ACCESSORIES
FIREARMS_WEAPONS_AND_KNIVES
FIREPLACE_AND_FIREPLACE_SCREENS
FIREWORKS
FISHING
FLORISTS
FLOWERS
FOOD_DRINK_AND_NUTRITION
FOOD_PRODUCTS
FOOD_RETAIL_AND_SERVICE
FRAGRANCES_AND_PERFUMES
FREEZER_AND_LOCKER_MEAT_PROVISIONERS
FUEL_DEALERS_FUEL_OIL_WOOD_AND_COAL
FUEL_DEALERS_NON_AUTOMOTIVE
FUNERAL_SERVICES_AND_CREMATORIES
FURNISHING_AND_DECORATING
FURNITURE
FURRIERS_AND_FUR_SHOPS
GADGETS_AND_OTHER_ELECTRONICS
GAMBLING
GAME_SOFTWARE
GAMES
GARDEN_SUPPLIES
GENERAL
GENERAL_CONTRACTORS
GENERAL_GOVERNMENT
GENERAL_SOFTWARE
GENERAL_TELECOM
GIFTS_AND_FLOWERS
GLASS_PAINT_AND_WALLPAPER_STORES
GLASSWARE_CRYSTAL_STORES
GOVERNMENT
GOVERNMENT_IDS_AND_LICENSES
GOVERNMENT_LICENSED_ON_LINE_CASINOS_ON_LINE_GAMBLING
GOVERNMENT_OWNED_LOTTERIES
GOVERNMENT_SERVICES
GRAPHIC_AND_COMMERCIAL_DESIGN
GREETING_CARDS
GROCERY_STORES_AND_SUPERMARKETS
HARDWARE_AND_TOOLS
HARDWARE_EQUIPMENT_AND_SUPPLIES
HAZARDOUS_RESTRICTED_AND_PERISHABLE_ITEMS
HEALTH_AND_BEAUTY_SPAS
HEALTH_AND_NUTRITION
HEALTH_AND_PERSONAL_CARE
HEARING_AIDS_SALES_AND_SUPPLIES
HEATING_PLUMBING_AC
HIGH_RISK_MERCHANT
HIRING_SERVICES
HOBBIES_TOYS_AND_GAMES
HOME_AND_GARDEN
HOME_AUDIO
HOME_DECOR
HOME_ELECTRONICS
HOSPITALS
HOTELS_MOTELS_INNS_RESORTS
HOUSEWARES
HUMAN_PARTS_AND_REMAINS
HUMOROUS_GIFTS_AND_NOVELTIES
HUNTING
IDS_LICENSES_AND_PASSPORTS
ILLEGAL_DRUGS_AND_PARAPHERNALIA
INDUSTRIAL
INDUSTRIAL_AND_MANUFACTURING_SUPPLIES
INSURANCE_AUTO_AND_HOME
INSURANCE_DIRECT
INSURANCE_LIFE_AND_ANNUITY
INSURANCE_SALES_UNDERWRITING
INSURANCE_UNDERWRITING_PREMIUMS
INTERNET_AND_NETWORK_SERVICES
INTRA_COMPANY_PURCHASES
LABORATORIES_DENTAL_MEDICAL
LANDSCAPING
LANDSCAPING_AND_HORTICULTURAL_SERVICES
LAUNDRY_CLEANING_SERVICES
LEGAL
LEGAL_SERVICES_AND_ATTORNEYS
LOCAL_DELIVERY_SERVICE
LOCKSMITH
LODGING_AND_ACCOMMODATIONS
LOTTERY_AND_CONTESTS
LUGGAGE_AND_LEATHER_GOODS
LUMBER_AND_BUILDING_MATERIALS
MAGAZINES
MAINTENANCE_AND_REPAIR_SERVICES
MAKEUP_AND_COSMETICS
MANUAL_CASH_DISBURSEMENTS
MASSAGE_PARLORS
MEDICAL
MEDICAL_AND_PHARMACEUTICAL
MEDICAL_CARE
MEDICAL_EQUIPMENT_AND_SUPPLIES
MEDICAL_SERVICES
MEETING_PLANNERS
MEMBERSHIP_CLUBS_AND_ORGANIZATIONS
MEMBERSHIP_COUNTRY_CLUBS_GOLF
MEMORABILIA
MEN_AND_BOY_CLOTHING_AND_ACCESSORY_STORES
MEN_CLOTHING
MERCHANDISE
METAPHYSICAL
MILITARIA
MILITARY_AND_CIVIL_SERVICE_UNIFORMS
MISC._AUTOMOTIVE_AIRCRAFT_AND_FARM_EQUIPMENT_DEALERS
MISC._GENERAL_MERCHANDISE
MISCELLANEOUS_GENERAL_SERVICES
MISCELLANEOUS_REPAIR_SHOPS_AND_RELATED_SERVICES
MODEL_KITS
MONEY_TRANSFER_MEMBER_FINANCIAL_INSTITUTION
MONEY_TRANSFER_MERCHANT
MOTION_PICTURE_THEATERS
MOTOR_FREIGHT_CARRIERS_AND_TRUCKING
MOTOR_HOME_AND_RECREATIONAL_VEHICLE_RENTAL
MOTOR_HOMES_DEALERS
MOTOR_VEHICLE_SUPPLIES_AND_NEW_PARTS
MOTORCYCLE_DEALERS
MOTORCYCLES
MOVIE
MOVIE_TICKETS
MOVING_AND_STORAGE
MULTI_LEVEL_MARKETING
MUSIC_CDS_CASSETTES_AND_ALBUMS
MUSIC_STORE_INSTRUMENTS_AND_SHEET_MUSIC
NETWORKING
NEW_AGE
NEW_PARTS_AND_SUPPLIES_MOTOR_VEHICLE
NEWS_DEALERS_AND_NEWSTANDS
NON_DURABLE_GOODS
NON_FICTION
NON_PROFIT_POLITICAL_AND_RELIGION
NONPROFIT
NOVELTIES
OEM_SOFTWARE
OFFICE_SUPPLIES_AND_EQUIPMENT
ONLINE_DATING
ONLINE_GAMING
ONLINE_GAMING_CURRENCY
ONLINE_SERVICES
OOUTBOUND_TELEMARKETING_MERCH
OPHTHALMOLOGISTS_OPTOMETRIST
OPTICIANS_AND_DISPENSING
ORTHOPEDIC_GOODS_PROSTHETICS
OSTEOPATHS
OTHER
PACKAGE_TOUR_OPERATORS
PAINTBALL
PAINTS_VARNISHES_AND_SUPPLIES
PARKING_LOTS_AND_GARAGES
PARTS_AND_ACCESSORIES
PAWN_SHOPS
PAYCHECK_LENDER_OR_CASH_ADVANCE
PERIPHERALS
PERSONALIZED_GIFTS
PET_SHOPS_PET_FOOD_AND_SUPPLIES
PETROLEUM_AND_PETROLEUM_PRODUCTS
PETS_AND_ANIMALS
PHOTOFINISHING_LABORATORIES_PHOTO_DEVELOPING
PHOTOGRAPHIC_STUDIOS_PORTRAITS
PHOTOGRAPHY
PHYSICAL_GOOD
PICTURE_VIDEO_PRODUCTION
PIECE_GOODS_NOTIONS_AND_OTHER_DRY_GOODS
PLANTS_AND_SEEDS
PLUMBING_AND_HEATING_EQUIPMENTS_AND_SUPPLIES
POLICE_RELATED_ITEMS
POLITICAL_ORGANIZATIONS
POSTAL_SERVICES_GOVERNMENT_ONLY
POSTERS
PREPAID_AND_STORED_VALUE_CARDS
PRESCRIPTION_DRUGS
PROMOTIONAL_ITEMS
PUBLIC_WAREHOUSING_AND_STORAGE
PUBLISHING_AND_PRINTING
PUBLISHING_SERVICES
RADAR_DECTORS
RADIO_TELEVISION_AND_STEREO_REPAIR
REAL_ESTATE
REAL_ESTATE_AGENT
REAL_ESTATE_AGENTS_AND_MANAGERS_RENTALS
RELIGION_AND_SPIRITUALITY_FOR_PROFIT
RELIGIOUS
RELIGIOUS_ORGANIZATIONS
REMITTANCE
RENTAL_PROPERTY_MANAGEMENT
RESIDENTIAL
RETAIL
RETAIL_FINE_JEWELRY_AND_WATCHES
REUPHOLSTERY_AND_FURNITURE_REPAIR
RINGS
ROOFING_SIDING_SHEET_METAL
RUGS_AND_CARPETS
SCHOOLS_AND_COLLEGES
SCIENCE_FICTION
SCRAPBOOKING
SCULPTURES
SECURITIES_BROKERS_AND_DEALERS
SECURITY_AND_SURVEILLANCE
SECURITY_AND_SURVEILLANCE_EQUIPMENT
SECURITY_BROKERS_AND_DEALERS
SEMINARS
SERVICE_STATIONS
SERVICES
SEWING_NEEDLEWORK_FABRIC_AND_PIECE_GOODS_STORES
SHIPPING_AND_PACKING
SHOE_REPAIR_HAT_CLEANING
SHOE_STORES
SHOES
SNOWMOBILE_DEALERS
SOFTWARE
SPECIALTY_AND_MISC._FOOD_STORES
SPECIALTY_CLEANING_POLISHING_AND_SANITATION_PREPARATIONS
SPECIALTY_OR_RARE_PETS
SPORT_GAMES_AND_TOYS
SPORTING_AND_RECREATIONAL_CAMPS
SPORTING_GOODS
SPORTS_AND_OUTDOORS
SPORTS_AND_RECREATION
STAMP_AND_COIN
STATIONARY_PRINTING_AND_WRITING_PAPER
STENOGRAPHIC_AND_SECRETARIAL_SUPPORT_SERVICES
STOCKS_BONDS_SECURITIES_AND_RELATED_CERTIFICATES
STORED_VALUE_CARDS
SUPPLIES
SUPPLIES_AND_TOYS
SURVEILLANCE_EQUIPMENT
SWIMMING_POOLS_AND_SPAS
SWIMMING_POOLS_SALES_SUPPLIES_SERVICES
TAILORS_AND_ALTERATIONS
TAX_PAYMENTS
TAX_PAYMENTS_GOVERNMENT_AGENCIES
TAXICABS_AND_LIMOUSINES
TELECOMMUNICATION_SERVICES
TELEPHONE_CARDS
TELEPHONE_EQUIPMENT
TELEPHONE_SERVICES
THEATER
TIRE_RETREADING_AND_REPAIR
TOLL_OR_BRIDGE_FEES
TOOLS_AND_EQUIPMENT
TOURIST_ATTRACTIONS_AND_EXHIBITS
TOWING_SERVICE
TOYS_AND_GAMES
TRADE_AND_VOCATIONAL_SCHOOLS
TRADEMARK_INFRINGEMENT
TRAILER_PARKS_AND_CAMPGROUNDS
TRAINING_SERVICES
TRANSPORTATION_SERVICES
TRAVEL
TRUCK_AND_UTILITY_TRAILER_RENTALS
TRUCK_STOP
TYPESETTING_PLATE_MAKING_AND_RELATED_SERVICES
USED_MERCHANDISE_AND_SECONDHAND_STORES
USED_PARTS_MOTOR_VEHICLE
UTILITIES
UTILITIES_ELECTRIC_GAS_WATER_SANITARY
VARIETY_STORES
VEHICLE_SALES
VEHICLE_SERVICE_AND_ACCESSORIES
VIDEO_EQUIPMENT
VIDEO_GAME_ARCADES_ESTABLISH
VIDEO_GAMES_AND_SYSTEMS
VIDEO_TAPE_RENTAL_STORES
VINTAGE_AND_COLLECTIBLE_VEHICLES
VINTAGE_AND_COLLECTIBLES
VITAMINS_AND_SUPPLEMENTS
VOCATIONAL_AND_TRADE_SCHOOLS
WATCH_CLOCK_AND_JEWELRY_REPAIR
WEB_HOSTING_AND_DESIGN
WELDING_REPAIR
WHOLESALE_CLUBS
WHOLESALE_FLORIST_SUPPLIERS
WHOLESALE_PRESCRIPTION_DRUGS
WILDLIFE_PRODUCTS
WIRE_TRANSFER
WIRE_TRANSFER_AND_MONEY_ORDER
WOMEN_ACCESSORY_SPECIALITY
WOMEN_CLOTHING

3
vendor/product-categories/index.js vendored Normal file
View File

@ -0,0 +1,3 @@
'use strict';
module.exports = require('./categories.js');

13
vendor/product-categories/package-lock.json generated vendored Normal file
View File

@ -0,0 +1,13 @@
{
"name": "@root/paypal-checkout-product-categories",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@root/paypal-checkout-product-categories",
"version": "1.0.0",
"license": "(CC0-1.0 OR MIT)"
}
}
}

23
vendor/product-categories/package.json vendored Normal file
View File

@ -0,0 +1,23 @@
{
"name": "@root/paypal-checkout-product-categories",
"version": "1.0.0",
"description": "Full list of product categories for Type Linting and Auto-Complete with @root/paypal-checkout",
"main": "index.js",
"files": ["categories.js"],
"scripts": {
"prepare": "node build.js",
"build": "node build.js",
"test": "node test.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/therootcompany/paypal-checkout.js.git"
},
"keywords": ["PayPal", "Checkout", "Product", "Categories", "API", "SDK"],
"author": "AJ ONeal <aj@therootcompany.com> (https://therootcompany.com/)",
"license": "(CC0-1.0 OR MIT)",
"bugs": {
"url": "https://github.com/therootcompany/paypal-checkout.js/issues"
},
"homepage": "https://github.com/therootcompany/paypal-checkout.js#readme"
}

8
vendor/product-categories/test.js vendored Normal file
View File

@ -0,0 +1,8 @@
"use strict";
if ("SOFTWARE" !== require("./categories.js").SOFTWARE) {
console.error(`FAIL: SOFTWARE !== "SOFTWARE"`);
process.exit(1);
}
console.info("PASS");