From: Nick Downing Date: Sun, 19 Dec 2021 02:16:07 +0000 (+1100) Subject: Initial commit, port PayPalCheckoutServerSideV2_nodejs.zip to jst_server X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=74e333576cd1550089c455de0b727753a4b58287;p=paypal_example_site.git Initial commit, port PayPalCheckoutServerSideV2_nodejs.zip to jst_server --- 74e333576cd1550089c455de0b727753a4b58287 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e0ecbc3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +.*.deps +.*.html +.*.json +.*.jst +.*.less +.*.min +.*.svg +/node_modules +/pnpm-lock.yaml diff --git a/_config/config.json b/_config/config.json new file mode 100644 index 0000000..4d54786 --- /dev/null +++ b/_config/config.json @@ -0,0 +1,7 @@ +{ + "environment": "sandbox", + "sandbox_client_id": "Aa2IfcoEvHnfJRnVQLSFrSs3SmTTkv5N1weMEL66ysqYIeHfAqXpDVkjOv3vLhkhbP4eKB6MpRlQIcJw", + "sandbox_secret": "EF6l6PDQJEZbdKTeg35pbBSft6WRdALQC3Xrl5vvG0VNgBUehQyTCQ09QdIauxoccvJOf5Aoy-OGsH5G", + "production_client_id": "", + "production_secret": "" +} \ No newline at end of file diff --git a/_config/server.jst b/_config/server.jst new file mode 100644 index 0000000..e6ebffc --- /dev/null +++ b/_config/server.jst @@ -0,0 +1,16 @@ +return async (resources, prev_server) => new _jst_server.Server( + resources, + { + hosts: { + 'localhost': { + type: 'site', + root: '.' + }, + 'localhost.localdomain': { + type: 'redirect', + host: 'localhost' + } + } + }, + prev_server +) diff --git a/_config/site.jst b/_config/site.jst new file mode 100644 index 0000000..dd80b4d --- /dev/null +++ b/_config/site.jst @@ -0,0 +1,26 @@ +let CustomSite = function(resources, root, options, prev_site) { + if (!this instanceof CustomSite) + throw Error('CustomSite is a constructor') + _jst_server.Site.call(this, resources, root, options, prev_site) +} + +CustomSite.prototype = Object.create(_jst_server.Site.prototype) + +CustomSite.prototype.respond = async function(env) { + if ( + env.parsed_url.pathname === '/node_modules' || + env.parsed_url.pathname.slice(0, 14) === '/node_modules/' || + env.parsed_url.pathname === '/package.json' + ) { + this.die(env, `banned file ${env.parsed_url.pathname}`) + return + } + return /*await*/ _jst_server.Site.prototype.respond.call(this, env) +} + +return async (resources, root, prev_site) => new CustomSite( + resources, + root, + {}, + prev_site +) diff --git a/_library/basic_functions.js b/_library/basic_functions.js new file mode 100644 index 0000000..b6ac0a9 --- /dev/null +++ b/_library/basic_functions.js @@ -0,0 +1,176 @@ +const https = require('https'); +const config = require('../_config/config.json'); +const get_oauth = () => { + return new Promise(resolve => { + + const data = 'grant_type=client_credentials'; + + const options = { + hostname: 'api.' + (config.environment === 'sandbox' ? 'sandbox.' : '') + 'paypal.com', + port: 443, + path: '/v1/oauth2/token', + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + 'Content-Length': data.length, + 'Authorization': 'Basic ' + Buffer.from((config.environment === 'sandbox' ? config.sandbox_client_id : config.production_client_id) + ':' + (config.environment === 'sandbox' ? config.sandbox_secret : config.production_secret)).toString('base64') + } + } + const my_callback = function(res){ + + let str=''; + + res.on('data',function(chunk){ + str+=chunk; + }); + + res.on('end',function(){ + obj=JSON.parse(str); + resolve(obj); + }); + } + let request = https.request(options, my_callback); + request.write(data); + request.end(); + + }); +}; +const get_access_token = () => { + return new Promise(resolve => { + get_oauth().then((response) => { + resolve(response.access_token); + }); + }); +}; +const create_order = (item_obj) => { + return new Promise(resolve => { + get_access_token().then((access_token) => { + + const options = { + hostname: 'api.' + (config.environment === 'sandbox' ? 'sandbox.' : '') + 'paypal.com', + port: 443, + path: '/v2/checkout/orders', + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + access_token + } + } + const my_callback = function(res){ + + let str=''; + + res.on('data',function(chunk){ + str+=chunk; + }); + + res.on('end',function(){ + obj=JSON.parse(str); + resolve(obj); + }); + } + let request = https.request(options,my_callback); + request.write(JSON.stringify(item_obj)); + request.end(); + + }); + + }); +}; +const get_order_details = (order_id) => { + return new Promise(resolve => { + get_access_token().then((access_token) => { + + const options = { + hostname: 'api.' + (config.environment === 'sandbox' ? 'sandbox.' : '') + 'paypal.com', + port: 443, + path: '/v2/checkout/orders/' + order_id, + method: 'GET', + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + access_token + } + } + const my_callback = function(res){ + + let str=''; + + res.on('data',function(chunk){ + str+=chunk; + }); + + res.on('end',function(){ + obj=JSON.parse(str); + resolve(obj); + }); + } + let request = https.request(options,my_callback); + request.end(); + + }); + + }); +}; +const patch_order_details = (new_order_details) => { + return new Promise((resolve, reject) => { + get_access_token().then((access_token) => { + patch_details = new_order_details.patch_details; + order_id = new_order_details.order_id; + const options = { + hostname: 'api.' + (config.environment === 'sandbox' ? 'sandbox.' : '') + 'paypal.com', + port: 443, + path: '/v2/checkout/orders/' + order_id, + method: 'PATCH', + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + access_token + } + } + let request = https.request(options, function (response) { + resolve(response.statusCode); + }); + request.write(JSON.stringify(patch_details)); + request.end(); + }); +}); + +}; +const capture_order = (order_id) => { + return new Promise(resolve => { + get_access_token().then((access_token) => { + const options = { + hostname: 'api.' + (config.environment === 'sandbox' ? 'sandbox.' : '') + 'paypal.com', + port: 443, + path: '/v2/checkout/orders/' + order_id + '/capture', + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + access_token, + 'return': 'representation', + 'PayPal-Partner-Attribution-Id': 'PP-DemoPortal-Checkout-NodeJS-SDK' + } + } + const my_callback = function(res){ + let str=''; + res.on('data',function(chunk){ + str+=chunk; + }); + res.on('end',function(){ + obj=JSON.parse(str); + resolve(obj); + }); + } + let request = https.request(options,my_callback); + request.end(); + }); + }); +}; + +module.exports = { + get_access_token: get_access_token, + get_oauth: get_oauth, + create_order: create_order, + get_order_details: get_order_details, + patch_order_details: patch_order_details, + capture_order: capture_order +}; diff --git a/_library/random_number.js b/_library/random_number.js new file mode 100644 index 0000000..a446935 --- /dev/null +++ b/_library/random_number.js @@ -0,0 +1 @@ +module.exports = () => Math.floor(100000 + Math.random() * 900000) diff --git a/_orig/PayPalCheckoutServerSideV2_nodejs.zip b/_orig/PayPalCheckoutServerSideV2_nodejs.zip new file mode 100644 index 0000000..5e2c706 Binary files /dev/null and b/_orig/PayPalCheckoutServerSideV2_nodejs.zip differ diff --git a/_ssl/ca.conf b/_ssl/ca.conf new file mode 100644 index 0000000..d0d9a5f --- /dev/null +++ b/_ssl/ca.conf @@ -0,0 +1,25 @@ +[ ca ] +default_ca = CA_default # The default ca section + +[ CA_default ] + +#dir = ./demoCA # top dir +#database = $dir/index.txt # index file. +#new_certs_dir = $dir/newcerts # new certs dir +# +#certificate = $dir/cacert.pem # The CA cert +#serial = $dir/serial # serial no file +#private_key = $dir/private/cakey.pem# CA private key +#RANDFILE = $dir/private/.rand # random number file +# +default_days = 365 # how long to certify for +#default_crl_days= 30 # how long before next CRL +#default_md = md5 # md to use +# +#policy = policy_any # default policy +#email_in_dn = no # Don't add the email into cert DN +# +#name_opt = ca_default # Subject name display option +#cert_opt = ca_default # Certificate display option +#copy_extensions = none +copy_extensions = copyall diff --git a/_ssl/ca_cert.pem b/_ssl/ca_cert.pem new file mode 100644 index 0000000..74cb479 --- /dev/null +++ b/_ssl/ca_cert.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDazCCAlOgAwIBAgIUFREyB8FfpEHUio8HY7b0d7FaKdcwDQYJKoZIhvcNAQEL +BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMTExMDgwNzU0MTNaFw0yMTEy +MDgwNzU0MTNaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw +HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQDLY+eBF29tRNWwNb4uDdWUAs+7jDybeos94E8tgPKO +JEc2flBwolka9GU357x9J5v2KCnOuCkKArhL2tmkms5f2F4Eezb/l9DnryUdckqC +MI2bwAz/a/T+3HLjqI4l5mawE21JXNggqAccixRUY/gK3+V7M+zOdpwRc4v7Ca0R +sBwwfve8Ws8xqKryVFvzJM0QXiAjZvxMpLygdbnmjCKKVCY00Mfh20KqHYBMIMHa +M0RhdRrvi8/2oPfRcMByjZdjn8BQ+yUwQXbzP2MC+iq87lLuxUxEYGaQU4nzIMH1 +7Ga05t6zhF41jqDnrbjKgbgxPGNNxvau/rrpCnr++NQ/AgMBAAGjUzBRMB0GA1Ud +DgQWBBRBtnDR6bDQjBctACDXe2FTsASBEzAfBgNVHSMEGDAWgBRBtnDR6bDQjBct +ACDXe2FTsASBEzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCM +H2UzfYIphO/16z8SO0thdjexjfad0bMIZC39kD92ILHvxk68D0uel4q5Rp3+F66j +J7OupHIzEGSB23suw6n/cDrIJOa5VU9geaUZBVIH8GSy6nQTnkukiX92OTS11ecW +qABoACcptQz4oC3E68K6BYre4/QamJDAqdP4aNVbka040XTiWzvfRlOVeWz+gZTa +zObQiEzj1SwsYgcNSkrquZ/7vcEBaCncxXD8oRxqfEgNA6BRqUqnKCUSUmk/ed3b +hRSpHURjJGntHAzzFzaCC5dfMBEnAszfoOdLua/BV/JZcB7t4YIcIYMKdSYxpvoO +Nr3opPQhzBXur01KZuUA +-----END CERTIFICATE----- diff --git a/_ssl/ca_cert.srl b/_ssl/ca_cert.srl new file mode 100644 index 0000000..b882cea --- /dev/null +++ b/_ssl/ca_cert.srl @@ -0,0 +1 @@ +D29D1C6A226490AD diff --git a/_ssl/ca_key.pem b/_ssl/ca_key.pem new file mode 100644 index 0000000..e65d8ce --- /dev/null +++ b/_ssl/ca_key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAy2PngRdvbUTVsDW+Lg3VlALPu4w8m3qLPeBPLYDyjiRHNn5Q +cKJZGvRlN+e8fSeb9igpzrgpCgK4S9rZpJrOX9heBHs2/5fQ568lHXJKgjCNm8AM +/2v0/txy46iOJeZmsBNtSVzYIKgHHIsUVGP4Ct/lezPsznacEXOL+wmtEbAcMH73 +vFrPMaiq8lRb8yTNEF4gI2b8TKS8oHW55owiilQmNNDH4dtCqh2ATCDB2jNEYXUa +74vP9qD30XDAco2XY5/AUPslMEF28z9jAvoqvO5S7sVMRGBmkFOJ8yDB9exmtObe +s4ReNY6g5624yoG4MTxjTcb2rv666Qp6/vjUPwIDAQABAoIBAA3vOEsl2eJ4ltNN +u0vYcsuDLcxBnV1hleyVU5dggD2wypg3KzesR8KK/+xGmilQ72R79/FLuLQQ36OC +yOp4GK+EWVyhPHFia1OUMkzEKcqlnO4QyFMviEd1vwFN6P87u8lQa2pdTAlguawA +81Gcz7+e+0/njM/QXHztl6eJUCwn7zEbG8+we0g8GkLILOBA3Tuy5Vu+ox1LQZQp +WPqIMhm0GXPOVRKBr0mPVWtJvyAYvTX13GqNM1YFbElkbnkbsTaJhg/L3J9UJNsm +BbOg0oUdq1yWoy7cjOXiq3aG9rNws9PBXbbDB/G67aae/1SJ7eBTV/kCEuYh0YDx +MSn5xYECgYEA/uZueW4dFTKMBebNFvJreQei1ecaGwEFckUYD5u02VugtYc9inQ2 +sK7ENq/CsA10WKBxV84lIdiG5yXjG1RwCLvTV6YBP5uL9dVMln25x6ZDUxOlYzuZ +OZUcabR3Y3Ar349vDV+vFle47J0YW8H89O5YlVxvLfZ+CFFFSBSMRCECgYEAzESS +5IvNH1RUCR0tqRkHA0SXMiNxF85lFbUrbS2yMI60LCaTE2q/uK5008f5laD3LYKU +Gq7SVP1U4z0+g9jGa0rvYd1h3o6fJMrFBiBN1ZRRzMFaiQxxNbyjCV7LR86m6aSo +pz4f7k8EmzrsmZw7MF/l9Dy3AWHpg1cwYdR6DF8CgYB17kS0d6aK9Rzlahf/At+I +WmkTD937Gmjbqm3sYry0R3k+IzjswsG+0szDBGRNsZvfmTN3TU/OrfAUJ2pAbbt7 +vvKTvaEcPanubeYGRlrarOi/GfrNw3grtPo1SaJm5jHWN/VIObm225UaG8B2S3Tu +GQvw5pglqsI6tOcZ5y/SIQKBgBVJuD1VTIVNVoy0m8OZth9jEJbLFsgyXFqMzP/N +2VoyJRjM1FsbrutiUw6XMq2jXt9BUooNWiI9XJFqGo/HEbaw0o3ScpatKmy9LRdc +WoA9uuCp7fOGdm3xQNSDKpBLOx3yaRk04kMFvScoVuwTWh/Kfr6bbT8Zoypq9cHc +UPPlAoGBAIEtVPhH6R51/HREPMWXWgwZujkeD0VQX+hNP8VOgSlts9L4bDn7res5 +DXHDXU3Q+vY+86qDvJgJaOdmt7IoNXgRlU9tUZP4MD8YG32Xjn3dnB5e/3SmBJwD +NV4mVx+7X6me5rb4NdpMcSzulVXy3SfnQTaDsNghpcTqOXLFI0ti +-----END RSA PRIVATE KEY----- diff --git a/_ssl/localhost.conf b/_ssl/localhost.conf new file mode 100644 index 0000000..fa3ef54 --- /dev/null +++ b/_ssl/localhost.conf @@ -0,0 +1,66 @@ +# The main section is named req because the command we are using is req +# (openssl req ...) +[ req ] +## This specifies the default key size in bits. If not specified then 512 is +## used. It is used if the -new option is used. It can be overridden by using +## the -newkey option. +#default_bits = 2048 +# +## This is the default filename to write a private key to. If not specified the +## key is written to standard output. This can be overridden by the -keyout +## option. +#default_keyfile = oats.key +# +## If this is set to no then if a private key is generated it is not encrypted. +## This is equivalent to the -nodes command line option. For compatibility +## encrypt_rsa_key is an equivalent option. +#encrypt_key = no + +# This option specifies the digest algorithm to use. Possible values include +# md5 sha1 mdc2. If not present then MD5 is used. This option can be overridden +# on the command line. +default_md = sha1 + +# if set to the value no this disables prompting of certificate fields and just +# takes values from the config file directly. It also changes the expected +# format of the distinguished_name and attributes sections. +prompt = no + +# if set to the value yes then field values to be interpreted as UTF8 strings, +# by default they are interpreted as ASCII. This means that the field values, +# whether prompted from a terminal or obtained from a configuration file, must +# be valid UTF8 strings. +utf8 = yes + +# This specifies the section containing the distinguished name fields to +# prompt for when generating a certificate or certificate request. +distinguished_name = my_req_distinguished_name + +# this specifies the configuration file section containing a list of extensions +# to add to the certificate request. It can be overridden by the -reqexts +# command line switch. See the x509v3_config(5) manual page for details of the +# extension section format. +req_extensions = my_extensions + +[ my_req_distinguished_name ] +C = PT +ST = Lisboa +L = Lisboa +O = Oats In The Water +#CN = *.oats.org +CN = localhost + +[ my_extensions ] +basicConstraints=CA:FALSE +subjectAltName=@my_subject_alt_names +subjectKeyIdentifier = hash + +[ my_subject_alt_names ] +#DNS.1 = *.oats.org +#DNS.2 = *.oats.net +#DNS.3 = *.oats.in +#DNS.4 = oats.org +#DNS.5 = oats.net +#DNS.6 = oats.in +DNS.1 = localhost +DNS.2 = localhost.localdomain diff --git a/_ssl/localhost_cert.pem b/_ssl/localhost_cert.pem new file mode 100644 index 0000000..13a969f --- /dev/null +++ b/_ssl/localhost_cert.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDgDCCAmigAwIBAgIJANKdHGoiZJCtMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMjExMTA4MDc1NDEzWhcNMjExMjA4MDc1NDEzWjBf +MQswCQYDVQQGEwJQVDEPMA0GA1UECAwGTGlzYm9hMQ8wDQYDVQQHDAZMaXNib2Ex +GjAYBgNVBAoMEU9hdHMgSW4gVGhlIFdhdGVyMRIwEAYDVQQDDAlsb2NhbGhvc3Qw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDDJLav5I1Dxx9Lzv7DyHig +ApIkm9U8tcRKuM3Q4q3xj8P2VmSHVHZ0FfjKs/NZ8hLi3go+EzGolmiRKPA7V9UQ +Zgm5MmC6tewiol76lsjehUKuG+DmT3n79xSHsj5PC6wkE/IkifcQIeGVJWgQbRR4 +JSGaX4tmmpxNrDDgpVnaXEO8I5KR/jvniAn2DoTKlY5XSIUXlbZQPHdlLdLUU7in +5M19b9qnIdJRxa4mcOWNtsUHU16SJZAmQBmg4vAhMc4XyJ23YE8cNxUxusKrhoUB +sWmvjGgbbaYgtwBmCFQNSFiJhyzgg6sdUot7wVXDkXBTJPQRQO82CJyw6YoDnTCL +AgMBAAGjWTBXMAkGA1UdEwQCMAAwKwYDVR0RBCQwIoIJbG9jYWxob3N0ghVsb2Nh +bGhvc3QubG9jYWxkb21haW4wHQYDVR0OBBYEFPKfGhTkosDI90l245Si/Ce/CLr/ +MA0GCSqGSIb3DQEBCwUAA4IBAQCMjFo4qbgRHefLMc5yc53qn9OVa693lR9RQb+n +HgVHUuhPRQfNr6WgbfiWjpK5r2RU7Tj7GsueNZlK+tdJxXIvo29yjrdFZ4uUfCMB +Rr9VrjdBhv5/MLuLLnNGuC4LxNaZaZZEPF5DtVh5FZajisgB4jYFOEJNvltWgBca +pR469W8qte2NYprjni1lzMlr0cQBMFt00jt5ZU8u7oeFt7/lzpiStA9W5FIv7DZV +FoEzq51uwGK6FvRhil8x9pr1GzSrZdLfsEELNRZNqLG8rRhcKAUsMER+lS6LtRdJ +ORQ3LnfodE2bCNO8MMx0A5ZA1CGlMOOE5twSlYLgS/hvkK6y +-----END CERTIFICATE----- diff --git a/_ssl/localhost_cert_bundle.pem b/_ssl/localhost_cert_bundle.pem new file mode 100644 index 0000000..a1ed9bc --- /dev/null +++ b/_ssl/localhost_cert_bundle.pem @@ -0,0 +1,42 @@ +-----BEGIN CERTIFICATE----- +MIIDgDCCAmigAwIBAgIJANKdHGoiZJCtMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMjExMTA4MDc1NDEzWhcNMjExMjA4MDc1NDEzWjBf +MQswCQYDVQQGEwJQVDEPMA0GA1UECAwGTGlzYm9hMQ8wDQYDVQQHDAZMaXNib2Ex +GjAYBgNVBAoMEU9hdHMgSW4gVGhlIFdhdGVyMRIwEAYDVQQDDAlsb2NhbGhvc3Qw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDDJLav5I1Dxx9Lzv7DyHig +ApIkm9U8tcRKuM3Q4q3xj8P2VmSHVHZ0FfjKs/NZ8hLi3go+EzGolmiRKPA7V9UQ +Zgm5MmC6tewiol76lsjehUKuG+DmT3n79xSHsj5PC6wkE/IkifcQIeGVJWgQbRR4 +JSGaX4tmmpxNrDDgpVnaXEO8I5KR/jvniAn2DoTKlY5XSIUXlbZQPHdlLdLUU7in +5M19b9qnIdJRxa4mcOWNtsUHU16SJZAmQBmg4vAhMc4XyJ23YE8cNxUxusKrhoUB +sWmvjGgbbaYgtwBmCFQNSFiJhyzgg6sdUot7wVXDkXBTJPQRQO82CJyw6YoDnTCL +AgMBAAGjWTBXMAkGA1UdEwQCMAAwKwYDVR0RBCQwIoIJbG9jYWxob3N0ghVsb2Nh +bGhvc3QubG9jYWxkb21haW4wHQYDVR0OBBYEFPKfGhTkosDI90l245Si/Ce/CLr/ +MA0GCSqGSIb3DQEBCwUAA4IBAQCMjFo4qbgRHefLMc5yc53qn9OVa693lR9RQb+n +HgVHUuhPRQfNr6WgbfiWjpK5r2RU7Tj7GsueNZlK+tdJxXIvo29yjrdFZ4uUfCMB +Rr9VrjdBhv5/MLuLLnNGuC4LxNaZaZZEPF5DtVh5FZajisgB4jYFOEJNvltWgBca +pR469W8qte2NYprjni1lzMlr0cQBMFt00jt5ZU8u7oeFt7/lzpiStA9W5FIv7DZV +FoEzq51uwGK6FvRhil8x9pr1GzSrZdLfsEELNRZNqLG8rRhcKAUsMER+lS6LtRdJ +ORQ3LnfodE2bCNO8MMx0A5ZA1CGlMOOE5twSlYLgS/hvkK6y +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDazCCAlOgAwIBAgIUFREyB8FfpEHUio8HY7b0d7FaKdcwDQYJKoZIhvcNAQEL +BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMTExMDgwNzU0MTNaFw0yMTEy +MDgwNzU0MTNaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw +HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQDLY+eBF29tRNWwNb4uDdWUAs+7jDybeos94E8tgPKO +JEc2flBwolka9GU357x9J5v2KCnOuCkKArhL2tmkms5f2F4Eezb/l9DnryUdckqC +MI2bwAz/a/T+3HLjqI4l5mawE21JXNggqAccixRUY/gK3+V7M+zOdpwRc4v7Ca0R +sBwwfve8Ws8xqKryVFvzJM0QXiAjZvxMpLygdbnmjCKKVCY00Mfh20KqHYBMIMHa +M0RhdRrvi8/2oPfRcMByjZdjn8BQ+yUwQXbzP2MC+iq87lLuxUxEYGaQU4nzIMH1 +7Ga05t6zhF41jqDnrbjKgbgxPGNNxvau/rrpCnr++NQ/AgMBAAGjUzBRMB0GA1Ud +DgQWBBRBtnDR6bDQjBctACDXe2FTsASBEzAfBgNVHSMEGDAWgBRBtnDR6bDQjBct +ACDXe2FTsASBEzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCM +H2UzfYIphO/16z8SO0thdjexjfad0bMIZC39kD92ILHvxk68D0uel4q5Rp3+F66j +J7OupHIzEGSB23suw6n/cDrIJOa5VU9geaUZBVIH8GSy6nQTnkukiX92OTS11ecW +qABoACcptQz4oC3E68K6BYre4/QamJDAqdP4aNVbka040XTiWzvfRlOVeWz+gZTa +zObQiEzj1SwsYgcNSkrquZ/7vcEBaCncxXD8oRxqfEgNA6BRqUqnKCUSUmk/ed3b +hRSpHURjJGntHAzzFzaCC5dfMBEnAszfoOdLua/BV/JZcB7t4YIcIYMKdSYxpvoO +Nr3opPQhzBXur01KZuUA +-----END CERTIFICATE----- diff --git a/_ssl/localhost_csr.pem b/_ssl/localhost_csr.pem new file mode 100644 index 0000000..b28c691 --- /dev/null +++ b/_ssl/localhost_csr.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIDDDCCAfQCAQAwXzELMAkGA1UEBhMCUFQxDzANBgNVBAgMBkxpc2JvYTEPMA0G +A1UEBwwGTGlzYm9hMRowGAYDVQQKDBFPYXRzIEluIFRoZSBXYXRlcjESMBAGA1UE +AwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwyS2 +r+SNQ8cfS87+w8h4oAKSJJvVPLXESrjN0OKt8Y/D9lZkh1R2dBX4yrPzWfIS4t4K +PhMxqJZokSjwO1fVEGYJuTJgurXsIqJe+pbI3oVCrhvg5k95+/cUh7I+TwusJBPy +JIn3ECHhlSVoEG0UeCUhml+LZpqcTaww4KVZ2lxDvCOSkf4754gJ9g6EypWOV0iF +F5W2UDx3ZS3S1FO4p+TNfW/apyHSUcWuJnDljbbFB1NekiWQJkAZoOLwITHOF8id +t2BPHDcVMbrCq4aFAbFpr4xoG22mILcAZghUDUhYiYcs4IOrHVKLe8FVw5FwUyT0 +EUDvNgicsOmKA50wiwIDAQABoGgwZgYJKoZIhvcNAQkOMVkwVzAJBgNVHRMEAjAA +MCsGA1UdEQQkMCKCCWxvY2FsaG9zdIIVbG9jYWxob3N0LmxvY2FsZG9tYWluMB0G +A1UdDgQWBBTynxoU5KLAyPdJduOUovwnvwi6/zANBgkqhkiG9w0BAQUFAAOCAQEA +L4XofNRjzahIDCj/pHVnsaXtioidv5Hp0vE+9LPhzZz/bH/e7s8lJnTalEkPNUxD +FPwiRar6MILQwn5N1b+kToSoiYDsCL77Y5WSlhcwe7gLwgDTlNwu2H030BZEr0ve +AEAems45TJk8o3kC5s3dt0KaGbRikub1HMTpFrlQUBLbO848t6qXcZCVjoAWYKlp +jaYn7r3bWVyZ2W2oIlQ19Tbxz+kG81Vxrg1FtAo7aBHTaOvEskgnEQ2Emc0mbLoe +YoT0Gg7Vrurl+T5gazmV1WMKszSjP8NKhTUcMESiRIUsmQczWiDBONiH9PGmGKHI +7aEBzQIK7m3goyS3I4q6nw== +-----END CERTIFICATE REQUEST----- diff --git a/_ssl/localhost_ext.conf b/_ssl/localhost_ext.conf new file mode 100644 index 0000000..d5005dc --- /dev/null +++ b/_ssl/localhost_ext.conf @@ -0,0 +1,13 @@ +basicConstraints=CA:FALSE +subjectAltName=@my_subject_alt_names +subjectKeyIdentifier = hash + +[ my_subject_alt_names ] +#DNS.1 = *.oats.org +#DNS.2 = *.oats.net +#DNS.3 = *.oats.in +#DNS.4 = oats.org +#DNS.5 = oats.net +#DNS.6 = oats.in +DNS.1 = localhost +DNS.2 = localhost.localdomain diff --git a/_ssl/localhost_key.pem b/_ssl/localhost_key.pem new file mode 100644 index 0000000..6c94353 --- /dev/null +++ b/_ssl/localhost_key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAwyS2r+SNQ8cfS87+w8h4oAKSJJvVPLXESrjN0OKt8Y/D9lZk +h1R2dBX4yrPzWfIS4t4KPhMxqJZokSjwO1fVEGYJuTJgurXsIqJe+pbI3oVCrhvg +5k95+/cUh7I+TwusJBPyJIn3ECHhlSVoEG0UeCUhml+LZpqcTaww4KVZ2lxDvCOS +kf4754gJ9g6EypWOV0iFF5W2UDx3ZS3S1FO4p+TNfW/apyHSUcWuJnDljbbFB1Ne +kiWQJkAZoOLwITHOF8idt2BPHDcVMbrCq4aFAbFpr4xoG22mILcAZghUDUhYiYcs +4IOrHVKLe8FVw5FwUyT0EUDvNgicsOmKA50wiwIDAQABAoIBAEuOiImcJbIrhAuX +Lv9hPIs/05QHHk4uVr1TxqTtT8orDwXvN2dKpb6Wz0i02jFmUDe1HyQfzGdpLT2f +Kzze6ik6SOODBP7l93MFiV7fSREXadT+CFtERIfxh+pucj+q1lD1xBivrpB5fd2A +qUVK5tUKE3OxMMlebcyJMjeY7ixkRVgjROFeXs0t50xitzn/wPN0dVPZ6JFCPgRD +fc72E1K+DmfrzFZ2+rzqoVzAE7OSYQns3r2jNXlCEVw2jXsmnIRIi9wejbRthjbx +gA1IdenZcf4FkOMTTFuWGynT5tfF3cVzy5QtYemGZWSK4LNuWaTSzZCk3/sCxWk5 +Vbz/AdkCgYEA8gc2WEfbk5kVhU7UV5SRDRFtGuS8fmZ0RnqFdx6qy2EWYnwYXgzT +cZc6TiEuJ5getmEVsqzxFm3gWMyD0bEhY0jqoMVKMM70QQOQOZOB4lykXmpRDKny +/DU7/0bp7sBzFCKCWISCjGKWc98KWy24ZdKl8ZAr3zjDxE5UYvquKIcCgYEAzmie +r+1Y7DUtniogqpDLr6NnuvH52d1s4DEsHZQ6KRWE82d/X+2YU2R7/0QwfLBvcbT7 +OxlQP5rRoL6pX+ViZBmky0CSc/HYZZ+8uGwFc1X46zGfuvTSWaAStdIFPOX2O0JF +LLyF5/0/CK56agL3YxGREx2iQdauqTsOyr2LLN0CgYEAzYEgPN9u6ymd415m4KKO +c1krmh1Ei9M0wa9A6j9I6H3cgu05x4n+c8HjyPlVdlstINDYmqlL4C6VwvCMsR1E +60e7qZ07fKwNK7L54FmGfI0LJ/wAK8+WOV5+PiiZc5dHX35ZzQ1eyBLiCysEYR02 +KIcvTiiLh/NsDqAv+Qc/n7sCgYAup0z+3LnVoeturXz2sIWpbFi804ayrK64OcUL +5n4C3T9QuNr8drqQVs0EFIiVFlgKLmr+n6kYx0iMeavU5gcIMxehbTXtCQPtbF5+ +nMPantsFZhEBc+a7pUe1WwQeEKhIGqGCDBaEKiR+NNmsboE2HjlZRcBv+zM9QwED +6DW17QKBgQCRZfGUWasWXW6s9aZ1FgLPAXz/M9BLZjnx627KvbF4C+ZwfszntJxn +1A74mhHWJyKbt8YzfOTsTj40lp/npSpgjRQmUoqThx8d2cA41ALo0ktk6E9Zpp1j +phi0woa+TdEpqE2Jb8hJcyRKGCOVOKL/bnZL/QVgMebhg02n//wa9w== +-----END RSA PRIVATE KEY----- diff --git a/_ssl/n.sh b/_ssl/n.sh new file mode 100755 index 0000000..9fbf379 --- /dev/null +++ b/_ssl/n.sh @@ -0,0 +1,30 @@ +#!/bin/sh + +# see https://gist.github.com/Soarez/9688998 + +# note that the CSR contains X509 extensions, particularly the SAN which +# is mandatory for getting Google Chrome to accept the certificate, but +# unfortunately "openssl x509" will strip extensions -- this can be fixed +# by using the "openssl ca" command with "extensions = copyall" (or in +# the normal case filters would be specified on what extensions to copy), +# but the "openssl ca" command is very complicated and requires a directory +# structure to be set up, so we fake it with the "localhost_ext.conf" file + +# generate a key for the subject +#openssl genrsa -out localhost_key.pem 2048 + +# generate a CSR +openssl req -new -key localhost_key.pem -out localhost_csr.pem -config localhost.conf + +# generate a key for the CA +#openssl genrsa -out ca_key.pem 2048 + +# generate a self signed certificate for the CA +openssl req -new -x509 -key ca_key.pem -out ca_cert.pem + +# sign the certificate +#openssl x509 -req -in localhost_csr.pem -extfile localhost_ext.conf -CA ca_cert.pem -CAkey ca_key.pem -CAcreateserial -out localhost_cert.pem +openssl x509 -req -in localhost_csr.pem -extfile localhost_ext.conf -CA ca_cert.pem -CAkey ca_key.pem -CAserial ca_cert.srl -out localhost_cert.pem + +# resolve problems with not including the signing chain (can improve this?) +cat localhost_cert.pem ca_cert.pem > localhost_cert_bundle.pem diff --git a/api/captureOrder.json.jst b/api/captureOrder.json.jst new file mode 100644 index 0000000..3186882 --- /dev/null +++ b/api/captureOrder.json.jst @@ -0,0 +1,15 @@ +let basic_functions = require('../_library/basic_functions.js') +let cookie = require('cookie') + +return async env => { + let cookies = cookie.parse(env.request.headers.cookie || '') + let response = await basic_functions.capture_order(cookies.order_id) + console.log('capture_order()', response) + + env.site.serve( + env, + 200, + Buffer.from(JSON.stringify(response)), + 'getOrderDetails.json.jst' + ) +} diff --git a/api/createOrder.json.jst b/api/createOrder.json.jst new file mode 100644 index 0000000..4cdb0fb --- /dev/null +++ b/api/createOrder.json.jst @@ -0,0 +1,117 @@ +let basic_functions = require('../_library/basic_functions.js') +let querystring = require('querystring') +let random_number = require('../_library/random_number.js') +let stream_buffers = require('stream-buffers') +let XDate = require('xdate') + +return async env => { + let response = null; + if (env.request.method === 'POST') { + let write_stream = new stream_buffers.WritableStreamBuffer() + let data = new Promise( + (resolve, reject) => { + write_stream. + on('finish', () => {resolve(write_stream.getContents())}). + on('error', () => {reject()}) + } + ) + env.request.pipe(write_stream) + let query = querystring.parse((await data).toString()) + console.log('received createOrder form:', JSON.stringify(query)) + + //Build the PayPal object to create order and populate with POST params from website + let item_obj = { + "intent" : "CAPTURE", + "application_context" : { + "return_url" : query.return_url, + "cancel_url" : query.cancel_url + }, + "purchase_units" : [ + { + "reference_id" : "PU1", + "description" : "Camera Shop", + "invoice_id" : "INV-CameraShop-" + random_number(), + "custom_id" : "CUST-CameraShop", + "amount" : { + "currency_code" : query.currency, + "value" : query.total_amt, + "breakdown" : { + "item_total" : { + "currency_code" : query.currency, + "value" : query.item_amt + }, + "shipping" : { + "currency_code" : query.currency, + "value" : query.shipping_amt + }, + "tax_total" : { + "currency_code" : query.currency, + "value" : query.tax_amt + }, + "handling" : { + "currency_code" : query.currency, + "value" : query.handling_fee + }, + "shipping_discount" : { + "currency_code" : query.currency, + "value" : query.shipping_discount + }, + "insurance" : { + "currency_code" : query.currency, + "value" : query.insurance_fee + } + } + }, + "items" : [{ + "name" : "DSLR Camera", + "description" : "Black Camera - Digital SLR", + "sku" : "sku01", + "unit_amount" : { + "currency_code" : query.currency, + "value" : query.item_amt + }, + "quantity" : "1", + "category" : "PHYSICAL_GOODS" + }] + } + ] + }; + //If order details contain shipping, append shipping and preferences + if (query.line1 !== undefined) { + item_obj.application_context.shipping_preference = "SET_PROVIDED_ADDRESS"; + item_obj.application_context.user_action = "PAY_NOW"; + item_obj.purchase_units[0].shipping = { + "address" : { + "address_line_1": query.line1, + "address_line_2": query.line2, + "admin_area_2": query.city, + "admin_area_1": query.state, + "postal_code": query.zip, + "country_code": query.countrySelect + } + }; + } + console.log('item_obj', item_obj) + response = await basic_functions.create_order(item_obj) + console.log('create_order()', response) + + //sess.order_id = response.id; + let expires = new XDate() + expires.addDays(1) + env.response.setHeader( + 'Set-Cookie', + 'order_id=' + + response.id + + '; expires=' + + expires + + '; path=/;' + ) + } + + env.site.serve( + env, + 200, + Buffer.from(JSON.stringify(response)), + 'createOrder.json.jst' + ) +} diff --git a/api/getOrderDetails.json.jst b/api/getOrderDetails.json.jst new file mode 100644 index 0000000..b8cfaa9 --- /dev/null +++ b/api/getOrderDetails.json.jst @@ -0,0 +1,15 @@ +let basic_functions = require('../_library/basic_functions.js') +let cookie = require('cookie') + +return async env => { + let cookies = cookie.parse(env.request.headers.cookie || '') + let response = await basic_functions.get_order_details(cookies.order_id) + console.log('get_order_details()', response) + + env.site.serve( + env, + 200, + Buffer.from(JSON.stringify(response)), + 'getOrderDetails.json.jst' + ) +} diff --git a/api/patchOrder.json.jst b/api/patchOrder.json.jst new file mode 100644 index 0000000..0094534 --- /dev/null +++ b/api/patchOrder.json.jst @@ -0,0 +1,73 @@ +let basic_functions = require('../_library/basic_functions.js') +let cookie = require('cookie') +let querystring = require('querystring') +let random_number = require('../_library/random_number.js') +let stream_buffers = require('stream-buffers') +let XDate = require('xdate') + +return async env => { + let response = null; + if (env.request.method === 'POST') { + let write_stream = new stream_buffers.WritableStreamBuffer() + let data = new Promise( + (resolve, reject) => { + write_stream. + on('finish', () => {resolve(write_stream.getContents())}). + on('error', () => {reject()}) + } + ) + env.request.pipe(write_stream) + let query = querystring.parse((await data).toString()) + console.log('received patchOrder form:', JSON.stringify(query)) + + let cookies = cookie.parse(env.request.headers.cookie || '') + let new_order_details = { + "patch_details": [{ + "op" : "replace", + "path" : "/purchase_units/@reference_id==\'PU1\'/amount", + "value" : { + "currency_code" : query.currency, + "value" : parseInt(query.total_amt) + parseInt(query.updated_shipping) - parseInt(query.current_shipping), + "breakdown" : { + "item_total" : { + "currency_code" : query.currency, + "value" : query.item_amt, + }, + "shipping" : { + "currency_code" : query.currency, + "value" : query.updated_shipping + }, + "tax_total" : { + "currency_code" : query.currency, + "value" : query.tax_amt + }, + "shipping_discount" : { + "currency_code" : query.currency, + "value" : query.shipping_discount + }, + "handling" : { + "currency_code" : query.currency, + "value" : query.handling_fee + }, + "insurance" : { + "currency_code" : query.currency, + "value" : query.insurance_fee + } + } + } + }], + "order_id": cookies.order_id + }; + response = { + http_code: await basic_functions.patch_order_details(new_order_details) + } + console.log('patch_order_details()', response) + } + + env.site.serve( + env, + 200, + Buffer.from(JSON.stringify(response)), + 'patchOrder.json.jst' + ) +} diff --git a/img/camera.jpg b/img/camera.jpg new file mode 100644 index 0000000..acfbbf1 Binary files /dev/null and b/img/camera.jpg differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..d8e5cce --- /dev/null +++ b/index.html @@ -0,0 +1,263 @@ + + + + + + + + + + Checkout With PayPal NodeJs Demo + + + + +
+
+

Checkout with PayPal Demo

+

Using Orders v2 REST API with PayPal JavaScript SDK

+
Server-side Integration
+
+
+
+
+

Sample Sandbox Buyer Credentials

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Buyer EmailPassword
emily_doe@buyer.comqwer1234
bill_bong@buyer.comqwer1234
jack_potter@buyer.com123456789
harry_doe@buyer.com123456789
ron_brown@buyer.comqwer1234
bella_brown@buyer.comqwer1234
+
+
+
+
+

Pricing Details

+
+
+ + + +
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+ +
+ + +
+
+
+
+
+
+

Readme

+
    +
  1. Enter REST API credentials in common/config/config.json. You can get your own REST app credentials by creating a REST app with the steps outlined + here + .
  2. +
  3. Click on 'PayPal Checkout’ button and see the experience.
  4. +
  5. Checkout with PayPal using a buyer sandbox account provided on this page. And you're done!
  6. +
  7. In the guest checkout experience, the buyer country can be switched. When switched to one of Germany, Poland, Austria, Netherlands, Italy and Spain, you will be able to choose the alternative payment methods offered in those countries.
  8. +
  9. For example: Selecting 'Germany' in the country drop down will pre-fill the shipping address on the Shipping Information page. For all other countries not mentioned in step 5, the address has to be manually entered.
  10. +
+
+

In-Context Checkout integration steps with PayPal JavaScript SDK

+
    +
  1. Copy the files and folders in the package to the same location where you have your shopping cart page.
  2. +
  3. In order to view Alternative Payment Methods as part of the guest checkout flow, you must add query parameters intent=capture, commit=true, vault=false and buyer-country= and you must provide a supported buyer country
  4. +
  5. Include the following script on your shopping cart page: (For APMs, the layout must be vertical and setting up the payment in the alternative payment method supported currency is required for the alternative payment method to render.)
    
    +        paypal.Buttons({
    +        env: 'sandbox', // sandbox | production
    +    
    +            // Set style of buttons
    +            style: {
    +                layout: 'vertical',   // horizontal | vertical <-Must be vertical for APMs
    +                size:   'responsive',   // medium | large | responsive
    +                shape:  'pill',         // pill | rect
    +                color:  'gold',         // gold | blue | silver | black,
    +                fundingicons: false,    // true | false,
    +                tagline: false          // true | false,
    +            },
    +    
    +        // payment() is called when the button is clicked
    +        createOrder: function() {
    +    
    +            return fetch('/my-server/create-paypal-transaction')
    +                .then(function(res) {
    +                    return res.json();
    +                }).then(function(data) {
    +                    return data.orderID;
    +                });
    +        },
    +    
    +        // onAuthorize() is called when the buyer approves the payment
    +        onApprove: function(data, actions) {
    +    
    +            return fetch('/my-server/capture-paypal-transaction', {
    +                    body: JSON.stringify({
    +                    orderID: data.orderID
    +                    })
    +                }).then(function(res) {
    +                    return res.json();
    +                }).then(function(details) {
    +                    alert('Transaction funds captured from ' + details.payer_given_name);
    +                });
    +        }
    +    }).render('#paypal-button-container');
    +                
  6. +
  7. Open your browser and navigate to your Shopping cart page. Click on 'Checkout with PayPal' button and complete the flow.
  8. +
  9. You can use the sample Buyer Sandbox credentials provided on index/home page.
  10. +
  11. Refer to PayPal Developer site for detailed guidelines.
  12. +
  13. Click here for the API reference.
  14. +
+
+
+
+ + + + + + + + + diff --git a/js/config.js b/js/config.js new file mode 100644 index 0000000..a5e380b --- /dev/null +++ b/js/config.js @@ -0,0 +1,258 @@ +//Helper Functions +function showDom(id) { + let arr; + if (!Array.isArray(id)) { + arr = [id]; + } else { + arr = id; + } + arr.forEach(function (domId) { + document.getElementById(domId).style.display = "block"; + }); +} + +function hideDom(id) { + let arr; + if (!Array.isArray(id)) { + arr = [id]; + } else { + arr = id; + } + arr.forEach(function (domId) { + document.getElementById(domId).style.display = "none"; + }); +} + +function getUrlParams(prop) { + let params = {}, + search = decodeURIComponent(window.location.href.slice(window.location.href.indexOf("?") + 1)), + definitions = search.split("&"); + + definitions.forEach(function (val) { + let parts = val.split("=", 2); + params[parts[0]] = parts[1]; + }); + + return (prop && prop in params) ? params[prop] : params; +} + +document.addEventListener("input", function (event) { + if ((event.target.id === "countrySelect") && event.target.id !== null) { + window.location.href = + window.location.pathname + + "?buyer-country=" + + event.target.options[event.target.selectedIndex].value; + } +}); + +ready = function (fn) { + if (document.readyState != "loading") { + fn(); + } else { + document.addEventListener("DOMContentLoaded", fn); + } +} + +select_country_dropdown = function () { + const queryString = window.location.search; + const urlParams = new URLSearchParams(queryString); + const buyer_country = urlParams.get("buyer-country") + //If this param exists in URL + if (buyer_country) { + //Build script tag for head based on buyer country + let head = document.getElementsByTagName("head")[0]; + let paypal_sdk_script = document.createElement("script"); + paypal_sdk_script.type = "text/javascript"; + paypal_sdk_script.setAttribute("async", ""); + paypal_sdk_script.src = "https://www.paypal.com/sdk/js?intent=capture&vault=false&client-id=Aa2IfcoEvHnfJRnVQLSFrSs3SmTTkv5N1weMEL66ysqYIeHfAqXpDVkjOv3vLhkhbP4eKB6MpRlQIcJw&buyer-country=" + buyer_country; + paypal_sdk_script.onload = init_smart_buttons; + head.appendChild(paypal_sdk_script); + //Pre-populate fields + for (let i = 0; i < document.getElementById("countrySelect").options.length; i++) { + if (document.getElementById("countrySelect").options[i].value == buyer_country) { + document.getElementById("countrySelect").options[i].selected = true; + } + } + apm_country_list = [ + { + country: "DE", address: { + address_line_1: "Bayreuther Straße 42", + address_line_2: "", + city: "Gmindersdorf", + state: "Reutlingen", + postal_code: "72760", + }, recipient_name: "Jane Doe" + }, + { + country: "US", address: { + address_line_1: "2211 North Street", + address_line_2: "", + city: "San Jose", + state: "CA", + postal_code: "95123" + }, recipient_name: "Jane Doe" + }, + { + country: "BE", address: { + address_line_1: "Putstraat 478", + address_line_2: "", + city: "Sint-Pauwels", + state: "", + postal_code: "9170" + }, recipient_name: "Marina Beich" + }, + { + country: "PL", address: { + address_line_1: "ul. Królewska 78", + address_line_2: "", + city: "Kraków", + state: "", + postal_code: "30-081" + }, recipient_name: "August Pedersen" + }, + { + country: "AT", address: { + address_line_1: "Hauptstrasse 85", + address_line_2: "", + city: "PULGARN", + state: "", + postal_code: "4221" + }, recipient_name: "Berrie Hulstein" + }, + { + country: "NL", address: { + address_line_1: "Asterstraat 135", + address_line_2: "", + city: "Almelo", + state: "", + postal_code: "7601 AK" + }, recipient_name: "Joos Voorham" + }, + { + country: "IT", address: { + address_line_1: "Via Longhena, 132", + address_line_2: "", + city: "Galloro RM", + state: "", + postal_code: "00040" + }, recipient_name: "Colette Jalbert" + }, + { + country: "ES", address: { + address_line_1: "Calle Alcalá 22", + address_line_2: "", + city: "Madrid", + state: "", + postal_code: "28055" + }, recipient_name: "Ana García López" + }, + { + country: "AU", address: { + address_line_1: "15 Mary Street", + address_line_2: "", + city: "North Sydney", + state: "NSW", + postal_code: "2001" + }, recipient_name: "Jane Doe" + }, + { + country: "MX", address: { + address_line_1: "Av. Caudillo del Sur 1234, Edificio B-5", + address_line_2: "11560, Col. Municipio Libre, D.F.", + city: "Mexico City", + state: "Morelos", + postal_code: "11560" + }, recipient_name: "Raúl Uriarte, Jr." + }, + { + country: "BR", address: { + address_line_1: "Rua da Matriz 123", + address_line_2: "apto 25 Centro", + city: "Rio de Janeiro", + state: "Paraná", + postal_code: "01000-001" + }, recipient_name: "João da Silva" + }, + { + country: "JP", address: { + address_line_1: "123-4567 東京都港区", + address_line_2: "青山 1-1-1 ペイパルビル 1037", + city: "港区", + state: "東京都", + postal_code: "104-0051" + }, recipient_name: "山田 花子" + }, + { + country: "GB", address: { + address_line_1: "1 Main Terrace", + address_line_2: "", + city: "Wolverhampton", + state: "West Midlands", + postal_code: "W12 4LQ" + }, recipient_name: "Jane Doe" + } + ]; + apm_country_check = false; + apm_country_list.forEach(function (country_object) { + if (country_object.country === buyer_country) { + apm_country_check = true; + document.getElementById("recipient_name").value = country_object.recipient_name; + document.getElementById("line1").value = country_object.address.address_line_1; + document.getElementById("line2").value = country_object.address.address_line_2; + document.getElementById("city").value = country_object.address.city; + document.getElementById("state").value = country_object.address.state; + document.getElementById("zip").value = country_object.address.postal_code; + } + }); + if (apm_country_check === false && buyer_country !== null) { + document.getElementById("recipient_name").value = "Jane Doe"; + document.getElementById("line1").value = + document.getElementById("line2").value = + document.getElementById("city").value = + document.getElementById("state").value = + document.getElementById("zip").value = ""; + } + } else { + //Build script tag with no particular buyer country + let head = document.getElementsByTagName("head")[0]; + let paypal_sdk_script = document.createElement("script"); + paypal_sdk_script.type = "text/javascript"; + paypal_sdk_script.setAttribute("async", ""); + paypal_sdk_script.src = "https://www.paypal.com/sdk/js?intent=capture&vault=false&client-id=Aa2IfcoEvHnfJRnVQLSFrSs3SmTTkv5N1weMEL66ysqYIeHfAqXpDVkjOv3vLhkhbP4eKB6MpRlQIcJw"; + paypal_sdk_script.onload = init_smart_buttons; + head.appendChild(paypal_sdk_script); + } +} + +ready(select_country_dropdown); + +let serialize = function (form) { + + // Setup our serialized data + let serialized = []; + + // Loop through each field in the form + for (let i = 0; i < form.elements.length; i++) { + + let field = form.elements[i]; + + // Don't serialize fields without a name, submits, buttons, file and reset inputs, and disabled fields + if (!field.name || field.disabled || field.type === "file" || field.type === "reset" || field.type === "submit" || field.type === "button") continue; + + // If a multi-select, get all selections + if (field.type === "select-multiple") { + for (let n = 0; n < field.options.length; n++) { + if (!field.options[n].selected) continue; + serialized.push(encodeURIComponent(field.name) + "=" + encodeURIComponent(field.options[n].value)); + } + } + + // Convert field data to a query string + else if ((field.type !== "checkbox" && field.type !== "radio") || field.checked) { + serialized.push(encodeURIComponent(field.name) + "=" + encodeURIComponent(field.value)); + } + } + + return serialized.join("&"); + +}; \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..9a95157 --- /dev/null +++ b/package.json @@ -0,0 +1,16 @@ +{ + "name": "@ndcode/paypal_example_site", + "version": "0.0.1", + "description": "Example website using JavaScript Template system", + "directories": {}, + "dependencies": { + "cookie": "^0.3.1", + "querystring": "^0.2.0", + "stream-buffers": "^3.0.2", + "xdate": "^0.8.2" + }, + "devDependencies": {}, + "scripts": {}, + "author": "Nick Downing", + "license": "CC-BY-SA-3.0" +} diff --git a/pages/shipping.html b/pages/shipping.html new file mode 100644 index 0000000..f47efb1 --- /dev/null +++ b/pages/shipping.html @@ -0,0 +1,435 @@ + + + + + + + + + + Checkout With PayPal NodeJs Demo + + + + +
+
+

Checkout with PayPal Demo

+

Using Orders v2 REST API with PayPal JavaScript SDK

+
Server-side Integration
+
+
+
+

Shipping Information

+
+
+ + + + + + + + + + +
+ +
+ +
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+ +
+
+ +
+ +
+
+
+
+ +
+
+
+
+
+
+
+ + + + + + + + + diff --git a/pages/success.html b/pages/success.html new file mode 100644 index 0000000..437d54b --- /dev/null +++ b/pages/success.html @@ -0,0 +1,255 @@ + + + + + + + + + + Checkout With PayPal NodeJs Demo + + + + +
+
+

Checkout with PayPal Demo

+

Using Orders v2 REST API with PayPal JavaScript SDK

+
Server-side Integration
+
+
+
+ + + +
+
+
+
+ + + + + + + +