WIP: Order.{createRequest,capture}

This commit is contained in:
AJ ONeal 2021-10-16 22:07:59 -06:00
parent 19cfcabc27
commit e1fa70d495
4 changed files with 198 additions and 2 deletions

View File

@ -46,7 +46,11 @@ PPC.Subscriptions.createRequest({
```txt ```txt
PayPal.init(client_id, client_secret, 'sandbox|live', defaults); PayPal.init(client_id, client_secret, 'sandbox|live', defaults);
PayPal.request({ method, url, headers, json }); PayPal.request({ method, url, headers, json });
```
### Subscrptions (Recurring Payments)
```txt
// Webhook 'event_type': // Webhook 'event_type':
PayPal.Product.create({ ... }); // CATALOG.PRODUCT.CREATED PayPal.Product.create({ ... }); // CATALOG.PRODUCT.CREATED
@ -66,11 +70,47 @@ PayPal.Subscription.details(id);
PayPal.Subscription.cancel(id, { reason }); PayPal.Subscription.cancel(id, { reason });
``` ```
### Orders (One-Time Payments)
```txt
PayPal.Order.createRequest({ ... }); // ??
```
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>
# Redirects # Redirects
- `return_url` - `return_url`
- `cancel_url` - `cancel_url`
### Orders
#### `return_url`
Order Request `return_url` will be called with the `token` query param as the
`order_id`:
```txt
https://example.com/redirects/paypal-checkout/return
?token=XXXXXXXXXXXXXXXXX
&PayerID=XXXXXXXXXXXXX
```
Again, `token` is the `order_id`.
#### `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 status.
It's up to you to confirm with the user and change the status to `CANCELLED`.
### Subscriptions
#### `return_url` #### `return_url`
Subscription Request `return_url` will include the following: Subscription Request `return_url` will include the following:

View File

@ -114,6 +114,69 @@ function enumify(obj) {
} }
*/ */
let Order = {};
Order.intents = {
CAPTURE: "CAPTURE",
AUTHORIZE: "AUTHORIZE",
};
// 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 = {}; let Product = {};
// SaaS would be type=SERVICE, category=SOFTWARE // SaaS would be type=SERVICE, category=SOFTWARE
@ -447,6 +510,7 @@ Subscription.cancel = async function _showProductDetails(id, { reason }) {
module.exports.init = PayPal.init; module.exports.init = PayPal.init;
module.exports.request = PayPal.request; module.exports.request = PayPal.request;
module.exports.Order = Order;
module.exports.Plan = Plan; module.exports.Plan = Plan;
module.exports.Product = Product; module.exports.Product = Product;
module.exports.Subscription = Subscription; module.exports.Subscription = Subscription;

View File

@ -11,7 +11,7 @@ if (!process.env.PAYPAL_CLIENT_ID) {
} }
let PayPal = require("../"); let PayPal = require("../");
let { Plan, Product, Subscription } = PayPal; let { Plan, Product /*, Subscription*/ } = PayPal;
async function test() { async function test() {
let products = await Product.list(); let products = await Product.list();
@ -48,7 +48,11 @@ async function test() {
} }
if (require.main === module) { if (require.main === module) {
PayPal.init(process.env.PAYPAL_CLIENT_ID, process.env.PAYPAL_CLIENT_SECRET); PayPal.init(
process.env.PAYPAL_CLIENT_ID,
process.env.PAYPAL_CLIENT_SECRET,
"sandbox"
);
test().catch(function (err) { test().catch(function (err) {
console.error("Something bad happened:"); console.error("Something bad happened:");
console.error(JSON.stringify(err, null, 2)); 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));
});
}