mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-04 08:47:23 +08:00
move module.local to module
This commit is contained in:
parent
c443e4053c
commit
f8e82bdfaf
217 changed files with 8 additions and 2 deletions
5
modules/ppcp-button/.babelrc
Normal file
5
modules/ppcp-button/.babelrc
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"plugins": [
|
||||
"babel-plugin-transform-object-rest-spread"
|
||||
]
|
||||
}
|
1
modules/ppcp-button/.gitignore
vendored
Normal file
1
modules/ppcp-button/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/node_modules/
|
1
modules/ppcp-button/assets/css/hosted-fields.css
Normal file
1
modules/ppcp-button/assets/css/hosted-fields.css
Normal file
|
@ -0,0 +1 @@
|
|||
.ppcp-card-icon{max-width:50px;margin-left:5px}#ppcp-hosted-fields .ppcp-dcc-credit-card-wrapper{width:100%;display:grid;grid-template-columns:55% 1fr 1fr;grid-template-rows:1fr 1fr auto;grid-column-gap:15px;margin-bottom:15px}#ppcp-hosted-fields .ppcp-dcc-credit-card-wrapper label,#ppcp-hosted-fields .ppcp-dcc-credit-card-wrapper span{height:30px;padding:0;margin:0;overflow:hidden;position:relative;vertical-align:bottom;font-size:10px}#ppcp-hosted-fields .ppcp-dcc-credit-card-wrapper label{grid-row:1/2}#ppcp-hosted-fields .ppcp-dcc-credit-card-wrapper span{grid-row:2/3;background:white;border:1px #666;padding:5px}#ppcp-hosted-fields .ppcp-dcc-credit-card-wrapper button{grid-row:3/4;grid-column:1/4}#ppcp-hosted-fields .ppcp-dcc-credit-card-wrapper label{line-height:30px}
|
2
modules/ppcp-button/assets/js/button.js
Normal file
2
modules/ppcp-button/assets/js/button.js
Normal file
File diff suppressed because one or more lines are too long
1
modules/ppcp-button/assets/js/button.js.map
Normal file
1
modules/ppcp-button/assets/js/button.js.map
Normal file
File diff suppressed because one or more lines are too long
2
modules/ppcp-button/assets/js/hostedfields.js
Normal file
2
modules/ppcp-button/assets/js/hostedfields.js
Normal file
|
@ -0,0 +1,2 @@
|
|||
!function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=0)}([function(e,t,r){e.exports=r.p+"css/hosted-fields.css"}]);
|
||||
//# sourceMappingURL=hostedfields.js.map
|
1
modules/ppcp-button/assets/js/hostedfields.js.map
Normal file
1
modules/ppcp-button/assets/js/hostedfields.js.map
Normal file
|
@ -0,0 +1 @@
|
|||
{"version":3,"sources":["webpack:///webpack/bootstrap","webpack:///./resources/css/hosted-fields.scss"],"names":["installedModules","__webpack_require__","moduleId","exports","module","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s"],"mappings":"aACE,IAAIA,EAAmB,GAGvB,SAASC,EAAoBC,GAG5B,GAAGF,EAAiBE,GACnB,OAAOF,EAAiBE,GAAUC,QAGnC,IAAIC,EAASJ,EAAiBE,GAAY,CACzCG,EAAGH,EACHI,GAAG,EACHH,QAAS,IAUV,OANAI,EAAQL,GAAUM,KAAKJ,EAAOD,QAASC,EAAQA,EAAOD,QAASF,GAG/DG,EAAOE,GAAI,EAGJF,EAAOD,QAKfF,EAAoBQ,EAAIF,EAGxBN,EAAoBS,EAAIV,EAGxBC,EAAoBU,EAAI,SAASR,EAASS,EAAMC,GAC3CZ,EAAoBa,EAAEX,EAASS,IAClCG,OAAOC,eAAeb,EAASS,EAAM,CAAEK,YAAY,EAAMC,IAAKL,KAKhEZ,EAAoBkB,EAAI,SAAShB,GACX,oBAAXiB,QAA0BA,OAAOC,aAC1CN,OAAOC,eAAeb,EAASiB,OAAOC,YAAa,CAAEC,MAAO,WAE7DP,OAAOC,eAAeb,EAAS,aAAc,CAAEmB,OAAO,KAQvDrB,EAAoBsB,EAAI,SAASD,EAAOE,GAEvC,GADU,EAAPA,IAAUF,EAAQrB,EAAoBqB,IAC/B,EAAPE,EAAU,OAAOF,EACpB,GAAW,EAAPE,GAA8B,iBAAVF,GAAsBA,GAASA,EAAMG,WAAY,OAAOH,EAChF,IAAII,EAAKX,OAAOY,OAAO,MAGvB,GAFA1B,EAAoBkB,EAAEO,GACtBX,OAAOC,eAAeU,EAAI,UAAW,CAAET,YAAY,EAAMK,MAAOA,IACtD,EAAPE,GAA4B,iBAATF,EAAmB,IAAI,IAAIM,KAAON,EAAOrB,EAAoBU,EAAEe,EAAIE,EAAK,SAASA,GAAO,OAAON,EAAMM,IAAQC,KAAK,KAAMD,IAC9I,OAAOF,GAIRzB,EAAoB6B,EAAI,SAAS1B,GAChC,IAAIS,EAAST,GAAUA,EAAOqB,WAC7B,WAAwB,OAAOrB,EAAgB,SAC/C,WAA8B,OAAOA,GAEtC,OADAH,EAAoBU,EAAEE,EAAQ,IAAKA,GAC5BA,GAIRZ,EAAoBa,EAAI,SAASiB,EAAQC,GAAY,OAAOjB,OAAOkB,UAAUC,eAAe1B,KAAKuB,EAAQC,IAGzG/B,EAAoBkC,EAAI,GAIjBlC,EAAoBA,EAAoBmC,EAAI,G,kBClFrDhC,EAAOD,QAAU,IAA0B","file":"js/hostedfields.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n","module.exports = __webpack_public_path__ + \"css/hosted-fields.css\";"],"sourceRoot":""}
|
8
modules/ppcp-button/composer.json
Normal file
8
modules/ppcp-button/composer.json
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"name": "inpsyde/ppcp-button",
|
||||
"type": "inpsyde-module",
|
||||
"require": {
|
||||
"dhii/module-interface": "0.2.x-dev",
|
||||
"inpsyde/ppcp-api-client": "dev-master"
|
||||
}
|
||||
}
|
10
modules/ppcp-button/extensions.php
Normal file
10
modules/ppcp-button/extensions.php
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
/**
|
||||
* The button module extensions.
|
||||
*
|
||||
* @package Inpsyde\PayPalCommerce\Button
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
return array();
|
16
modules/ppcp-button/module.php
Normal file
16
modules/ppcp-button/module.php
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
/**
|
||||
* The button module.
|
||||
*
|
||||
* @package Inpsyde\PayPalCommerce\Button
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Inpsyde\PayPalCommerce\Button;
|
||||
|
||||
use Dhii\Modular\Module\ModuleInterface;
|
||||
|
||||
return static function (): ModuleInterface {
|
||||
return new ButtonModule();
|
||||
};
|
23
modules/ppcp-button/package.json
Normal file
23
modules/ppcp-button/package.json
Normal file
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"name": "ppc-button",
|
||||
"version": "1.0.0",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"main": "resources/js/button.js",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.9.0",
|
||||
"@babel/preset-env": "^7.9.5",
|
||||
"babel-loader": "^8.1.0",
|
||||
"cross-env": "^5.0.1",
|
||||
"file-loader": "^4.2.0",
|
||||
"node-sass": "^4.13.0",
|
||||
"sass-loader": "^8.0.0",
|
||||
"webpack": "^4.42.1",
|
||||
"webpack-cli": "^3.1.2",
|
||||
"babel-plugin-transform-object-rest-spread": "^6.26.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "cross-env BABEL_ENV=default NODE_ENV=production webpack",
|
||||
"watch": "cross-env BABEL_ENV=default NODE_ENV=production webpack --watch",
|
||||
"dev": "cross-env BABEL_ENV=default webpack --watch"
|
||||
}
|
||||
}
|
50
modules/ppcp-button/resources/css/hosted-fields.scss
Normal file
50
modules/ppcp-button/resources/css/hosted-fields.scss
Normal file
|
@ -0,0 +1,50 @@
|
|||
.ppcp-card-icon {
|
||||
max-width: 50px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
#ppcp-hosted-fields {
|
||||
|
||||
.ppcp-dcc-credit-card-wrapper {
|
||||
width: 100%;
|
||||
display: grid;
|
||||
grid-template-columns: 55% 1fr 1fr;
|
||||
grid-template-rows: 1fr 1fr auto;
|
||||
grid-column-gap: 15px;
|
||||
margin-bottom: 15px;
|
||||
|
||||
label, span {
|
||||
height: 30px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
vertical-align: bottom;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
label {
|
||||
grid-row: 1/2;
|
||||
}
|
||||
span {
|
||||
grid-row: 2/3;
|
||||
background:white;
|
||||
border: 1px #666;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
button {
|
||||
grid-row: 3/4;
|
||||
grid-column: 1/4;
|
||||
}
|
||||
|
||||
label {
|
||||
line-height: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
85
modules/ppcp-button/resources/js/button.js
Normal file
85
modules/ppcp-button/resources/js/button.js
Normal file
|
@ -0,0 +1,85 @@
|
|||
import MiniCartBootstap from './modules/ContextBootstrap/MiniCartBootstap';
|
||||
import SingleProductBootstap from './modules/ContextBootstrap/SingleProductBootstap';
|
||||
import CartBootstrap from './modules/ContextBootstrap/CartBootstap';
|
||||
import CheckoutBootstap from './modules/ContextBootstrap/CheckoutBootstap';
|
||||
import Renderer from './modules/Renderer/Renderer';
|
||||
import ErrorHandler from './modules/ErrorHandler';
|
||||
import CreditCardRenderer from "./modules/Renderer/CreditCardRenderer";
|
||||
import dataClientIdAttributeHandler from "./modules/DataClientIdAttributeHandler";
|
||||
import MessageRenderer from "./modules/Renderer/MessageRenderer";
|
||||
|
||||
const bootstrap = () => {
|
||||
const errorHandler = new ErrorHandler(PayPalCommerceGateway.labels.error.generic);
|
||||
const creditCardRenderer = new CreditCardRenderer(PayPalCommerceGateway, errorHandler);
|
||||
const renderer = new Renderer(creditCardRenderer, PayPalCommerceGateway);
|
||||
const messageRenderer = new MessageRenderer(PayPalCommerceGateway.messages);
|
||||
const context = PayPalCommerceGateway.context;
|
||||
if (context === 'mini-cart' || context === 'product') {
|
||||
const miniCartBootstrap = new MiniCartBootstap(
|
||||
PayPalCommerceGateway,
|
||||
renderer
|
||||
);
|
||||
|
||||
miniCartBootstrap.init();
|
||||
}
|
||||
|
||||
if (context === 'product') {
|
||||
const singleProductBootstrap = new SingleProductBootstap(
|
||||
PayPalCommerceGateway,
|
||||
renderer,
|
||||
messageRenderer,
|
||||
);
|
||||
|
||||
singleProductBootstrap.init();
|
||||
}
|
||||
|
||||
if (context === 'cart') {
|
||||
const cartBootstrap = new CartBootstrap(
|
||||
PayPalCommerceGateway,
|
||||
renderer,
|
||||
);
|
||||
|
||||
cartBootstrap.init();
|
||||
}
|
||||
|
||||
if (context === 'checkout') {
|
||||
const checkoutBootstap = new CheckoutBootstap(
|
||||
PayPalCommerceGateway,
|
||||
renderer,
|
||||
messageRenderer
|
||||
);
|
||||
|
||||
checkoutBootstap.init();
|
||||
}
|
||||
|
||||
if (context !== 'checkout') {
|
||||
messageRenderer.render();
|
||||
}
|
||||
};
|
||||
document.addEventListener(
|
||||
'DOMContentLoaded',
|
||||
() => {
|
||||
if (!typeof (PayPalCommerceGateway)) {
|
||||
console.error('PayPal button could not be configured.');
|
||||
return;
|
||||
}
|
||||
const script = document.createElement('script');
|
||||
|
||||
script.addEventListener('load', (event) => {
|
||||
bootstrap();
|
||||
});
|
||||
script.setAttribute('src', PayPalCommerceGateway.button.url);
|
||||
Object.entries(PayPalCommerceGateway.script_attributes).forEach(
|
||||
(keyValue) => {
|
||||
script.setAttribute(keyValue[0], keyValue[1]);
|
||||
}
|
||||
);
|
||||
|
||||
if (PayPalCommerceGateway.data_client_id.set_attribute) {
|
||||
dataClientIdAttributeHandler(script, PayPalCommerceGateway.data_client_id);
|
||||
return;
|
||||
}
|
||||
|
||||
document.body.append(script);
|
||||
},
|
||||
);
|
|
@ -0,0 +1,46 @@
|
|||
import onApprove from '../OnApproveHandler/onApproveForContinue.js';
|
||||
import {payerData} from "../Helper/PayerData";
|
||||
|
||||
class CartActionHandler {
|
||||
|
||||
constructor(config, errorHandler) {
|
||||
this.config = config;
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
configuration() {
|
||||
const createOrder = (data, actions) => {
|
||||
const payer = payerData();
|
||||
const bnCode = typeof this.config.bn_codes[this.config.context] !== 'undefined' ?
|
||||
this.config.bn_codes[this.config.context] : '';
|
||||
return fetch(this.config.ajax.create_order.endpoint, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
nonce: this.config.ajax.create_order.nonce,
|
||||
purchase_units: [],
|
||||
bn_code:bnCode,
|
||||
payer,
|
||||
context:this.config.context
|
||||
}),
|
||||
}).then(function(res) {
|
||||
return res.json();
|
||||
}).then(function(data) {
|
||||
if (!data.success) {
|
||||
console.error(data);
|
||||
throw Error(data.data.message);
|
||||
}
|
||||
return data.data.id;
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
createOrder,
|
||||
onApprove: onApprove(this, this.errorHandler),
|
||||
onError: (error) => {
|
||||
this.errorHandler.genericError();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default CartActionHandler;
|
|
@ -0,0 +1,55 @@
|
|||
import onApprove from '../OnApproveHandler/onApproveForPayNow.js';
|
||||
import {payerData} from "../Helper/PayerData";
|
||||
|
||||
class CheckoutActionHandler {
|
||||
|
||||
constructor(config, errorHandler) {
|
||||
this.config = config;
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
configuration() {
|
||||
const createOrder = (data, actions) => {
|
||||
const payer = payerData();
|
||||
const bnCode = typeof this.config.bn_codes[this.config.context] !== 'undefined' ?
|
||||
this.config.bn_codes[this.config.context] : '';
|
||||
|
||||
|
||||
const errorHandler = this.errorHandler;
|
||||
const formValues = jQuery('form.checkout').serialize();
|
||||
|
||||
return fetch(this.config.ajax.create_order.endpoint, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
nonce: this.config.ajax.create_order.nonce,
|
||||
payer,
|
||||
bn_code:bnCode,
|
||||
context:this.config.context,
|
||||
form:formValues
|
||||
})
|
||||
}).then(function (res) {
|
||||
return res.json();
|
||||
}).then(function (data) {
|
||||
if (!data.success) {
|
||||
errorHandler.message(data.data.message, true);
|
||||
return;
|
||||
}
|
||||
const input = document.createElement('input');
|
||||
input.setAttribute('type', 'hidden');
|
||||
input.setAttribute('name', 'ppcp-resume-order');
|
||||
input.setAttribute('value', data.data.purchase_units[0].custom_id);
|
||||
document.querySelector('form.checkout').append(input);
|
||||
return data.data.id;
|
||||
});
|
||||
}
|
||||
return {
|
||||
createOrder,
|
||||
onApprove:onApprove(this, this.errorHandler),
|
||||
onError: (error) => {
|
||||
this.errorHandler.genericError();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default CheckoutActionHandler;
|
|
@ -0,0 +1,133 @@
|
|||
import ButtonsToggleListener from '../Helper/ButtonsToggleListener';
|
||||
import Product from '../Entity/Product';
|
||||
import onApprove from '../OnApproveHandler/onApproveForContinue';
|
||||
import {payerData} from "../Helper/PayerData";
|
||||
|
||||
class SingleProductActionHandler {
|
||||
|
||||
constructor(
|
||||
config,
|
||||
updateCart,
|
||||
showButtonCallback,
|
||||
hideButtonCallback,
|
||||
formElement,
|
||||
errorHandler
|
||||
) {
|
||||
this.config = config;
|
||||
this.updateCart = updateCart;
|
||||
this.showButtonCallback = showButtonCallback;
|
||||
this.hideButtonCallback = hideButtonCallback;
|
||||
this.formElement = formElement;
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
configuration()
|
||||
{
|
||||
|
||||
if ( this.hasVariations() ) {
|
||||
const observer = new ButtonsToggleListener(
|
||||
this.formElement.querySelector('.single_add_to_cart_button'),
|
||||
this.showButtonCallback,
|
||||
this.hideButtonCallback
|
||||
);
|
||||
observer.init();
|
||||
}
|
||||
|
||||
return {
|
||||
createOrder: this.createOrder(),
|
||||
onApprove: onApprove(this, this.errorHandler),
|
||||
onError: (error) => {
|
||||
this.errorHandler.genericError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createOrder()
|
||||
{
|
||||
var getProducts = null;
|
||||
if (! this.isGroupedProduct() ) {
|
||||
getProducts = () => {
|
||||
const id = document.querySelector('[name="add-to-cart"]').value;
|
||||
const qty = document.querySelector('[name="quantity"]').value;
|
||||
const variations = this.variations();
|
||||
return [new Product(id, qty, variations)];
|
||||
}
|
||||
} else {
|
||||
getProducts = () => {
|
||||
const products = [];
|
||||
this.formElement.querySelectorAll('input[type="number"]').forEach((element) => {
|
||||
if (! element.value) {
|
||||
return;
|
||||
}
|
||||
const elementName = element.getAttribute('name').match(/quantity\[([\d]*)\]/);
|
||||
if (elementName.length !== 2) {
|
||||
return;
|
||||
}
|
||||
const id = parseInt(elementName[1]);
|
||||
const quantity = parseInt(element.value);
|
||||
products.push(new Product(id, quantity, null));
|
||||
})
|
||||
return products;
|
||||
}
|
||||
}
|
||||
const createOrder = (data, actions) => {
|
||||
this.errorHandler.clear();
|
||||
|
||||
const onResolve = (purchase_units) => {
|
||||
const payer = payerData();
|
||||
const bnCode = typeof this.config.bn_codes[this.config.context] !== 'undefined' ?
|
||||
this.config.bn_codes[this.config.context] : '';
|
||||
return fetch(this.config.ajax.create_order.endpoint, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
nonce: this.config.ajax.create_order.nonce,
|
||||
purchase_units,
|
||||
payer,
|
||||
bn_code:bnCode,
|
||||
context:this.config.context
|
||||
})
|
||||
}).then(function (res) {
|
||||
return res.json();
|
||||
}).then(function (data) {
|
||||
if (!data.success) {
|
||||
console.error(data);
|
||||
throw Error(data.data.message);
|
||||
}
|
||||
return data.data.id;
|
||||
});
|
||||
};
|
||||
|
||||
const promise = this.updateCart.update(onResolve, getProducts());
|
||||
return promise;
|
||||
};
|
||||
return createOrder;
|
||||
}
|
||||
|
||||
variations()
|
||||
{
|
||||
|
||||
if (! this.hasVariations()) {
|
||||
return null;
|
||||
}
|
||||
const attributes = [...this.formElement.querySelectorAll("[name^='attribute_']")].map(
|
||||
(element) => {
|
||||
return {
|
||||
value:element.value,
|
||||
name:element.name
|
||||
}
|
||||
}
|
||||
);
|
||||
return attributes;
|
||||
}
|
||||
|
||||
hasVariations()
|
||||
{
|
||||
return this.formElement.classList.contains('variations_form');
|
||||
}
|
||||
|
||||
isGroupedProduct()
|
||||
{
|
||||
return this.formElement.classList.contains('grouped_form');
|
||||
}
|
||||
}
|
||||
export default SingleProductActionHandler;
|
|
@ -0,0 +1,42 @@
|
|||
import CartActionHandler from '../ActionHandler/CartActionHandler';
|
||||
import ErrorHandler from '../ErrorHandler';
|
||||
|
||||
class CartBootstrap {
|
||||
constructor(gateway, renderer) {
|
||||
this.gateway = gateway;
|
||||
this.renderer = renderer;
|
||||
}
|
||||
|
||||
init() {
|
||||
if (!this.shouldRender()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.render();
|
||||
|
||||
jQuery(document.body).on('updated_cart_totals updated_checkout', () => {
|
||||
this.render();
|
||||
});
|
||||
}
|
||||
|
||||
shouldRender() {
|
||||
return document.querySelector(this.gateway.button.wrapper) !==
|
||||
null || document.querySelector(this.gateway.hosted_fields.wrapper) !==
|
||||
null;
|
||||
}
|
||||
|
||||
render() {
|
||||
const actionHandler = new CartActionHandler(
|
||||
PayPalCommerceGateway,
|
||||
new ErrorHandler(this.gateway.labels.error.generic),
|
||||
);
|
||||
|
||||
this.renderer.render(
|
||||
this.gateway.button.wrapper,
|
||||
this.gateway.hosted_fields.wrapper,
|
||||
actionHandler.configuration(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default CartBootstrap;
|
|
@ -0,0 +1,80 @@
|
|||
import ErrorHandler from '../ErrorHandler';
|
||||
import CheckoutActionHandler from '../ActionHandler/CheckoutActionHandler';
|
||||
|
||||
class CheckoutBootstap {
|
||||
constructor(gateway, renderer, messages) {
|
||||
this.gateway = gateway;
|
||||
this.renderer = renderer;
|
||||
this.messages = messages
|
||||
}
|
||||
|
||||
init() {
|
||||
|
||||
this.render();
|
||||
|
||||
jQuery(document.body).on('updated_checkout', () => {
|
||||
this.render();
|
||||
});
|
||||
|
||||
jQuery(document.body).
|
||||
on('updated_checkout payment_method_selected', () => {
|
||||
this.switchBetweenPayPalandOrderButton();
|
||||
});
|
||||
this.switchBetweenPayPalandOrderButton();
|
||||
}
|
||||
|
||||
shouldRender() {
|
||||
if (document.querySelector(this.gateway.button.cancel_wrapper)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return document.querySelector(this.gateway.button.wrapper) !== null || document.querySelector(this.gateway.hosted_fields.wrapper) !== null;
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.shouldRender()) {
|
||||
return;
|
||||
}
|
||||
if (document.querySelector(this.gateway.hosted_fields.wrapper + '>div')) {
|
||||
document.querySelector(this.gateway.hosted_fields.wrapper + '>div').setAttribute('style', '');
|
||||
}
|
||||
const actionHandler = new CheckoutActionHandler(
|
||||
PayPalCommerceGateway,
|
||||
new ErrorHandler(this.gateway.labels.error.generic),
|
||||
);
|
||||
|
||||
this.renderer.render(
|
||||
this.gateway.button.wrapper,
|
||||
this.gateway.hosted_fields.wrapper,
|
||||
actionHandler.configuration(),
|
||||
);
|
||||
}
|
||||
|
||||
switchBetweenPayPalandOrderButton() {
|
||||
const currentPaymentMethod = jQuery(
|
||||
'input[name="payment_method"]:checked').val();
|
||||
|
||||
if (currentPaymentMethod !== 'ppcp-gateway' && currentPaymentMethod !== 'ppcp-credit-card-gateway') {
|
||||
this.renderer.hideButtons(this.gateway.button.wrapper);
|
||||
this.renderer.hideButtons(this.gateway.messages.wrapper);
|
||||
this.renderer.hideButtons(this.gateway.hosted_fields.wrapper);
|
||||
jQuery('#place_order').show();
|
||||
}
|
||||
else {
|
||||
jQuery('#place_order').hide();
|
||||
if (currentPaymentMethod === 'ppcp-gateway') {
|
||||
this.renderer.showButtons(this.gateway.button.wrapper);
|
||||
this.renderer.showButtons(this.gateway.messages.wrapper);
|
||||
this.messages.render();
|
||||
this.renderer.hideButtons(this.gateway.hosted_fields.wrapper);
|
||||
}
|
||||
if (currentPaymentMethod === 'ppcp-credit-card-gateway') {
|
||||
this.renderer.hideButtons(this.gateway.button.wrapper);
|
||||
this.renderer.hideButtons(this.gateway.messages.wrapper);
|
||||
this.renderer.showButtons(this.gateway.hosted_fields.wrapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default CheckoutBootstap;
|
|
@ -0,0 +1,43 @@
|
|||
import ErrorHandler from '../ErrorHandler';
|
||||
import CartActionHandler from '../ActionHandler/CartActionHandler';
|
||||
|
||||
class MiniCartBootstap {
|
||||
constructor(gateway, renderer) {
|
||||
this.gateway = gateway;
|
||||
this.renderer = renderer;
|
||||
this.actionHandler = null;
|
||||
}
|
||||
|
||||
init() {
|
||||
|
||||
this.actionHandler = new CartActionHandler(
|
||||
PayPalCommerceGateway,
|
||||
new ErrorHandler(this.gateway.labels.error.generic),
|
||||
);
|
||||
this.render();
|
||||
|
||||
jQuery(document.body).on('wc_fragments_loaded wc_fragments_refreshed', () => {
|
||||
this.render();
|
||||
});
|
||||
}
|
||||
|
||||
shouldRender() {
|
||||
return document.querySelector(this.gateway.button.mini_cart_wrapper) !==
|
||||
null || document.querySelector(this.gateway.hosted_fields.mini_cart_wrapper) !==
|
||||
null;
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.shouldRender()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.renderer.render(
|
||||
this.gateway.button.mini_cart_wrapper,
|
||||
this.gateway.hosted_fields.mini_cart_wrapper,
|
||||
this.actionHandler.configuration()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default MiniCartBootstap;
|
|
@ -0,0 +1,65 @@
|
|||
import ErrorHandler from '../ErrorHandler';
|
||||
import UpdateCart from "../Helper/UpdateCart";
|
||||
import SingleProductActionHandler from "../ActionHandler/SingleProductActionHandler";
|
||||
|
||||
class SingleProductBootstap {
|
||||
constructor(gateway, renderer, messages) {
|
||||
this.gateway = gateway;
|
||||
this.renderer = renderer;
|
||||
this.messages = messages;
|
||||
}
|
||||
|
||||
init() {
|
||||
if (!this.shouldRender()) {
|
||||
this.renderer.hideButtons(this.gateway.hosted_fields.wrapper);
|
||||
return;
|
||||
}
|
||||
|
||||
this.render();
|
||||
}
|
||||
|
||||
shouldRender() {
|
||||
if (document.querySelector('form.cart') === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
render() {
|
||||
const actionHandler = new SingleProductActionHandler(
|
||||
this.gateway,
|
||||
new UpdateCart(
|
||||
this.gateway.ajax.change_cart.endpoint,
|
||||
this.gateway.ajax.change_cart.nonce,
|
||||
),
|
||||
() => {
|
||||
this.renderer.showButtons(this.gateway.button.wrapper);
|
||||
this.renderer.showButtons(this.gateway.hosted_fields.wrapper);
|
||||
let priceText = "0";
|
||||
if (document.querySelector('form.cart ins .woocommerce-Price-amount')) {
|
||||
priceText = document.querySelector('form.cart ins .woocommerce-Price-amount').innerText;
|
||||
}
|
||||
else if (document.querySelector('form.cart .woocommerce-Price-amount')) {
|
||||
priceText = document.querySelector('form.cart .woocommerce-Price-amount').innerText;
|
||||
}
|
||||
const amount = parseInt(priceText.replace(/([^\d,\.\s]*)/g, ''));
|
||||
this.messages.renderWithAmount(amount)
|
||||
},
|
||||
() => {
|
||||
this.renderer.hideButtons(this.gateway.button.wrapper);
|
||||
this.renderer.hideButtons(this.gateway.hosted_fields.wrapper);
|
||||
},
|
||||
document.querySelector('form.cart'),
|
||||
new ErrorHandler(this.gateway.labels.error.generic),
|
||||
);
|
||||
|
||||
this.renderer.render(
|
||||
this.gateway.button.wrapper,
|
||||
this.gateway.hosted_fields.wrapper,
|
||||
actionHandler.configuration(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default SingleProductBootstap;
|
|
@ -0,0 +1,52 @@
|
|||
const storageKey = 'ppcp-data-client-id';
|
||||
|
||||
const validateToken = (token, user) => {
|
||||
if (! token) {
|
||||
return false;
|
||||
}
|
||||
if (token.user !== user) {
|
||||
return false;
|
||||
}
|
||||
const currentTime = new Date().getTime();
|
||||
const isExpired = currentTime >= token.expiration * 1000;
|
||||
return ! isExpired;
|
||||
}
|
||||
|
||||
const storedTokenForUser = (user) => {
|
||||
const token = JSON.parse(sessionStorage.getItem(storageKey));
|
||||
if (validateToken(token, user)) {
|
||||
return token.token;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
const storeToken = (token) => {
|
||||
sessionStorage.setItem(storageKey, JSON.stringify(token));
|
||||
}
|
||||
|
||||
const dataClientIdAttributeHandler = (script, config) => {
|
||||
const token = storedTokenForUser(config.user);
|
||||
if (token) {
|
||||
script.setAttribute('data-client-token', token);
|
||||
document.body.append(script);
|
||||
return;
|
||||
}
|
||||
fetch(config.endpoint, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
nonce: config.nonce
|
||||
})
|
||||
}).then((res)=>{
|
||||
return res.json();
|
||||
}).then((data)=>{
|
||||
const isValid = validateToken(data, config.user);
|
||||
if (!isValid) {
|
||||
return;
|
||||
}
|
||||
storeToken(data);
|
||||
script.setAttribute('data-client-token', data.token);
|
||||
document.body.append(script);
|
||||
});
|
||||
}
|
||||
|
||||
export default dataClientIdAttributeHandler;
|
18
modules/ppcp-button/resources/js/modules/Entity/Product.js
Normal file
18
modules/ppcp-button/resources/js/modules/Entity/Product.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
class Product {
|
||||
|
||||
constructor(id, quantity, variations) {
|
||||
this.id = id;
|
||||
this.quantity = quantity;
|
||||
this.variations = variations;
|
||||
}
|
||||
|
||||
data() {
|
||||
return {
|
||||
id:this.id,
|
||||
quantity:this.quantity,
|
||||
variations:this.variations
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Product;
|
46
modules/ppcp-button/resources/js/modules/ErrorHandler.js
Normal file
46
modules/ppcp-button/resources/js/modules/ErrorHandler.js
Normal file
|
@ -0,0 +1,46 @@
|
|||
class ErrorHandler {
|
||||
|
||||
constructor(genericErrorText)
|
||||
{
|
||||
this.genericErrorText = genericErrorText;
|
||||
this.wrapper = document.querySelector('.woocommerce-notices-wrapper');
|
||||
}
|
||||
|
||||
genericError() {
|
||||
if (this.wrapper.classList.contains('ppcp-persist')) {
|
||||
return;
|
||||
}
|
||||
this.clear();
|
||||
this.message(this.genericErrorText)
|
||||
}
|
||||
|
||||
message(text, persist = false)
|
||||
{
|
||||
this.wrapper.classList.add('woocommerce-error');
|
||||
if (persist) {
|
||||
this.wrapper.classList.add('ppcp-persist');
|
||||
} else {
|
||||
this.wrapper.classList.remove('ppcp-persist');
|
||||
}
|
||||
this.wrapper.innerText = this.sanitize(text);
|
||||
jQuery.scroll_to_notices(jQuery('.woocommerce-notices-wrapper'))
|
||||
}
|
||||
|
||||
sanitize(text)
|
||||
{
|
||||
const textarea = document.createElement('textarea');
|
||||
textarea.innerHTML = text;
|
||||
return textarea.value.replace('Error: ', '');
|
||||
}
|
||||
|
||||
clear()
|
||||
{
|
||||
if (! this.wrapper.classList.contains('woocommerce-error')) {
|
||||
return;
|
||||
}
|
||||
this.wrapper.classList.remove('woocommerce-error');
|
||||
this.wrapper.innerText = '';
|
||||
}
|
||||
}
|
||||
|
||||
export default ErrorHandler;
|
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
* When you can't add something to the cart, the PayPal buttons should not show.
|
||||
* Therefore we listen for changes on the add to cart button and show/hide the buttons accordingly.
|
||||
*/
|
||||
|
||||
class ButtonsToggleListener {
|
||||
constructor(element, showCallback, hideCallback)
|
||||
{
|
||||
this.element = element;
|
||||
this.showCallback = showCallback;
|
||||
this.hideCallback = hideCallback;
|
||||
this.observer = null;
|
||||
}
|
||||
|
||||
init()
|
||||
{
|
||||
const config = { attributes : true };
|
||||
const callback = () => {
|
||||
if (this.element.classList.contains('disabled')) {
|
||||
this.hideCallback();
|
||||
return;
|
||||
}
|
||||
this.showCallback();
|
||||
}
|
||||
this.observer = new MutationObserver(callback);
|
||||
this.observer.observe(this.element, config);
|
||||
callback();
|
||||
}
|
||||
|
||||
disconnect()
|
||||
{
|
||||
this.observer.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
export default ButtonsToggleListener;
|
34
modules/ppcp-button/resources/js/modules/Helper/PayerData.js
Normal file
34
modules/ppcp-button/resources/js/modules/Helper/PayerData.js
Normal file
|
@ -0,0 +1,34 @@
|
|||
export const payerData = () => {
|
||||
const payer = PayPalCommerceGateway.payer;
|
||||
if (! payer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const phone = (document.querySelector('#billing_phone') || typeof payer.phone !== 'undefined') ?
|
||||
{
|
||||
phone_type:"HOME",
|
||||
phone_number:{
|
||||
national_number : (document.querySelector('#billing_phone')) ? document.querySelector('#billing_phone').value : payer.phone.phone_number.national_number
|
||||
}
|
||||
} : null;
|
||||
const payerData = {
|
||||
email_address:(document.querySelector('#billing_email')) ? document.querySelector('#billing_email').value : payer.email_address,
|
||||
name : {
|
||||
surname: (document.querySelector('#billing_last_name')) ? document.querySelector('#billing_last_name').value : payer.name.surname,
|
||||
given_name: (document.querySelector('#billing_first_name')) ? document.querySelector('#billing_first_name').value : payer.name.given_name
|
||||
},
|
||||
address : {
|
||||
country_code : (document.querySelector('#billing_country')) ? document.querySelector('#billing_country').value : payer.address.country_code,
|
||||
address_line_1 : (document.querySelector('#billing_address_1')) ? document.querySelector('#billing_address_1').value : payer.address.address_line_1,
|
||||
address_line_2 : (document.querySelector('#billing_address_2')) ? document.querySelector('#billing_address_2').value : payer.address.address_line_2,
|
||||
admin_area_1 : (document.querySelector('#billing_city')) ? document.querySelector('#billing_city').value : payer.address.admin_area_1,
|
||||
admin_area_2 : (document.querySelector('#billing_state')) ? document.querySelector('#billing_state').value : payer.address.admin_area_2,
|
||||
postal_code : (document.querySelector('#billing_postcode')) ? document.querySelector('#billing_postcode').value : payer.address.postal_code
|
||||
}
|
||||
};
|
||||
|
||||
if (phone) {
|
||||
payerData.phone = phone;
|
||||
}
|
||||
return payerData;
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
import Product from "../Entity/Product";
|
||||
class UpdateCart {
|
||||
|
||||
constructor(endpoint, nonce)
|
||||
{
|
||||
this.endpoint = endpoint;
|
||||
this.nonce = nonce;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param onResolve
|
||||
* @param {Product[]} products
|
||||
* @returns {Promise<unknown>}
|
||||
*/
|
||||
update(onResolve, products)
|
||||
{
|
||||
return new Promise((resolve, reject) => {
|
||||
fetch(
|
||||
this.endpoint,
|
||||
{
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
nonce: this.nonce,
|
||||
products,
|
||||
})
|
||||
}
|
||||
).then(
|
||||
(result) => {
|
||||
return result.json();
|
||||
}
|
||||
).then((result) => {
|
||||
if (! result.success) {
|
||||
reject(result.data);
|
||||
return;
|
||||
}
|
||||
|
||||
const resolved = onResolve(result.data);
|
||||
resolve(resolved);
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default UpdateCart;
|
|
@ -0,0 +1,24 @@
|
|||
const onApprove = (context, errorHandler) => {
|
||||
return (data, actions) => {
|
||||
return fetch(context.config.ajax.approve_order.endpoint, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
nonce: context.config.ajax.approve_order.nonce,
|
||||
order_id:data.orderID
|
||||
})
|
||||
}).then((res)=>{
|
||||
return res.json();
|
||||
}).then((data)=>{
|
||||
if (!data.success) {
|
||||
errorHandler.genericError();
|
||||
return actions.restart().catch(err => {
|
||||
errorHandler.genericError();
|
||||
});;
|
||||
}
|
||||
location.href = context.config.redirect;
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export default onApprove;
|
|
@ -0,0 +1,26 @@
|
|||
const onApprove = (context, errorHandler) => {
|
||||
return (data, actions) => {
|
||||
return fetch(context.config.ajax.approve_order.endpoint, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
nonce: context.config.ajax.approve_order.nonce,
|
||||
order_id:data.orderID
|
||||
})
|
||||
}).then((res)=>{
|
||||
return res.json();
|
||||
}).then((data)=>{
|
||||
if (!data.success) {
|
||||
errorHandler.genericError();
|
||||
console.error(data);
|
||||
if (typeof actions.restart !== 'undefined') {
|
||||
return actions.restart();
|
||||
}
|
||||
throw new Error(data.data.message);
|
||||
}
|
||||
document.querySelector('#place_order').click()
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export default onApprove;
|
|
@ -0,0 +1,86 @@
|
|||
class CreditCardRenderer {
|
||||
|
||||
constructor(defaultConfig, errorHandler) {
|
||||
this.defaultConfig = defaultConfig;
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
render(wrapper, contextConfig) {
|
||||
|
||||
if (
|
||||
this.defaultConfig.context !== 'checkout'
|
||||
|| wrapper === null
|
||||
|| document.querySelector(wrapper) === null
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
typeof paypal.HostedFields === 'undefined'
|
||||
|| ! paypal.HostedFields.isEligible()
|
||||
) {
|
||||
const wrapperElement = document.querySelector(wrapper);
|
||||
wrapperElement.parentNode.removeChild(wrapperElement);
|
||||
return;
|
||||
}
|
||||
if (
|
||||
this.defaultConfig.enforce_vault
|
||||
&& document.querySelector(wrapper + ' .ppcp-credit-card-vault')
|
||||
) {
|
||||
document.querySelector(wrapper + ' .ppcp-credit-card-vault').checked = true;
|
||||
document.querySelector(wrapper + ' .ppcp-credit-card-vault').setAttribute('disabled', true);
|
||||
}
|
||||
paypal.HostedFields.render({
|
||||
createOrder: contextConfig.createOrder,
|
||||
fields: {
|
||||
number: {
|
||||
selector: wrapper + ' .ppcp-credit-card',
|
||||
placeholder: this.defaultConfig.hosted_fields.labels.credit_card_number,
|
||||
},
|
||||
cvv: {
|
||||
selector: wrapper + ' .ppcp-cvv',
|
||||
placeholder: this.defaultConfig.hosted_fields.labels.cvv,
|
||||
},
|
||||
expirationDate: {
|
||||
selector: wrapper + ' .ppcp-expiration-date',
|
||||
placeholder: this.defaultConfig.hosted_fields.labels.mm_yyyy,
|
||||
}
|
||||
}
|
||||
}).then(hostedFields => {
|
||||
const submitEvent = (event) => {
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
this.errorHandler.clear();
|
||||
const state = hostedFields.getState();
|
||||
const formValid = Object.keys(state.fields).every(function (key) {
|
||||
return state.fields[key].isValid;
|
||||
});
|
||||
|
||||
if (formValid) {
|
||||
|
||||
let vault = document.querySelector(wrapper + ' .ppcp-credit-card-vault') ?
|
||||
document.querySelector(wrapper + ' .ppcp-credit-card-vault').checked : false;
|
||||
vault = this.defaultConfig.enforce_vault || vault;
|
||||
|
||||
hostedFields.submit({
|
||||
contingencies: ['3D_SECURE'],
|
||||
vault
|
||||
}).then((payload) => {
|
||||
payload.orderID = payload.orderId;
|
||||
return contextConfig.onApprove(payload);
|
||||
});
|
||||
} else {
|
||||
this.errorHandler.message(this.defaultConfig.hosted_fields.labels.fields_not_valid);
|
||||
}
|
||||
}
|
||||
hostedFields.on('inputSubmitRequest', function () {
|
||||
submitEvent(null);
|
||||
});
|
||||
document.querySelector(wrapper).addEventListener(
|
||||
'submit',
|
||||
submitEvent
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
export default CreditCardRenderer;
|
|
@ -0,0 +1,49 @@
|
|||
class MessageRenderer {
|
||||
|
||||
constructor(config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
render() {
|
||||
if (! this.shouldRender()) {
|
||||
return;
|
||||
}
|
||||
|
||||
paypal.Messages({
|
||||
amount: this.config.amount,
|
||||
placement: this.config.placement,
|
||||
style: this.config.style
|
||||
}).render(this.config.wrapper);
|
||||
}
|
||||
|
||||
renderWithAmount(amount) {
|
||||
|
||||
if (! this.shouldRender()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newWrapper = document.createElement('div');
|
||||
newWrapper.setAttribute('id', this.config.wrapper.replace('#', ''));
|
||||
|
||||
const sibling = document.querySelector(this.config.wrapper).nextSibling;
|
||||
document.querySelector(this.config.wrapper).parentElement.removeChild(document.querySelector(this.config.wrapper));
|
||||
sibling.parentElement.insertBefore(newWrapper, sibling);
|
||||
paypal.Messages({
|
||||
amount,
|
||||
placement: this.config.placement,
|
||||
style: this.config.style
|
||||
}).render(this.config.wrapper);
|
||||
}
|
||||
|
||||
shouldRender() {
|
||||
|
||||
if (typeof paypal.Messages === 'undefined' || typeof this.config.wrapper === 'undefined' ) {
|
||||
return false;
|
||||
}
|
||||
if (! document.querySelector(this.config.wrapper)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
export default MessageRenderer;
|
|
@ -0,0 +1,48 @@
|
|||
class Renderer {
|
||||
constructor(creditCardRenderer, defaultConfig) {
|
||||
this.defaultConfig = defaultConfig;
|
||||
this.creditCardRenderer = creditCardRenderer;
|
||||
}
|
||||
|
||||
render(wrapper, hostedFieldsWrapper, contextConfig) {
|
||||
|
||||
this.renderButtons(wrapper, contextConfig);
|
||||
this.creditCardRenderer.render(hostedFieldsWrapper, contextConfig);
|
||||
}
|
||||
|
||||
renderButtons(wrapper, contextConfig) {
|
||||
if (! document.querySelector(wrapper) || this.isAlreadyRendered(wrapper)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const style = wrapper === this.defaultConfig.button.wrapper ? this.defaultConfig.button.style : this.defaultConfig.button.mini_cart_style;
|
||||
paypal.Buttons({
|
||||
style,
|
||||
...contextConfig,
|
||||
}).render(wrapper);
|
||||
}
|
||||
|
||||
isAlreadyRendered(wrapper) {
|
||||
return document.querySelector(wrapper).hasChildNodes();
|
||||
}
|
||||
|
||||
hideButtons(element) {
|
||||
const domElement = document.querySelector(element);
|
||||
if (! domElement ) {
|
||||
return false;
|
||||
}
|
||||
domElement.style.display = 'none';
|
||||
return true;
|
||||
}
|
||||
|
||||
showButtons(element) {
|
||||
const domElement = document.querySelector(element);
|
||||
if (! domElement ) {
|
||||
return false;
|
||||
}
|
||||
domElement.style.display = 'block';
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export default Renderer;
|
157
modules/ppcp-button/services.php
Normal file
157
modules/ppcp-button/services.php
Normal file
|
@ -0,0 +1,157 @@
|
|||
<?php
|
||||
/**
|
||||
* The button module services.
|
||||
*
|
||||
* @package Inpsyde\PayPalCommerce\Button
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Inpsyde\PayPalCommerce\Button;
|
||||
|
||||
use Dhii\Data\Container\ContainerInterface;
|
||||
use Inpsyde\PayPalCommerce\Button\Assets\DisabledSmartButton;
|
||||
use Inpsyde\PayPalCommerce\Button\Assets\SmartButton;
|
||||
use Inpsyde\PayPalCommerce\Button\Assets\SmartButtonInterface;
|
||||
use Inpsyde\PayPalCommerce\Button\Endpoint\ApproveOrderEndpoint;
|
||||
use Inpsyde\PayPalCommerce\Button\Endpoint\ChangeCartEndpoint;
|
||||
use Inpsyde\PayPalCommerce\Button\Endpoint\CreateOrderEndpoint;
|
||||
use Inpsyde\PayPalCommerce\Button\Endpoint\DataClientIdEndpoint;
|
||||
use Inpsyde\PayPalCommerce\Button\Endpoint\RequestData;
|
||||
use Inpsyde\PayPalCommerce\Button\Exception\RuntimeException;
|
||||
use Inpsyde\PayPalCommerce\Button\Helper\EarlyOrderHandler;
|
||||
use Inpsyde\PayPalCommerce\Button\Helper\MessagesApply;
|
||||
use Inpsyde\PayPalCommerce\Button\Helper\ThreeDSecure;
|
||||
use Inpsyde\PayPalCommerce\Onboarding\Environment;
|
||||
use Inpsyde\PayPalCommerce\Onboarding\State;
|
||||
|
||||
return array(
|
||||
'button.client_id' => static function ( ContainerInterface $container ): string {
|
||||
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
$client_id = $settings->has( 'client_id' ) ? $settings->get( 'client_id' ) : '';
|
||||
if ( $client_id ) {
|
||||
return $client_id;
|
||||
}
|
||||
|
||||
$env = $container->get( 'onboarding.environment' );
|
||||
/**
|
||||
* The environment.
|
||||
*
|
||||
* @var Environment $env
|
||||
*/
|
||||
|
||||
/**
|
||||
* ToDo: Add production platform client Id.
|
||||
*/
|
||||
return $env->current_environment_is( Environment::SANDBOX ) ?
|
||||
'AQB97CzMsd58-It1vxbcDAGvMuXNCXRD9le_XUaMlHB_U7XsU9IiItBwGQOtZv9sEeD6xs2vlIrL4NiD' : '';
|
||||
},
|
||||
'button.smart-button' => static function ( ContainerInterface $container ): SmartButtonInterface {
|
||||
|
||||
$state = $container->get( 'onboarding.state' );
|
||||
/**
|
||||
* The state.
|
||||
*
|
||||
* @var State $state
|
||||
*/
|
||||
if ( $state->current_state() < State::STATE_PROGRESSIVE ) {
|
||||
return new DisabledSmartButton();
|
||||
}
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
$paypal_disabled = ! $settings->has( 'enabled' ) || ! $settings->get( 'enabled' );
|
||||
$credit_card_disabled = ! $settings->has( 'dcc_gateway_enabled' ) || ! $settings->get( 'dcc_gateway_enabled' );
|
||||
if ( $paypal_disabled && $credit_card_disabled ) {
|
||||
return new DisabledSmartButton();
|
||||
}
|
||||
$payee_repository = $container->get( 'api.repository.payee' );
|
||||
$identity_token = $container->get( 'api.endpoint.identity-token' );
|
||||
$payer_factory = $container->get( 'api.factory.payer' );
|
||||
$request_data = $container->get( 'button.request-data' );
|
||||
|
||||
$client_id = $container->get( 'button.client_id' );
|
||||
$dcc_applies = $container->get( 'api.helpers.dccapplies' );
|
||||
$subscription_helper = $container->get( 'subscription.helper' );
|
||||
$messages_apply = $container->get( 'button.helper.messages-apply' );
|
||||
return new SmartButton(
|
||||
$container->get( 'button.url' ),
|
||||
$container->get( 'session.handler' ),
|
||||
$settings,
|
||||
$payee_repository,
|
||||
$identity_token,
|
||||
$payer_factory,
|
||||
$client_id,
|
||||
$request_data,
|
||||
$dcc_applies,
|
||||
$subscription_helper,
|
||||
$messages_apply
|
||||
);
|
||||
},
|
||||
'button.url' => static function ( ContainerInterface $container ): string {
|
||||
return plugins_url(
|
||||
'/modules.local/ppcp-button/',
|
||||
dirname( __FILE__, 3 ) . '/woocommerce-paypal-commerce-gateway.php'
|
||||
);
|
||||
},
|
||||
'button.request-data' => static function ( ContainerInterface $container ): RequestData {
|
||||
return new RequestData();
|
||||
},
|
||||
'button.endpoint.change-cart' => static function ( ContainerInterface $container ): ChangeCartEndpoint {
|
||||
if ( ! \WC()->cart ) {
|
||||
throw new RuntimeException( 'cant initialize endpoint at this moment' );
|
||||
}
|
||||
$cart = WC()->cart;
|
||||
$shipping = WC()->shipping();
|
||||
$request_data = $container->get( 'button.request-data' );
|
||||
$repository = $container->get( 'api.repository.cart' );
|
||||
$data_store = \WC_Data_Store::load( 'product' );
|
||||
return new ChangeCartEndpoint( $cart, $shipping, $request_data, $repository, $data_store );
|
||||
},
|
||||
'button.endpoint.create-order' => static function ( ContainerInterface $container ): CreateOrderEndpoint {
|
||||
$request_data = $container->get( 'button.request-data' );
|
||||
$repository = $container->get( 'api.repository.cart' );
|
||||
$order_endpoint = $container->get( 'api.endpoint.order' );
|
||||
$payer_factory = $container->get( 'api.factory.payer' );
|
||||
$session_handler = $container->get( 'session.handler' );
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
$early_order_handler = $container->get( 'button.helper.early-order-handler' );
|
||||
return new CreateOrderEndpoint(
|
||||
$request_data,
|
||||
$repository,
|
||||
$order_endpoint,
|
||||
$payer_factory,
|
||||
$session_handler,
|
||||
$settings,
|
||||
$early_order_handler
|
||||
);
|
||||
},
|
||||
'button.helper.early-order-handler' => static function ( ContainerInterface $container ) : EarlyOrderHandler {
|
||||
|
||||
$state = $container->get( 'onboarding.state' );
|
||||
$order_processor = $container->get( 'wcgateway.order-processor' );
|
||||
$session_handler = $container->get( 'session.handler' );
|
||||
$prefix = $container->get( 'api.prefix' );
|
||||
return new EarlyOrderHandler( $state, $order_processor, $session_handler, $prefix );
|
||||
},
|
||||
'button.endpoint.approve-order' => static function ( ContainerInterface $container ): ApproveOrderEndpoint {
|
||||
$request_data = $container->get( 'button.request-data' );
|
||||
$order_endpoint = $container->get( 'api.endpoint.order' );
|
||||
$session_handler = $container->get( 'session.handler' );
|
||||
$three_d_secure = $container->get( 'button.helper.three-d-secure' );
|
||||
return new ApproveOrderEndpoint( $request_data, $order_endpoint, $session_handler, $three_d_secure );
|
||||
},
|
||||
'button.endpoint.data-client-id' => static function( ContainerInterface $container ) : DataClientIdEndpoint {
|
||||
$request_data = $container->get( 'button.request-data' );
|
||||
$identity_token = $container->get( 'api.endpoint.identity-token' );
|
||||
return new DataClientIdEndpoint(
|
||||
$request_data,
|
||||
$identity_token
|
||||
);
|
||||
},
|
||||
'button.helper.three-d-secure' => static function ( ContainerInterface $container ): ThreeDSecure {
|
||||
return new ThreeDSecure();
|
||||
},
|
||||
'button.helper.messages-apply' => static function ( ContainerInterface $container ): MessagesApply {
|
||||
return new MessagesApply();
|
||||
},
|
||||
);
|
44
modules/ppcp-button/src/Assets/class-disabledsmartbutton.php
Normal file
44
modules/ppcp-button/src/Assets/class-disabledsmartbutton.php
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
/**
|
||||
* If we can't render our buttons, this Null object will be used.
|
||||
*
|
||||
* @package Inpsyde\PayPalCommerce\Button\Assets
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Inpsyde\PayPalCommerce\Button\Assets;
|
||||
|
||||
/**
|
||||
* Class DisabledSmartButton
|
||||
*/
|
||||
class DisabledSmartButton implements SmartButtonInterface {
|
||||
|
||||
/**
|
||||
* Renders the necessary HTML.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function render_wrapper(): bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues necessary scripts.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function enqueue(): bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether tokens can be stored or not.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function can_save_vault_token(): bool {
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
816
modules/ppcp-button/src/Assets/class-smartbutton.php
Normal file
816
modules/ppcp-button/src/Assets/class-smartbutton.php
Normal file
|
@ -0,0 +1,816 @@
|
|||
<?php
|
||||
/**
|
||||
* Registers and configures the necessary Javascript for the button, credit messaging and DCC fields.
|
||||
*
|
||||
* @package Inpsyde\PayPalCommerce\Button\Assets
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Inpsyde\PayPalCommerce\Button\Assets;
|
||||
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Endpoint\IdentityToken;
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Factory\PayerFactory;
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Helper\DccApplies;
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Repository\PayeeRepository;
|
||||
use Inpsyde\PayPalCommerce\Button\Endpoint\ApproveOrderEndpoint;
|
||||
use Inpsyde\PayPalCommerce\Button\Endpoint\ChangeCartEndpoint;
|
||||
use Inpsyde\PayPalCommerce\Button\Endpoint\CreateOrderEndpoint;
|
||||
use Inpsyde\PayPalCommerce\Button\Endpoint\DataClientIdEndpoint;
|
||||
use Inpsyde\PayPalCommerce\Button\Endpoint\RequestData;
|
||||
use Inpsyde\PayPalCommerce\Button\Helper\MessagesApply;
|
||||
use Inpsyde\PayPalCommerce\Session\SessionHandler;
|
||||
use Inpsyde\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
||||
use Inpsyde\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
||||
/**
|
||||
* Class SmartButton
|
||||
*/
|
||||
class SmartButton implements SmartButtonInterface {
|
||||
|
||||
/**
|
||||
* The URL to the module.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $module_url;
|
||||
|
||||
/**
|
||||
* The Session Handler.
|
||||
*
|
||||
* @var SessionHandler
|
||||
*/
|
||||
private $session_handler;
|
||||
|
||||
/**
|
||||
* The settings.
|
||||
*
|
||||
* @var Settings
|
||||
*/
|
||||
private $settings;
|
||||
|
||||
/**
|
||||
* The Payee Repository.
|
||||
*
|
||||
* @var PayeeRepository
|
||||
*/
|
||||
private $payee_repository;
|
||||
|
||||
/**
|
||||
* The Identity Token.
|
||||
*
|
||||
* @var IdentityToken
|
||||
*/
|
||||
private $identity_token;
|
||||
|
||||
/**
|
||||
* The Payer Factory.
|
||||
*
|
||||
* @var PayerFactory
|
||||
*/
|
||||
private $payer_factory;
|
||||
|
||||
/**
|
||||
* The client ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $client_id;
|
||||
|
||||
/**
|
||||
* The Request Data.
|
||||
*
|
||||
* @var RequestData
|
||||
*/
|
||||
private $request_data;
|
||||
|
||||
/**
|
||||
* The DCC Applies helper.
|
||||
*
|
||||
* @var DccApplies
|
||||
*/
|
||||
private $dcc_applies;
|
||||
|
||||
/**
|
||||
* The Subscription Helper.
|
||||
*
|
||||
* @var SubscriptionHelper
|
||||
*/
|
||||
private $subscription_helper;
|
||||
|
||||
/**
|
||||
* The Messages apply helper.
|
||||
*
|
||||
* @var MessagesApply
|
||||
*/
|
||||
private $messages_apply;
|
||||
|
||||
/**
|
||||
* SmartButton constructor.
|
||||
*
|
||||
* @param string $module_url The URL to the module.
|
||||
* @param SessionHandler $session_handler The Session Handler.
|
||||
* @param Settings $settings The Settings.
|
||||
* @param PayeeRepository $payee_repository The Payee Repository.
|
||||
* @param IdentityToken $identity_token The Identity Token.
|
||||
* @param PayerFactory $payer_factory The Payer factory.
|
||||
* @param string $client_id The client ID.
|
||||
* @param RequestData $request_data The Request Data helper.
|
||||
* @param DccApplies $dcc_applies The DCC applies helper.
|
||||
* @param SubscriptionHelper $subscription_helper The subscription helper.
|
||||
* @param MessagesApply $messages_apply The Messages apply helper.
|
||||
*/
|
||||
public function __construct(
|
||||
string $module_url,
|
||||
SessionHandler $session_handler,
|
||||
Settings $settings,
|
||||
PayeeRepository $payee_repository,
|
||||
IdentityToken $identity_token,
|
||||
PayerFactory $payer_factory,
|
||||
string $client_id,
|
||||
RequestData $request_data,
|
||||
DccApplies $dcc_applies,
|
||||
SubscriptionHelper $subscription_helper,
|
||||
MessagesApply $messages_apply
|
||||
) {
|
||||
|
||||
$this->module_url = $module_url;
|
||||
$this->session_handler = $session_handler;
|
||||
$this->settings = $settings;
|
||||
$this->payee_repository = $payee_repository;
|
||||
$this->identity_token = $identity_token;
|
||||
$this->payer_factory = $payer_factory;
|
||||
$this->client_id = $client_id;
|
||||
$this->request_data = $request_data;
|
||||
$this->dcc_applies = $dcc_applies;
|
||||
$this->subscription_helper = $subscription_helper;
|
||||
$this->messages_apply = $messages_apply;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the necessary action hooks to render the HTML depending on the settings.
|
||||
*
|
||||
* @return bool
|
||||
* @throws \Inpsyde\PayPalCommerce\WcGateway\Exception\NotFoundException When a setting was not found.
|
||||
*/
|
||||
public function render_wrapper(): bool {
|
||||
|
||||
if ( ! $this->can_save_vault_token() && $this->has_subscriptions() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( $this->settings->has( 'enabled' ) && $this->settings->get( 'enabled' ) ) {
|
||||
$this->render_button_wrapper_registrar();
|
||||
$this->render_message_wrapper_registrar();
|
||||
}
|
||||
|
||||
if (
|
||||
$this->settings->has( 'dcc_gateway_enabled' )
|
||||
&& $this->settings->get( 'dcc_gateway_enabled' )
|
||||
&& ! $this->session_handler->order()
|
||||
) {
|
||||
add_action(
|
||||
'woocommerce_review_order_after_submit',
|
||||
array(
|
||||
$this,
|
||||
'dcc_renderer',
|
||||
),
|
||||
11
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the hooks to render the credit messaging HTML depending on the settings.
|
||||
*
|
||||
* @return bool
|
||||
* @throws \Inpsyde\PayPalCommerce\WcGateway\Exception\NotFoundException When a setting was not found.
|
||||
*/
|
||||
private function render_message_wrapper_registrar(): bool {
|
||||
|
||||
$not_enabled_on_cart = $this->settings->has( 'message_cart_enabled' ) &&
|
||||
! $this->settings->get( 'message_cart_enabled' );
|
||||
if (
|
||||
is_cart()
|
||||
&& ! $not_enabled_on_cart
|
||||
) {
|
||||
add_action(
|
||||
'woocommerce_proceed_to_checkout',
|
||||
array(
|
||||
$this,
|
||||
'message_renderer',
|
||||
),
|
||||
19
|
||||
);
|
||||
}
|
||||
|
||||
$not_enabled_on_product_page = $this->settings->has( 'message_product_enabled' ) &&
|
||||
! $this->settings->get( 'message_product_enabled' );
|
||||
if (
|
||||
( is_product() || wc_post_content_has_shortcode( 'product_page' ) )
|
||||
&& ! $not_enabled_on_product_page
|
||||
) {
|
||||
add_action(
|
||||
'woocommerce_single_product_summary',
|
||||
array(
|
||||
$this,
|
||||
'message_renderer',
|
||||
),
|
||||
30
|
||||
);
|
||||
}
|
||||
|
||||
$not_enabled_on_checkout = $this->settings->has( 'message_enabled' ) &&
|
||||
! $this->settings->get( 'message_enabled' );
|
||||
if ( ! $not_enabled_on_checkout ) {
|
||||
add_action(
|
||||
'woocommerce_review_order_after_submit',
|
||||
array(
|
||||
$this,
|
||||
'message_renderer',
|
||||
),
|
||||
11
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the hooks where to render the button HTML according to the settings.
|
||||
*
|
||||
* @return bool
|
||||
* @throws \Inpsyde\PayPalCommerce\WcGateway\Exception\NotFoundException When a setting was not found.
|
||||
*/
|
||||
private function render_button_wrapper_registrar(): bool {
|
||||
|
||||
$not_enabled_on_cart = $this->settings->has( 'button_cart_enabled' ) &&
|
||||
! $this->settings->get( 'button_cart_enabled' );
|
||||
if (
|
||||
is_cart()
|
||||
&& ! $not_enabled_on_cart
|
||||
) {
|
||||
add_action(
|
||||
'woocommerce_proceed_to_checkout',
|
||||
array(
|
||||
$this,
|
||||
'button_renderer',
|
||||
),
|
||||
20
|
||||
);
|
||||
}
|
||||
|
||||
$not_enabled_on_product_page = $this->settings->has( 'button_single_product_enabled' ) &&
|
||||
! $this->settings->get( 'button_single_product_enabled' );
|
||||
if (
|
||||
( is_product() || wc_post_content_has_shortcode( 'product_page' ) )
|
||||
&& ! $not_enabled_on_product_page
|
||||
) {
|
||||
add_action(
|
||||
'woocommerce_single_product_summary',
|
||||
array(
|
||||
$this,
|
||||
'button_renderer',
|
||||
),
|
||||
31
|
||||
);
|
||||
}
|
||||
|
||||
$not_enabled_on_minicart = $this->settings->has( 'button_mini_cart_enabled' ) &&
|
||||
! $this->settings->get( 'button_mini_cart_enabled' );
|
||||
if (
|
||||
! $not_enabled_on_minicart
|
||||
) {
|
||||
add_action(
|
||||
'woocommerce_widget_shopping_cart_after_buttons',
|
||||
static function () {
|
||||
echo '<p
|
||||
id="ppc-button-minicart"
|
||||
class="woocommerce-mini-cart__buttons buttons"
|
||||
></p>';
|
||||
},
|
||||
30
|
||||
);
|
||||
}
|
||||
|
||||
add_action( 'woocommerce_review_order_after_submit', array( $this, 'button_renderer' ), 10 );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues the script.
|
||||
*
|
||||
* @return bool
|
||||
* @throws \Inpsyde\PayPalCommerce\WcGateway\Exception\NotFoundException When a setting was not found.
|
||||
*/
|
||||
public function enqueue(): bool {
|
||||
$buttons_enabled = $this->settings->has( 'enabled' ) && $this->settings->get( 'enabled' );
|
||||
if ( ! is_checkout() && ! $buttons_enabled ) {
|
||||
return false;
|
||||
}
|
||||
if ( ! $this->can_save_vault_token() && $this->has_subscriptions() ) {
|
||||
return false;
|
||||
}
|
||||
wp_enqueue_style(
|
||||
'ppcp-hosted-fields',
|
||||
$this->module_url . '/assets/css/hosted-fields.css',
|
||||
array(),
|
||||
1
|
||||
);
|
||||
wp_enqueue_script(
|
||||
'ppcp-smart-button',
|
||||
$this->module_url . '/assets/js/button.js',
|
||||
array( 'jquery' ),
|
||||
1,
|
||||
true
|
||||
);
|
||||
|
||||
wp_localize_script(
|
||||
'ppcp-smart-button',
|
||||
'PayPalCommerceGateway',
|
||||
$this->localize_script()
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the HTML for the buttons.
|
||||
*/
|
||||
public function button_renderer() {
|
||||
$product = wc_get_product();
|
||||
if (
|
||||
! is_checkout() && is_a( $product, \WC_Product::class )
|
||||
&& (
|
||||
$product->is_type( array( 'external', 'grouped' ) )
|
||||
|| ! $product->is_in_stock()
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
echo '<div id="ppc-button"></div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the HTML for the credit messaging.
|
||||
*/
|
||||
public function message_renderer() {
|
||||
|
||||
echo '<div id="ppcp-messages"></div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* The values for the credit messaging.
|
||||
*
|
||||
* @return array
|
||||
* @throws \Inpsyde\PayPalCommerce\WcGateway\Exception\NotFoundException When a setting was not found.
|
||||
*/
|
||||
private function message_values(): array {
|
||||
|
||||
if (
|
||||
$this->settings->has( 'disable_funding' )
|
||||
&& in_array( 'credit', (array) $this->settings->get( 'disable_funding' ), true )
|
||||
) {
|
||||
return array();
|
||||
}
|
||||
$placement = 'product';
|
||||
$product = wc_get_product();
|
||||
$amount = ( is_a( $product, \WC_Product::class ) ) ? wc_get_price_including_tax( $product ) : 0;
|
||||
$layout = $this->settings->has( 'message_product_layout' ) ?
|
||||
$this->settings->get( 'message_product_layout' ) : 'text';
|
||||
$logo_type = $this->settings->has( 'message_product_logo' ) ?
|
||||
$this->settings->get( 'message_product_logo' ) : 'primary';
|
||||
$logo_position = $this->settings->has( 'message_product_position' ) ?
|
||||
$this->settings->get( 'message_product_position' ) : 'left';
|
||||
$text_color = $this->settings->has( 'message_product_color' ) ?
|
||||
$this->settings->get( 'message_product_color' ) : 'black';
|
||||
$style_color = $this->settings->has( 'message_product_flex_color' ) ?
|
||||
$this->settings->get( 'message_product_flex_color' ) : 'blue';
|
||||
$ratio = $this->settings->has( 'message_product_flex_ratio' ) ?
|
||||
$this->settings->get( 'message_product_flex_ratio' ) : '1x1';
|
||||
$should_show = $this->settings->has( 'message_product_enabled' )
|
||||
&& $this->settings->get( 'message_product_enabled' );
|
||||
if ( is_checkout() ) {
|
||||
$placement = 'payment';
|
||||
$amount = WC()->cart->get_total( 'raw' );
|
||||
$layout = $this->settings->has( 'message_layout' ) ?
|
||||
$this->settings->get( 'message_layout' ) : 'text';
|
||||
$logo_type = $this->settings->has( 'message_logo' ) ?
|
||||
$this->settings->get( 'message_logo' ) : 'primary';
|
||||
$logo_position = $this->settings->has( 'message_position' ) ?
|
||||
$this->settings->get( 'message_position' ) : 'left';
|
||||
$text_color = $this->settings->has( 'message_color' ) ?
|
||||
$this->settings->get( 'message_color' ) : 'black';
|
||||
$style_color = $this->settings->has( 'message_flex_color' ) ?
|
||||
$this->settings->get( 'message_flex_color' ) : 'blue';
|
||||
$ratio = $this->settings->has( 'message_flex_ratio' ) ?
|
||||
$this->settings->get( 'message_flex_ratio' ) : '1x1';
|
||||
$should_show = $this->settings->has( 'message_enabled' )
|
||||
&& $this->settings->get( 'message_enabled' );
|
||||
}
|
||||
if ( is_cart() ) {
|
||||
$placement = 'cart';
|
||||
$amount = WC()->cart->get_total( 'raw' );
|
||||
$layout = $this->settings->has( 'message_cart_layout' ) ?
|
||||
$this->settings->get( 'message_cart_layout' ) : 'text';
|
||||
$logo_type = $this->settings->has( 'message_cart_logo' ) ?
|
||||
$this->settings->get( 'message_cart_logo' ) : 'primary';
|
||||
$logo_position = $this->settings->has( 'message_cart_position' ) ?
|
||||
$this->settings->get( 'message_cart_position' ) : 'left';
|
||||
$text_color = $this->settings->has( 'message_cart_color' ) ?
|
||||
$this->settings->get( 'message_cart_color' ) : 'black';
|
||||
$style_color = $this->settings->has( 'message_cart_flex_color' ) ?
|
||||
$this->settings->get( 'message_cart_flex_color' ) : 'blue';
|
||||
$ratio = $this->settings->has( 'message_cart_flex_ratio' ) ?
|
||||
$this->settings->get( 'message_cart_flex_ratio' ) : '1x1';
|
||||
$should_show = $this->settings->has( 'message_cart_enabled' )
|
||||
&& $this->settings->get( 'message_cart_enabled' );
|
||||
}
|
||||
|
||||
if ( ! $should_show ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$values = array(
|
||||
'wrapper' => '#ppcp-messages',
|
||||
'amount' => $amount,
|
||||
'placement' => $placement,
|
||||
'style' => array(
|
||||
'layout' => $layout,
|
||||
'logo' => array(
|
||||
'type' => $logo_type,
|
||||
'position' => $logo_position,
|
||||
),
|
||||
'text' => array(
|
||||
'color' => $text_color,
|
||||
),
|
||||
'color' => $style_color,
|
||||
'ratio' => $ratio,
|
||||
),
|
||||
);
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the HTML for the DCC fields.
|
||||
*
|
||||
* @throws \Inpsyde\PayPalCommerce\WcGateway\Exception\NotFoundException When a setting hasnt been found.
|
||||
*/
|
||||
public function dcc_renderer() {
|
||||
|
||||
$id = 'ppcp-hosted-fields';
|
||||
$can_render_dcc = $this->dcc_applies->for_country_currency()
|
||||
&& $this->settings->has( 'client_id' )
|
||||
&& $this->settings->get( 'client_id' );
|
||||
if ( ! $can_render_dcc ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$save_card = $this->can_save_vault_token() ? sprintf(
|
||||
'<div>
|
||||
|
||||
<label for="ppcp-vault-%1$s">%2$s</label>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="ppcp-vault-%1$s"
|
||||
class="ppcp-credit-card-vault"
|
||||
name="vault"
|
||||
>
|
||||
</div>',
|
||||
esc_attr( $id ),
|
||||
esc_html__( 'Save your card', 'paypal-for-woocommerce' )
|
||||
) : '';
|
||||
|
||||
printf(
|
||||
'<form id="%1$s">
|
||||
<div class="ppcp-dcc-credit-card-wrapper" style="display: none">
|
||||
<label for="ppcp-credit-card-%1$s">%2$s</label>
|
||||
<span id="ppcp-credit-card-%1$s" class="ppcp-credit-card"></span>
|
||||
<label for="ppcp-expiration-date-%1$s">%3$s</label>
|
||||
<span
|
||||
id="ppcp-expiration-date-%1$s"
|
||||
class="ppcp-expiration-date"
|
||||
></span>
|
||||
<label for="ppcp-cvv-%1$s">%4$s</label>
|
||||
<span id="ppcp-cvv-%1$s" class="ppcp-cvv"></span>
|
||||
%5$s
|
||||
<button class="button alt">%6$s</button>
|
||||
</div>
|
||||
</form><div id="payments-sdk__contingency-lightbox"></div>',
|
||||
esc_attr( $id ),
|
||||
esc_html__( 'Credit Card number', 'paypal-for-woocommerce' ),
|
||||
esc_html__( 'Expiration', 'paypal-for-woocommerce' ),
|
||||
esc_html__( 'CVV', 'paypal-for-woocommerce' ),
|
||||
//phpcs:ignore
|
||||
$save_card,
|
||||
esc_html__( 'Place order', 'paypal-for-woocommerce' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether we can store vault tokens or not.
|
||||
*
|
||||
* @return bool
|
||||
* @throws \Inpsyde\PayPalCommerce\WcGateway\Exception\NotFoundException If a setting hasnt been found.
|
||||
*/
|
||||
public function can_save_vault_token(): bool {
|
||||
|
||||
if ( ! $this->settings->has( 'client_id' ) || ! $this->settings->get( 'client_id' ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( ! $this->settings->has( 'vault_enabled' ) || ! $this->settings->get( 'vault_enabled' ) ) {
|
||||
return false;
|
||||
}
|
||||
return is_user_logged_in();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether we need to initialize the script to enable tokenization for subscriptions or not.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function has_subscriptions(): bool {
|
||||
if ( ! $this->subscription_helper->accept_only_automatic_payment_gateways() ) {
|
||||
return false;
|
||||
}
|
||||
if ( is_product() ) {
|
||||
return $this->subscription_helper->current_product_is_subscription();
|
||||
}
|
||||
return $this->subscription_helper->cart_contains_subscription();
|
||||
}
|
||||
|
||||
/**
|
||||
* The localized data for the smart button.
|
||||
*
|
||||
* @return array
|
||||
* @throws \Inpsyde\PayPalCommerce\WcGateway\Exception\NotFoundException If a setting hasn't been found.
|
||||
*/
|
||||
private function localize_script(): array {
|
||||
$this->request_data->enqueue_nonce_fix();
|
||||
$localize = array(
|
||||
'script_attributes' => $this->attributes(),
|
||||
'data_client_id' => array(
|
||||
'set_attribute' => ( is_checkout() && $this->dcc_is_enabled() )
|
||||
|| $this->can_save_vault_token(),
|
||||
'endpoint' => home_url( \WC_AJAX::get_endpoint( DataClientIdEndpoint::ENDPOINT ) ),
|
||||
'nonce' => wp_create_nonce( DataClientIdEndpoint::nonce() ),
|
||||
'user' => get_current_user_id(),
|
||||
),
|
||||
'redirect' => wc_get_checkout_url(),
|
||||
'context' => $this->context(),
|
||||
'ajax' => array(
|
||||
'change_cart' => array(
|
||||
'endpoint' => home_url( \WC_AJAX::get_endpoint( ChangeCartEndpoint::ENDPOINT ) ),
|
||||
'nonce' => wp_create_nonce( ChangeCartEndpoint::nonce() ),
|
||||
),
|
||||
'create_order' => array(
|
||||
'endpoint' => home_url( \WC_AJAX::get_endpoint( CreateOrderEndpoint::ENDPOINT ) ),
|
||||
'nonce' => wp_create_nonce( CreateOrderEndpoint::nonce() ),
|
||||
),
|
||||
'approve_order' => array(
|
||||
'endpoint' => home_url( \WC_AJAX::get_endpoint( ApproveOrderEndpoint::ENDPOINT ) ),
|
||||
'nonce' => wp_create_nonce( ApproveOrderEndpoint::nonce() ),
|
||||
),
|
||||
),
|
||||
'enforce_vault' => $this->has_subscriptions(),
|
||||
'bn_codes' => $this->bn_codes(),
|
||||
'payer' => $this->payerData(),
|
||||
'button' => array(
|
||||
'wrapper' => '#ppc-button',
|
||||
'mini_cart_wrapper' => '#ppc-button-minicart',
|
||||
'cancel_wrapper' => '#ppcp-cancel',
|
||||
'url' => $this->url(),
|
||||
'mini_cart_style' => array(
|
||||
'layout' => $this->style_for_context( 'layout', 'mini-cart' ),
|
||||
'color' => $this->style_for_context( 'color', 'mini-cart' ),
|
||||
'shape' => $this->style_for_context( 'shape', 'mini-cart' ),
|
||||
'label' => $this->style_for_context( 'label', 'mini-cart' ),
|
||||
'tagline' => $this->style_for_context( 'tagline', 'mini-cart' ),
|
||||
),
|
||||
'style' => array(
|
||||
'layout' => $this->style_for_context( 'layout', $this->context() ),
|
||||
'color' => $this->style_for_context( 'color', $this->context() ),
|
||||
'shape' => $this->style_for_context( 'shape', $this->context() ),
|
||||
'label' => $this->style_for_context( 'label', $this->context() ),
|
||||
'tagline' => $this->style_for_context( 'tagline', $this->context() ),
|
||||
),
|
||||
),
|
||||
'hosted_fields' => array(
|
||||
'wrapper' => '#ppcp-hosted-fields',
|
||||
'mini_cart_wrapper' => '#ppcp-hosted-fields-mini-cart',
|
||||
'labels' => array(
|
||||
'credit_card_number' => '',
|
||||
'cvv' => '',
|
||||
'mm_yyyy' => __( 'MM/YYYY', 'paypal-for-woocommerce' ),
|
||||
'fields_not_valid' => __(
|
||||
'Unfortunatly, your credit card details are not valid.',
|
||||
'paypal-for-woocommerce'
|
||||
),
|
||||
),
|
||||
),
|
||||
'messages' => $this->message_values(),
|
||||
'labels' => array(
|
||||
'error' => array(
|
||||
'generic' => __(
|
||||
'Something went wrong. Please try again or choose another payment source.',
|
||||
'paypal-for-woocommerce'
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
if ( $this->style_for_context( 'layout', 'mini-cart' ) !== 'horizontal' ) {
|
||||
unset( $localize['button']['mini_cart_style']['tagline'] );
|
||||
}
|
||||
if ( $this->style_for_context( 'layout', $this->context() ) !== 'horizontal' ) {
|
||||
unset( $localize['button']['style']['tagline'] );
|
||||
}
|
||||
|
||||
$this->request_data->dequeue_nonce_fix();
|
||||
return $localize;
|
||||
}
|
||||
|
||||
/**
|
||||
* If we can find the payer data for a current customer, we will return it.
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
private function payerData(): ?array {
|
||||
|
||||
$customer = WC()->customer;
|
||||
if ( ! is_user_logged_in() || ! is_a( $customer, \WC_Customer::class ) ) {
|
||||
return null;
|
||||
}
|
||||
return $this->payer_factory->from_customer( $customer )->to_array();
|
||||
}
|
||||
|
||||
/**
|
||||
* The JavaScript SDK url to load.
|
||||
*
|
||||
* @return string
|
||||
* @throws \Inpsyde\PayPalCommerce\WcGateway\Exception\NotFoundException If a setting was not found.
|
||||
*/
|
||||
private function url(): string {
|
||||
$params = array(
|
||||
'client-id' => $this->client_id,
|
||||
'currency' => get_woocommerce_currency(),
|
||||
'locale' => get_user_locale(),
|
||||
// ToDo: Update date on releases.
|
||||
'integration-date' => gmdate( 'Y-m-d' ),
|
||||
'components' => implode( ',', $this->components() ),
|
||||
'vault' => ( is_checkout() && $this->dcc_is_enabled() ) || $this->can_save_vault_token() ?
|
||||
'true' : 'false',
|
||||
'commit' => is_checkout() ? 'true' : 'false',
|
||||
'intent' => ( $this->settings->has( 'intent' ) ) ?
|
||||
$this->settings->get( 'intent' ) : 'capture',
|
||||
);
|
||||
if (
|
||||
defined( 'WP_DEBUG' ) && \WP_DEBUG
|
||||
&& WC()->customer && WC()->customer->get_billing_country()
|
||||
) {
|
||||
$params['buyer-country'] = WC()->customer->get_billing_country();
|
||||
}
|
||||
$payee = $this->payee_repository->payee();
|
||||
if ( $payee->merchant_id() ) {
|
||||
$params['merchant-id'] = $payee->merchant_id();
|
||||
}
|
||||
$disable_funding = $this->settings->has( 'disable_funding' ) ?
|
||||
$this->settings->get( 'disable_funding' ) : array();
|
||||
$disable_funding[] = 'venmo';
|
||||
if ( ! is_checkout() ) {
|
||||
$disable_funding[] = 'card';
|
||||
}
|
||||
$params['disable-funding'] = implode( ',', array_unique( $disable_funding ) );
|
||||
$smart_button_url = add_query_arg( $params, 'https://www.paypal.com/sdk/js' );
|
||||
return $smart_button_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* The attributes we need to load for the JS SDK.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function attributes(): array {
|
||||
return array(
|
||||
'data-partner-attribution-id' => $this->bn_code_for_context( $this->context() ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* What BN Code to use in a given context.
|
||||
*
|
||||
* @param string $context The context.
|
||||
* @return string
|
||||
*/
|
||||
private function bn_code_for_context( string $context ): string {
|
||||
|
||||
$codes = $this->bn_codes();
|
||||
return ( isset( $codes[ $context ] ) ) ? $codes[ $context ] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* BN Codes to use.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function bn_codes(): array {
|
||||
|
||||
return array(
|
||||
'checkout' => 'Woo_PPCP',
|
||||
'cart' => 'Woo_PPCP',
|
||||
'mini-cart' => 'Woo_PPCP',
|
||||
'product' => 'Woo_PPCP',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The JS SKD components we need to load.
|
||||
*
|
||||
* @return array
|
||||
* @throws \Inpsyde\PayPalCommerce\WcGateway\Exception\NotFoundException If a setting was not found.
|
||||
*/
|
||||
private function components(): array {
|
||||
$components = array( 'buttons' );
|
||||
if ( $this->messages_apply->for_country() ) {
|
||||
$components[] = 'messages';
|
||||
}
|
||||
if ( $this->dcc_is_enabled() ) {
|
||||
$components[] = 'hosted-fields';
|
||||
}
|
||||
return $components;
|
||||
}
|
||||
|
||||
/**
|
||||
* The current context.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function context(): string {
|
||||
$context = 'mini-cart';
|
||||
if ( is_product() || wc_post_content_has_shortcode( 'product_page' ) ) {
|
||||
$context = 'product';
|
||||
}
|
||||
if ( is_cart() ) {
|
||||
$context = 'cart';
|
||||
}
|
||||
if ( is_checkout() && ! $this->session_handler->order() ) {
|
||||
$context = 'checkout';
|
||||
}
|
||||
return $context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether DCC is enabled or not.
|
||||
*
|
||||
* @return bool
|
||||
* @throws \Inpsyde\PayPalCommerce\WcGateway\Exception\NotFoundException If a setting has not been found.
|
||||
*/
|
||||
private function dcc_is_enabled(): bool {
|
||||
if ( ! $this->dcc_applies->for_country_currency() ) {
|
||||
return false;
|
||||
}
|
||||
$keys = array(
|
||||
'dcc_gateway_enabled' => 'is_checkout',
|
||||
);
|
||||
foreach ( $keys as $key => $callback ) {
|
||||
if ( $this->settings->has( $key ) && $this->settings->get( $key ) && $callback() ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the style for a given indicator in a given context.
|
||||
*
|
||||
* @param string $style The style.
|
||||
* @param string $context The context.
|
||||
*
|
||||
* @return string
|
||||
* @throws \Inpsyde\PayPalCommerce\WcGateway\Exception\NotFoundException When a setting hasn't been found.
|
||||
*/
|
||||
private function style_for_context( string $style, string $context ): string {
|
||||
$defaults = array(
|
||||
'layout' => 'vertical',
|
||||
'size' => 'responsive',
|
||||
'color' => 'gold',
|
||||
'shape' => 'pill',
|
||||
'label' => 'paypal',
|
||||
'tagline' => true,
|
||||
);
|
||||
|
||||
$value = isset( $defaults[ $style ] ) ?
|
||||
$defaults[ $style ] : '';
|
||||
$value = $this->settings->has( 'button_' . $style ) ?
|
||||
$this->settings->get( 'button_' . $style ) : $value;
|
||||
$value = $this->settings->has( 'button_' . $context . '_' . $style ) ?
|
||||
$this->settings->get( 'button_' . $context . '_' . $style ) : $value;
|
||||
|
||||
if ( is_bool( $value ) ) {
|
||||
$value = $value ? 'true' : 'false';
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
/**
|
||||
* The interface for the smart button asset renderer.
|
||||
*
|
||||
* @package Inpsyde\PayPalCommerce\Button\Assets
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Inpsyde\PayPalCommerce\Button\Assets;
|
||||
|
||||
/**
|
||||
* Interface SmartButtonInterface
|
||||
*/
|
||||
interface SmartButtonInterface {
|
||||
|
||||
/**
|
||||
* Renders the necessary HTML.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function render_wrapper(): bool;
|
||||
|
||||
/**
|
||||
* Enqueues the necessary scripts.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function enqueue(): bool;
|
||||
|
||||
/**
|
||||
* Whether the running installation could save vault tokens or not.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function can_save_vault_token(): bool;
|
||||
}
|
159
modules/ppcp-button/src/Endpoint/class-approveorderendpoint.php
Normal file
159
modules/ppcp-button/src/Endpoint/class-approveorderendpoint.php
Normal file
|
@ -0,0 +1,159 @@
|
|||
<?php
|
||||
/**
|
||||
* Endpoint to verify if an order has been approved. An approved order
|
||||
* will be stored in the current session.
|
||||
*
|
||||
* @package Inpsyde\PayPalCommerce\Button\Endpoint
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Inpsyde\PayPalCommerce\Button\Endpoint;
|
||||
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Entity\OrderStatus;
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use Inpsyde\PayPalCommerce\Button\Exception\RuntimeException;
|
||||
use Inpsyde\PayPalCommerce\Button\Helper\ThreeDSecure;
|
||||
use Inpsyde\PayPalCommerce\Session\SessionHandler;
|
||||
|
||||
/**
|
||||
* Class ApproveOrderEndpoint
|
||||
*/
|
||||
class ApproveOrderEndpoint implements EndpointInterface {
|
||||
|
||||
|
||||
public const ENDPOINT = 'ppc-approve-order';
|
||||
|
||||
/**
|
||||
* The request data helper.
|
||||
*
|
||||
* @var RequestData
|
||||
*/
|
||||
private $request_data;
|
||||
|
||||
/**
|
||||
* The session handler.
|
||||
*
|
||||
* @var SessionHandler
|
||||
*/
|
||||
private $session_handler;
|
||||
|
||||
/**
|
||||
* The order endpoint.
|
||||
*
|
||||
* @var OrderEndpoint
|
||||
*/
|
||||
private $api_endpoint;
|
||||
|
||||
/**
|
||||
* The 3d secure helper object.
|
||||
*
|
||||
* @var ThreeDSecure
|
||||
*/
|
||||
private $threed_secure;
|
||||
|
||||
/**
|
||||
* ApproveOrderEndpoint constructor.
|
||||
*
|
||||
* @param RequestData $request_data The request data helper.
|
||||
* @param OrderEndpoint $order_endpoint The order endpoint.
|
||||
* @param SessionHandler $session_handler The session handler.
|
||||
* @param ThreeDSecure $three_d_secure The 3d secure helper object.
|
||||
*/
|
||||
public function __construct(
|
||||
RequestData $request_data,
|
||||
OrderEndpoint $order_endpoint,
|
||||
SessionHandler $session_handler,
|
||||
ThreeDSecure $three_d_secure
|
||||
) {
|
||||
|
||||
$this->request_data = $request_data;
|
||||
$this->api_endpoint = $order_endpoint;
|
||||
$this->session_handler = $session_handler;
|
||||
$this->threed_secure = $three_d_secure;
|
||||
}
|
||||
|
||||
/**
|
||||
* The nonce.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function nonce(): string {
|
||||
return self::ENDPOINT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the request.
|
||||
*
|
||||
* @return bool
|
||||
* @throws RuntimeException When no order was found.
|
||||
*/
|
||||
public function handle_request(): bool {
|
||||
try {
|
||||
$data = $this->request_data->read_request( $this->nonce() );
|
||||
if ( ! isset( $data['order_id'] ) ) {
|
||||
throw new RuntimeException(
|
||||
__( 'No order id given', 'paypal-for-woocommerce' )
|
||||
);
|
||||
}
|
||||
|
||||
$order = $this->api_endpoint->order( $data['order_id'] );
|
||||
if ( ! $order ) {
|
||||
throw new RuntimeException(
|
||||
sprintf(
|
||||
// translators: %s is the id of the order.
|
||||
__( 'Order %s not found.', 'paypal-for-woocommerce' ),
|
||||
$data['order_id']
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ( $order->payment_source() && $order->payment_source()->card() ) {
|
||||
$proceed = $this->threed_secure->proceed_with_order( $order );
|
||||
if ( ThreeDSecure::RETRY === $proceed ) {
|
||||
throw new RuntimeException(
|
||||
__(
|
||||
'Something went wrong. Please try again.',
|
||||
'paypal-for-woocommerce'
|
||||
)
|
||||
);
|
||||
}
|
||||
if ( ThreeDSecure::REJECT === $proceed ) {
|
||||
throw new RuntimeException(
|
||||
__(
|
||||
'Unfortunatly, we can\'t accept your card. Please choose a different payment method.',
|
||||
'paypal-for-woocommerce'
|
||||
)
|
||||
);
|
||||
}
|
||||
$this->session_handler->replace_order( $order );
|
||||
wp_send_json_success( $order );
|
||||
}
|
||||
|
||||
if ( ! $order->status()->is( OrderStatus::APPROVED ) ) {
|
||||
throw new RuntimeException(
|
||||
sprintf(
|
||||
// translators: %s is the id of the order.
|
||||
__( 'Order %s is not approved yet.', 'paypal-for-woocommerce' ),
|
||||
$data['order_id']
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$this->session_handler->replace_order( $order );
|
||||
wp_send_json_success( $order );
|
||||
return true;
|
||||
} catch ( \RuntimeException $error ) {
|
||||
wp_send_json_error(
|
||||
array(
|
||||
'name' => is_a( $error, PayPalApiException::class ) ? $error->name() : '',
|
||||
'message' => $error->getMessage(),
|
||||
'code' => $error->getCode(),
|
||||
'details' => is_a( $error, PayPalApiException::class ) ? $error->details() : array(),
|
||||
)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
289
modules/ppcp-button/src/Endpoint/class-changecartendpoint.php
Normal file
289
modules/ppcp-button/src/Endpoint/class-changecartendpoint.php
Normal file
|
@ -0,0 +1,289 @@
|
|||
<?php
|
||||
/**
|
||||
* Endpoint to update the cart.
|
||||
*
|
||||
* @package Inpsyde\PayPalCommerce\Button\Endpoint
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Inpsyde\PayPalCommerce\Button\Endpoint;
|
||||
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Repository\CartRepository;
|
||||
use Inpsyde\PayPalCommerce\Button\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* Class ChangeCartEndpoint
|
||||
*/
|
||||
class ChangeCartEndpoint implements EndpointInterface {
|
||||
|
||||
|
||||
public const ENDPOINT = 'ppc-change-cart';
|
||||
|
||||
/**
|
||||
* The current cart object.
|
||||
*
|
||||
* @var \WC_Cart
|
||||
*/
|
||||
private $cart;
|
||||
|
||||
/**
|
||||
* The current shipping object.
|
||||
*
|
||||
* @var \WC_Shipping
|
||||
*/
|
||||
private $shipping;
|
||||
|
||||
/**
|
||||
* The request data helper.
|
||||
*
|
||||
* @var RequestData
|
||||
*/
|
||||
private $request_data;
|
||||
|
||||
/**
|
||||
* Contains purchase units based off the current WC cart.
|
||||
*
|
||||
* @var CartRepository
|
||||
*/
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* The product data store.
|
||||
*
|
||||
* @var \WC_Data_Store
|
||||
*/
|
||||
private $product_data_store;
|
||||
|
||||
/**
|
||||
* ChangeCartEndpoint constructor.
|
||||
*
|
||||
* @param \WC_Cart $cart The current WC cart object.
|
||||
* @param \WC_Shipping $shipping The current WC shipping object.
|
||||
* @param RequestData $request_data The request data helper.
|
||||
* @param CartRepository $repository The repository for the current purchase items.
|
||||
* @param \WC_Data_Store $product_data_store The data store for products.
|
||||
*/
|
||||
public function __construct(
|
||||
\WC_Cart $cart,
|
||||
\WC_Shipping $shipping,
|
||||
RequestData $request_data,
|
||||
CartRepository $repository,
|
||||
\WC_Data_Store $product_data_store
|
||||
) {
|
||||
|
||||
$this->cart = $cart;
|
||||
$this->shipping = $shipping;
|
||||
$this->request_data = $request_data;
|
||||
$this->repository = $repository;
|
||||
$this->product_data_store = $product_data_store;
|
||||
}
|
||||
|
||||
/**
|
||||
* The nonce.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function nonce(): string {
|
||||
return self::ENDPOINT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the request.
|
||||
*
|
||||
* @return bool
|
||||
* @throws \Exception On error.
|
||||
*/
|
||||
public function handle_request(): bool {
|
||||
try {
|
||||
return $this->handle_data();
|
||||
} catch ( RuntimeException $error ) {
|
||||
wp_send_json_error(
|
||||
array(
|
||||
'name' => is_a( $error, PayPalApiException::class ) ? $error->name() : '',
|
||||
'message' => $error->getMessage(),
|
||||
'code' => $error->getCode(),
|
||||
'details' => is_a( $error, PayPalApiException::class ) ? $error->details() : array(),
|
||||
)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the request data.
|
||||
*
|
||||
* @return bool
|
||||
* @throws \Exception On error.
|
||||
*/
|
||||
private function handle_data(): bool {
|
||||
$data = $this->request_data->read_request( $this->nonce() );
|
||||
$products = $this->products_from_data( $data );
|
||||
if ( ! $products ) {
|
||||
wp_send_json_error(
|
||||
array(
|
||||
'name' => '',
|
||||
'message' => __(
|
||||
'Necessary fields not defined. Action aborted.',
|
||||
'paypal-for-woocommerce'
|
||||
),
|
||||
'code' => 0,
|
||||
'details' => array(),
|
||||
)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->shipping->reset_shipping();
|
||||
$this->cart->empty_cart( false );
|
||||
$success = true;
|
||||
foreach ( $products as $product ) {
|
||||
$success = $success && ( ! $product['product']->is_type( 'variable' ) ) ?
|
||||
$this->add_product( $product['product'], $product['quantity'] )
|
||||
: $this->add_variable_product(
|
||||
$product['product'],
|
||||
$product['quantity'],
|
||||
$product['variations']
|
||||
);
|
||||
}
|
||||
if ( ! $success ) {
|
||||
$this->handle_error();
|
||||
return $success;
|
||||
}
|
||||
|
||||
wp_send_json_success( $this->generate_purchase_units() );
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles errors.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function handle_error(): bool {
|
||||
|
||||
$message = __(
|
||||
'Something went wrong. Action aborted',
|
||||
'paypal-for-woocommerce'
|
||||
);
|
||||
$errors = wc_get_notices( 'error' );
|
||||
if ( count( $errors ) ) {
|
||||
$message = array_reduce(
|
||||
$errors,
|
||||
static function ( string $add, array $error ): string {
|
||||
return $add . $error['notice'] . ' ';
|
||||
},
|
||||
''
|
||||
);
|
||||
wc_clear_notices();
|
||||
}
|
||||
|
||||
wp_send_json_error(
|
||||
array(
|
||||
'name' => '',
|
||||
'message' => $message,
|
||||
'code' => 0,
|
||||
'details' => array(),
|
||||
)
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns product information from an data array.
|
||||
*
|
||||
* @param array $data The data array.
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
private function products_from_data( array $data ): ?array {
|
||||
|
||||
$products = array();
|
||||
|
||||
if (
|
||||
! isset( $data['products'] )
|
||||
|| ! is_array( $data['products'] )
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
foreach ( $data['products'] as $product ) {
|
||||
if ( ! isset( $product['quantity'] ) || ! isset( $product['id'] ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$wc_product = wc_get_product( (int) $product['id'] );
|
||||
|
||||
if ( ! $wc_product ) {
|
||||
return null;
|
||||
}
|
||||
$products[] = array(
|
||||
'product' => $wc_product,
|
||||
'quantity' => (int) $product['quantity'],
|
||||
'variations' => isset( $product['variations'] ) ? $product['variations'] : null,
|
||||
);
|
||||
}
|
||||
return $products;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a product to the cart.
|
||||
*
|
||||
* @param \WC_Product $product The Product.
|
||||
* @param int $quantity The Quantity.
|
||||
*
|
||||
* @return bool
|
||||
* @throws \Exception When product could not be added.
|
||||
*/
|
||||
private function add_product( \WC_Product $product, int $quantity ): bool {
|
||||
return false !== $this->cart->add_to_cart( $product->get_id(), $quantity );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds variations to the cart.
|
||||
*
|
||||
* @param \WC_Product $product The Product.
|
||||
* @param int $quantity The Quantity.
|
||||
* @param array $post_variations The variations.
|
||||
*
|
||||
* @return bool
|
||||
* @throws \Exception When product could not be added.
|
||||
*/
|
||||
private function add_variable_product(
|
||||
\WC_Product $product,
|
||||
int $quantity,
|
||||
array $post_variations
|
||||
): bool {
|
||||
|
||||
$variations = array();
|
||||
foreach ( $post_variations as $key => $value ) {
|
||||
$variations[ $value['name'] ] = $value['value'];
|
||||
}
|
||||
|
||||
$variation_id = $this->product_data_store->find_matching_product_variation( $product, $variations );
|
||||
|
||||
// ToDo: Check stock status for variation.
|
||||
return false !== $this->cart->add_to_cart(
|
||||
$product->get_id(),
|
||||
$quantity,
|
||||
$variation_id,
|
||||
$variations
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Based on the cart contents, the purchase units are created.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function generate_purchase_units(): array {
|
||||
return array_map(
|
||||
static function ( PurchaseUnit $line_item ): array {
|
||||
return $line_item->to_array();
|
||||
},
|
||||
$this->repository->all()
|
||||
);
|
||||
}
|
||||
}
|
243
modules/ppcp-button/src/Endpoint/class-createorderendpoint.php
Normal file
243
modules/ppcp-button/src/Endpoint/class-createorderendpoint.php
Normal file
|
@ -0,0 +1,243 @@
|
|||
<?php
|
||||
/**
|
||||
* The endpoint to create an PayPal order.
|
||||
*
|
||||
* @package Inpsyde\PayPalCommerce\Button\Endpoint
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Inpsyde\PayPalCommerce\Button\Endpoint;
|
||||
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Entity\Order;
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Entity\PaymentMethod;
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Factory\PayerFactory;
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Repository\CartRepository;
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use Inpsyde\PayPalCommerce\Button\Helper\EarlyOrderHandler;
|
||||
use Inpsyde\PayPalCommerce\Session\SessionHandler;
|
||||
use Inpsyde\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
||||
/**
|
||||
* Class CreateOrderEndpoint
|
||||
*/
|
||||
class CreateOrderEndpoint implements EndpointInterface {
|
||||
|
||||
|
||||
public const ENDPOINT = 'ppc-create-order';
|
||||
|
||||
/**
|
||||
* The request data helper.
|
||||
*
|
||||
* @var RequestData
|
||||
*/
|
||||
private $request_data;
|
||||
|
||||
/**
|
||||
* The cart repository.
|
||||
*
|
||||
* @var CartRepository
|
||||
*/
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* The order endpoint.
|
||||
*
|
||||
* @var OrderEndpoint
|
||||
*/
|
||||
private $api_endpoint;
|
||||
|
||||
/**
|
||||
* The payer factory.
|
||||
*
|
||||
* @var PayerFactory
|
||||
*/
|
||||
private $payer_factory;
|
||||
|
||||
/**
|
||||
* The session handler.
|
||||
*
|
||||
* @var SessionHandler
|
||||
*/
|
||||
private $session_handler;
|
||||
|
||||
/**
|
||||
* The settings.
|
||||
*
|
||||
* @var Settings
|
||||
*/
|
||||
private $settings;
|
||||
|
||||
/**
|
||||
* The early order handler.
|
||||
*
|
||||
* @var EarlyOrderHandler
|
||||
*/
|
||||
private $early_order_handler;
|
||||
|
||||
/**
|
||||
* The current PayPal order in a process.
|
||||
*
|
||||
* @var Order|null
|
||||
*/
|
||||
private $order;
|
||||
|
||||
/**
|
||||
* CreateOrderEndpoint constructor.
|
||||
*
|
||||
* @param RequestData $request_data The RequestData object.
|
||||
* @param CartRepository $repository The CartRepository object.
|
||||
* @param OrderEndpoint $order_endpoint The OrderEndpoint object.
|
||||
* @param PayerFactory $payer_factory The PayerFactory object.
|
||||
* @param SessionHandler $session_handler The SessionHandler object.
|
||||
* @param Settings $settings The Settings object.
|
||||
* @param EarlyOrderHandler $early_order_handler The EarlyOrderHandler object.
|
||||
*/
|
||||
public function __construct(
|
||||
RequestData $request_data,
|
||||
CartRepository $repository,
|
||||
OrderEndpoint $order_endpoint,
|
||||
PayerFactory $payer_factory,
|
||||
SessionHandler $session_handler,
|
||||
Settings $settings,
|
||||
EarlyOrderHandler $early_order_handler
|
||||
) {
|
||||
|
||||
$this->request_data = $request_data;
|
||||
$this->repository = $repository;
|
||||
$this->api_endpoint = $order_endpoint;
|
||||
$this->payer_factory = $payer_factory;
|
||||
$this->session_handler = $session_handler;
|
||||
$this->settings = $settings;
|
||||
$this->early_order_handler = $early_order_handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the nonce.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function nonce(): string {
|
||||
return self::ENDPOINT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the request.
|
||||
*
|
||||
* @return bool
|
||||
* @throws \Inpsyde\PayPalCommerce\WcGateway\Exception\NotFoundException In case a setting was not found.
|
||||
*/
|
||||
public function handle_request(): bool {
|
||||
try {
|
||||
$data = $this->request_data->read_request( $this->nonce() );
|
||||
$purchase_units = $this->repository->all();
|
||||
$payer = null;
|
||||
if ( isset( $data['payer'] ) && $data['payer'] ) {
|
||||
if ( isset( $data['payer']['phone']['phone_number']['national_number'] ) ) {
|
||||
// make sure the phone number contains only numbers and is max 14. chars long.
|
||||
$number = $data['payer']['phone']['phone_number']['national_number'];
|
||||
$number = preg_replace( '/[^0-9]/', '', $number );
|
||||
$number = substr( $number, 0, 14 );
|
||||
$data['payer']['phone']['phone_number']['national_number'] = $number;
|
||||
}
|
||||
$payer = $this->payer_factory->from_paypal_response( json_decode( wp_json_encode( $data['payer'] ) ) );
|
||||
}
|
||||
$bn_code = isset( $data['bn_code'] ) ? (string) $data['bn_code'] : '';
|
||||
if ( $bn_code ) {
|
||||
$this->session_handler->replace_bn_code( $bn_code );
|
||||
$this->api_endpoint->with_bn_code( $bn_code );
|
||||
}
|
||||
$payee_preferred = $this->settings->has( 'payee_preferred' )
|
||||
&& $this->settings->get( 'payee_preferred' ) ?
|
||||
PaymentMethod::PAYEE_PREFERRED_IMMEDIATE_PAYMENT_REQUIRED
|
||||
: PaymentMethod::PAYEE_PREFERRED_UNRESTRICTED;
|
||||
$payment_method = new PaymentMethod( $payee_preferred );
|
||||
$order = $this->api_endpoint->create(
|
||||
$purchase_units,
|
||||
$payer,
|
||||
null,
|
||||
$payment_method
|
||||
);
|
||||
if ( 'checkout' === $data['context'] ) {
|
||||
$this->validateForm( $data['form'], $order );
|
||||
}
|
||||
wp_send_json_success( $order->to_array() );
|
||||
return true;
|
||||
} catch ( \RuntimeException $error ) {
|
||||
wp_send_json_error(
|
||||
array(
|
||||
'name' => is_a( $error, PayPalApiException::class ) ? $error->name() : '',
|
||||
'message' => $error->getMessage(),
|
||||
'code' => $error->getCode(),
|
||||
'details' => is_a( $error, PayPalApiException::class ) ? $error->details() : array(),
|
||||
)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the Request parameter and process the checkout form and validate it.
|
||||
*
|
||||
* @param string $form_values The values of the form.
|
||||
* @param Order $order The Order.
|
||||
*
|
||||
* @throws \Exception On Error.
|
||||
*/
|
||||
private function validateForm( string $form_values, Order $order ) {
|
||||
$this->order = $order;
|
||||
$parsed_values = wp_parse_args( $form_values );
|
||||
$_POST = $parsed_values;
|
||||
$_REQUEST = $parsed_values;
|
||||
|
||||
add_filter(
|
||||
'woocommerce_after_checkout_validation',
|
||||
array(
|
||||
$this,
|
||||
'after_checkout_validation',
|
||||
),
|
||||
10,
|
||||
2
|
||||
);
|
||||
$checkout = \WC()->checkout();
|
||||
$checkout->process_checkout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Once the checkout has been validated we execute this method.
|
||||
*
|
||||
* @param array $data The data.
|
||||
* @param \WP_Error $errors The errors, which occurred.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function after_checkout_validation( array $data, \WP_Error $errors ): array {
|
||||
|
||||
$order = $this->order;
|
||||
if ( ! $errors->errors ) {
|
||||
|
||||
/**
|
||||
* In case we are onboarded and everything is fine with the \WC_Order
|
||||
* we want this order to be created. We will intercept it and leave it
|
||||
* in the "Pending payment" status though, which than later will change
|
||||
* during the "onApprove"-JS callback or the webhook listener.
|
||||
*/
|
||||
if ( ! $this->early_order_handler->should_create_early_order() ) {
|
||||
wp_send_json_success( $order->to_array() );
|
||||
}
|
||||
$this->early_order_handler->register_for_order( $order );
|
||||
return $data;
|
||||
}
|
||||
|
||||
wp_send_json_error(
|
||||
array(
|
||||
'name' => '',
|
||||
'message' => $errors->get_error_message(),
|
||||
'code' => (int) $errors->get_error_code(),
|
||||
'details' => array(),
|
||||
)
|
||||
);
|
||||
return $data;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
/**
|
||||
* The Data Client ID endpoint.
|
||||
*
|
||||
* @package Inpsyde\PayPalCommerce\Button\Endpoint
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Inpsyde\PayPalCommerce\Button\Endpoint;
|
||||
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Endpoint\IdentityToken;
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* Class DataClientIdEndpoint
|
||||
*/
|
||||
class DataClientIdEndpoint implements EndpointInterface {
|
||||
|
||||
|
||||
public const ENDPOINT = 'ppc-data-client-id';
|
||||
|
||||
/**
|
||||
* The Request Data Helper.
|
||||
*
|
||||
* @var RequestData
|
||||
*/
|
||||
private $request_data;
|
||||
|
||||
/**
|
||||
* The Identity Token.
|
||||
*
|
||||
* @var IdentityToken
|
||||
*/
|
||||
private $identity_token;
|
||||
|
||||
/**
|
||||
* DataClientIdEndpoint constructor.
|
||||
*
|
||||
* @param RequestData $request_data The Request Data Helper.
|
||||
* @param IdentityToken $identity_token The Identity Token.
|
||||
*/
|
||||
public function __construct(
|
||||
RequestData $request_data,
|
||||
IdentityToken $identity_token
|
||||
) {
|
||||
|
||||
$this->request_data = $request_data;
|
||||
$this->identity_token = $identity_token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the nonce.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function nonce(): string {
|
||||
return self::ENDPOINT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function handle_request(): bool {
|
||||
try {
|
||||
$this->request_data->read_request( $this->nonce() );
|
||||
$user_id = get_current_user_id();
|
||||
$token = $this->identity_token->generate_for_customer( $user_id );
|
||||
wp_send_json(
|
||||
array(
|
||||
'token' => $token->token(),
|
||||
'expiration' => $token->expiration_timestamp(),
|
||||
'user' => get_current_user_id(),
|
||||
)
|
||||
);
|
||||
return true;
|
||||
} catch ( RuntimeException $error ) {
|
||||
wp_send_json_error(
|
||||
array(
|
||||
'name' => is_a( $error, PayPalApiException::class ) ? $error->name() : '',
|
||||
'message' => $error->getMessage(),
|
||||
'code' => $error->getCode(),
|
||||
'details' => is_a( $error, PayPalApiException::class ) ? $error->details() : array(),
|
||||
)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
30
modules/ppcp-button/src/Endpoint/class-endpointinterface.php
Normal file
30
modules/ppcp-button/src/Endpoint/class-endpointinterface.php
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
/**
|
||||
* The Endpoint interface.
|
||||
*
|
||||
* @package Inpsyde\PayPalCommerce\Button\Endpoint
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Inpsyde\PayPalCommerce\Button\Endpoint;
|
||||
|
||||
/**
|
||||
* Interface EndpointInterface
|
||||
*/
|
||||
interface EndpointInterface {
|
||||
|
||||
/**
|
||||
* Returns the nonce for an endpoint.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function nonce(): string;
|
||||
|
||||
/**
|
||||
* Handles the request for an endpoint.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function handle_request(): bool;
|
||||
}
|
91
modules/ppcp-button/src/Endpoint/class-requestdata.php
Normal file
91
modules/ppcp-button/src/Endpoint/class-requestdata.php
Normal file
|
@ -0,0 +1,91 @@
|
|||
<?php
|
||||
/**
|
||||
* Helper to read request data for the endpoints.
|
||||
*
|
||||
* @package Inpsyde\PayPalCommerce\Button\Endpoint
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Inpsyde\PayPalCommerce\Button\Endpoint;
|
||||
|
||||
use Inpsyde\PayPalCommerce\Button\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* Class RequestData
|
||||
*/
|
||||
class RequestData {
|
||||
|
||||
/**
|
||||
* Enqueues the nonce fix hook.
|
||||
*/
|
||||
public function enqueue_nonce_fix() {
|
||||
add_filter( 'nonce_user_logged_out', array( $this, 'nonce_fix' ), 100 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Dequeues the nonce fix hook.
|
||||
*/
|
||||
public function dequeue_nonce_fix() {
|
||||
remove_filter( 'nonce_user_logged_out', array( $this, 'nonce_fix' ), 100 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the current request.
|
||||
*
|
||||
* @param string $nonce The nonce.
|
||||
*
|
||||
* @return array
|
||||
* @throws RuntimeException When nonce validation fails.
|
||||
*/
|
||||
public function read_request( string $nonce ): array {
|
||||
$stream = file_get_contents( 'php://input' );
|
||||
$json = json_decode( $stream, true );
|
||||
$this->enqueue_nonce_fix();
|
||||
if (
|
||||
! isset( $json['nonce'] )
|
||||
|| ! wp_verify_nonce( $json['nonce'], $nonce )
|
||||
) {
|
||||
remove_filter( 'nonce_user_logged_out', array( $this, 'nonce_fix' ), 100 );
|
||||
throw new RuntimeException(
|
||||
__( 'Could not validate nonce.', 'paypal-for-woocommerce' )
|
||||
);
|
||||
}
|
||||
$this->dequeue_nonce_fix();
|
||||
|
||||
$sanitized = $this->sanitize( $json );
|
||||
return $sanitized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Woocommerce will give you a customer object on your 2nd request. the first page
|
||||
* load will not yet have this customer object, but the ajax request will. Therefore
|
||||
* the nonce validation will fail. this fixes this problem:
|
||||
*
|
||||
* @wp-hook nonce_user_logged_out
|
||||
* @see https://github.com/woocommerce/woocommerce/blob/69e3835041113bee80379c1037e97e26815a699b/includes/class-wc-session-handler.php#L288-L296
|
||||
* @return int
|
||||
*/
|
||||
public function nonce_fix(): int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes the data.
|
||||
*
|
||||
* @param array $assoc_array The data array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function sanitize( array $assoc_array ): array {
|
||||
$data = array();
|
||||
foreach ( (array) $assoc_array as $raw_key => $raw_value ) {
|
||||
if ( ! is_array( $raw_value ) ) {
|
||||
$data[ sanitize_text_field( urldecode( (string) $raw_key ) ) ] = sanitize_text_field( urldecode( (string) $raw_value ) );
|
||||
continue;
|
||||
}
|
||||
$data[ sanitize_text_field( urldecode( (string) $raw_key ) ) ] = $this->sanitize( $raw_value );
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
18
modules/ppcp-button/src/Exception/class-runtimeexception.php
Normal file
18
modules/ppcp-button/src/Exception/class-runtimeexception.php
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
/**
|
||||
* The modules Runtime Exception.
|
||||
*
|
||||
* @package Inpsyde\PayPalCommerce\Button\Exception
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Inpsyde\PayPalCommerce\Button\Exception;
|
||||
|
||||
/**
|
||||
* Class RuntimeException
|
||||
*/
|
||||
class RuntimeException extends \RuntimeException {
|
||||
|
||||
|
||||
}
|
174
modules/ppcp-button/src/Helper/class-earlyorderhandler.php
Normal file
174
modules/ppcp-button/src/Helper/class-earlyorderhandler.php
Normal file
|
@ -0,0 +1,174 @@
|
|||
<?php
|
||||
/**
|
||||
* Handles the Early Order logic, when we need to create the WC_Order by ourselfs.
|
||||
*
|
||||
* @package Inpsyde\PayPalCommerce\Button\Helper
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Inpsyde\PayPalCommerce\Button\Helper;
|
||||
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Entity\Order;
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use Inpsyde\PayPalCommerce\Onboarding\State;
|
||||
use Inpsyde\PayPalCommerce\Session\SessionHandler;
|
||||
use Inpsyde\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use Inpsyde\PayPalCommerce\WcGateway\Processor\OrderProcessor;
|
||||
use Inpsyde\PayPalCommerce\Webhooks\Handler\PrefixTrait;
|
||||
|
||||
/**
|
||||
* Class EarlyOrderHandler
|
||||
*/
|
||||
class EarlyOrderHandler {
|
||||
|
||||
use PrefixTrait;
|
||||
|
||||
/**
|
||||
* The State.
|
||||
*
|
||||
* @var State
|
||||
*/
|
||||
private $state;
|
||||
|
||||
/**
|
||||
* The Order Processor.
|
||||
*
|
||||
* @var OrderProcessor
|
||||
*/
|
||||
private $order_processor;
|
||||
|
||||
/**
|
||||
* The Session Handler.
|
||||
*
|
||||
* @var SessionHandler
|
||||
*/
|
||||
private $session_handler;
|
||||
|
||||
/**
|
||||
* EarlyOrderHandler constructor.
|
||||
*
|
||||
* @param State $state The State.
|
||||
* @param OrderProcessor $order_processor The Order Processor.
|
||||
* @param SessionHandler $session_handler The Session Handler.
|
||||
* @param string $prefix The Prefix.
|
||||
*/
|
||||
public function __construct(
|
||||
State $state,
|
||||
OrderProcessor $order_processor,
|
||||
SessionHandler $session_handler,
|
||||
string $prefix
|
||||
) {
|
||||
|
||||
$this->state = $state;
|
||||
$this->order_processor = $order_processor;
|
||||
$this->session_handler = $session_handler;
|
||||
$this->prefix = $prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether early orders should be created at all.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function should_create_early_order(): bool {
|
||||
return $this->state->current_state() === State::STATE_ONBOARDED;
|
||||
}
|
||||
|
||||
//phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||
|
||||
/**
|
||||
* Tries to determine the current WC Order Id based on the PayPal order
|
||||
* and the current order in session.
|
||||
*
|
||||
* @param int|null $value The initial value.
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function determine_wc_order_id( int $value = null ): ?int {
|
||||
|
||||
if ( ! isset( $_REQUEST['ppcp-resume-order'] ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
$resume_order_id = (int) WC()->session->get( 'order_awaiting_payment' );
|
||||
|
||||
$order = $this->session_handler->order();
|
||||
if ( ! $order ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
$order_id = false;
|
||||
foreach ( $order->purchase_units() as $purchase_unit ) {
|
||||
if ( $purchase_unit->custom_id() === sanitize_text_field( wp_unslash( $_REQUEST['ppcp-resume-order'] ) ) ) {
|
||||
$order_id = (int) $this->sanitize_custom_id( $purchase_unit->custom_id() );
|
||||
}
|
||||
}
|
||||
if ( $order_id === $resume_order_id ) {
|
||||
$value = $order_id;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
//phpcs:enable WordPress.Security.NonceVerification.Recommended
|
||||
|
||||
/**
|
||||
* Registers the necessary checkout actions for a given order.
|
||||
*
|
||||
* @param Order $order The PayPal order.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function register_for_order( Order $order ): bool {
|
||||
|
||||
$success = (bool) add_action(
|
||||
'woocommerce_checkout_order_processed',
|
||||
function ( $order_id ) use ( $order ) {
|
||||
try {
|
||||
$order = $this->configure_session_and_order( (int) $order_id, $order );
|
||||
wp_send_json_success( $order->to_array() );
|
||||
} catch ( \RuntimeException $error ) {
|
||||
wp_send_json_error(
|
||||
array(
|
||||
'name' => is_a( $error, PayPalApiException::class ) ?
|
||||
$error->name() : '',
|
||||
'message' => $error->getMessage(),
|
||||
'code' => $error->getCode(),
|
||||
'details' => is_a( $error, PayPalApiException::class ) ?
|
||||
$error->details() : array(),
|
||||
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the session, so we can pick up the order, once we pass through the checkout.
|
||||
*
|
||||
* @param int $order_id The Woocommerce order id.
|
||||
* @param Order $order The PayPal order.
|
||||
*
|
||||
* @return Order
|
||||
*/
|
||||
public function configure_session_and_order( int $order_id, Order $order ): Order {
|
||||
|
||||
/**
|
||||
* Set the order id in our session in order for
|
||||
* us to resume this order in checkout.
|
||||
*/
|
||||
WC()->session->set( 'order_awaiting_payment', $order_id );
|
||||
|
||||
$wc_order = wc_get_order( $order_id );
|
||||
$wc_order->update_meta_data( PayPalGateway::ORDER_ID_META_KEY, $order->id() );
|
||||
$wc_order->update_meta_data( PayPalGateway::INTENT_META_KEY, $order->intent() );
|
||||
$wc_order->save_meta_data();
|
||||
|
||||
/**
|
||||
* Patch Order so we have the \WC_Order id added.
|
||||
*/
|
||||
return $this->order_processor->patch_order( $wc_order, $order );
|
||||
}
|
||||
}
|
37
modules/ppcp-button/src/Helper/class-messagesapply.php
Normal file
37
modules/ppcp-button/src/Helper/class-messagesapply.php
Normal file
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
/**
|
||||
* Helper class to determine if credit messaging should be displayed.
|
||||
*
|
||||
* @package Inpsyde\PayPalCommerce\Button\Helper
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Inpsyde\PayPalCommerce\Button\Helper;
|
||||
|
||||
/**
|
||||
* Class MessagesApply
|
||||
*/
|
||||
class MessagesApply {
|
||||
|
||||
|
||||
/**
|
||||
* In which countries credit messaging is available.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $countries = array(
|
||||
'US',
|
||||
);
|
||||
|
||||
/**
|
||||
* Determines whether a credit messaging is enabled for the shops location country.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function for_country(): bool {
|
||||
$region = wc_get_base_location();
|
||||
$country = $region['country'];
|
||||
return in_array( $country, $this->countries, true );
|
||||
}
|
||||
}
|
104
modules/ppcp-button/src/Helper/class-threedsecure.php
Normal file
104
modules/ppcp-button/src/Helper/class-threedsecure.php
Normal file
|
@ -0,0 +1,104 @@
|
|||
<?php
|
||||
/**
|
||||
* Helper class to determine how to proceed with an order depending on the 3d secure feedback.
|
||||
*
|
||||
* @package Inpsyde\PayPalCommerce\Button\Helper
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Inpsyde\PayPalCommerce\Button\Helper;
|
||||
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Entity\CardAuthenticationResult as AuthResult;
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Entity\Order;
|
||||
|
||||
/**
|
||||
* Class ThreeDSecure
|
||||
*/
|
||||
class ThreeDSecure {
|
||||
|
||||
|
||||
public const NO_DECISION = 0;
|
||||
public const PROCCEED = 1;
|
||||
public const REJECT = 2;
|
||||
public const RETRY = 3;
|
||||
|
||||
/**
|
||||
* Determine, how we proceed with a given order.
|
||||
*
|
||||
* @link https://developer.paypal.com/docs/business/checkout/add-capabilities/3d-secure/#authenticationresult
|
||||
*
|
||||
* @param Order $order The order for which the decission is needed.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function proceed_with_order( Order $order ): int {
|
||||
if ( ! $order->payment_source() ) {
|
||||
return self::NO_DECISION;
|
||||
}
|
||||
if ( ! $order->payment_source()->card() ) {
|
||||
return self::NO_DECISION;
|
||||
}
|
||||
if ( ! $order->payment_source()->card()->authentication_result() ) {
|
||||
return self::NO_DECISION;
|
||||
}
|
||||
$result = $order->payment_source()->card()->authentication_result();
|
||||
if ( $result->liability_shift() === AuthResult::LIABILITY_SHIFT_POSSIBLE ) {
|
||||
return self::PROCCEED;
|
||||
}
|
||||
|
||||
if ( $result->liability_shift() === AuthResult::LIABILITY_SHIFT_UNKNOWN ) {
|
||||
return self::RETRY;
|
||||
}
|
||||
if ( $result->liability_shift() === AuthResult::LIABILITY_SHIFT_NO ) {
|
||||
return $this->no_liability_shift( $result );
|
||||
}
|
||||
return self::NO_DECISION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines how to proceed depending on the Liability Shift.
|
||||
*
|
||||
* @param AuthResult $result The AuthResult object based on which we make the decision.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function no_liability_shift( AuthResult $result ): int {
|
||||
|
||||
if (
|
||||
$result->enrollment_status() === AuthResult::ENROLLMENT_STATUS_BYPASS
|
||||
&& ! $result->authentication_result()
|
||||
) {
|
||||
return self::PROCCEED;
|
||||
}
|
||||
if (
|
||||
$result->enrollment_status() === AuthResult::ENROLLMENT_STATUS_UNAVAILABLE
|
||||
&& ! $result->authentication_result()
|
||||
) {
|
||||
return self::PROCCEED;
|
||||
}
|
||||
if (
|
||||
$result->enrollment_status() === AuthResult::ENROLLMENT_STATUS_NO
|
||||
&& ! $result->authentication_result()
|
||||
) {
|
||||
return self::PROCCEED;
|
||||
}
|
||||
|
||||
if ( $result->authentication_result() === AuthResult::AUTHENTICATION_RESULT_REJECTED ) {
|
||||
return self::REJECT;
|
||||
}
|
||||
|
||||
if ( $result->authentication_result() === AuthResult::AUTHENTICATION_RESULT_NO ) {
|
||||
return self::REJECT;
|
||||
}
|
||||
|
||||
if ( $result->authentication_result() === AuthResult::AUTHENTICATION_RESULT_UNABLE ) {
|
||||
return self::RETRY;
|
||||
}
|
||||
|
||||
if ( ! $result->authentication_result() ) {
|
||||
return self::RETRY;
|
||||
}
|
||||
return self::NO_DECISION;
|
||||
}
|
||||
}
|
154
modules/ppcp-button/src/class-buttonmodule.php
Normal file
154
modules/ppcp-button/src/class-buttonmodule.php
Normal file
|
@ -0,0 +1,154 @@
|
|||
<?php
|
||||
/**
|
||||
* The button module.
|
||||
*
|
||||
* @package Inpsyde\PayPalCommerce\Button
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Inpsyde\PayPalCommerce\Button;
|
||||
|
||||
use Dhii\Container\ServiceProvider;
|
||||
use Dhii\Modular\Module\ModuleInterface;
|
||||
use Inpsyde\PayPalCommerce\Button\Assets\SmartButtonInterface;
|
||||
use Inpsyde\PayPalCommerce\Button\Endpoint\ApproveOrderEndpoint;
|
||||
use Inpsyde\PayPalCommerce\Button\Endpoint\ChangeCartEndpoint;
|
||||
use Inpsyde\PayPalCommerce\Button\Endpoint\CreateOrderEndpoint;
|
||||
use Inpsyde\PayPalCommerce\Button\Endpoint\DataClientIdEndpoint;
|
||||
use Inpsyde\PayPalCommerce\Button\Helper\EarlyOrderHandler;
|
||||
use Interop\Container\ServiceProviderInterface;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Class ButtonModule
|
||||
*/
|
||||
class ButtonModule implements ModuleInterface {
|
||||
|
||||
|
||||
/**
|
||||
* Sets up the module.
|
||||
*
|
||||
* @return ServiceProviderInterface
|
||||
*/
|
||||
public function setup(): ServiceProviderInterface {
|
||||
return new ServiceProvider(
|
||||
require __DIR__ . '/../services.php',
|
||||
require __DIR__ . '/../extensions.php'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the module.
|
||||
*
|
||||
* @param ContainerInterface $container The Container.
|
||||
*/
|
||||
public function run( ContainerInterface $container ) {
|
||||
|
||||
add_action(
|
||||
'wp',
|
||||
static function () use ( $container ) {
|
||||
if ( is_admin() ) {
|
||||
return;
|
||||
}
|
||||
$smart_button = $container->get( 'button.smart-button' );
|
||||
/**
|
||||
* The Smart Button.
|
||||
*
|
||||
* @var SmartButtonInterface $smart_button
|
||||
*/
|
||||
$smart_button->render_wrapper();
|
||||
}
|
||||
);
|
||||
add_action(
|
||||
'wp_enqueue_scripts',
|
||||
static function () use ( $container ) {
|
||||
|
||||
$smart_button = $container->get( 'button.smart-button' );
|
||||
/**
|
||||
* The Smart Button.
|
||||
*
|
||||
* @var SmartButtonInterface $smart_button
|
||||
*/
|
||||
$smart_button->enqueue();
|
||||
}
|
||||
);
|
||||
|
||||
add_filter(
|
||||
'woocommerce_create_order',
|
||||
static function ( $value ) use ( $container ) {
|
||||
$early_order_handler = $container->get( 'button.helper.early-order-handler' );
|
||||
if ( ! is_null( $value ) ) {
|
||||
$value = (int) $value;
|
||||
}
|
||||
/**
|
||||
* The Early Order Handler
|
||||
*
|
||||
* @var EarlyOrderHandler $early_order_handler
|
||||
*/
|
||||
return $early_order_handler->determine_wc_order_id( $value );
|
||||
}
|
||||
);
|
||||
|
||||
$this->register_ajax_endpoints( $container );
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the Ajax Endpoints.
|
||||
*
|
||||
* @param ContainerInterface $container The Container.
|
||||
*/
|
||||
private function register_ajax_endpoints( ContainerInterface $container ) {
|
||||
add_action(
|
||||
'wc_ajax_' . DataClientIdEndpoint::ENDPOINT,
|
||||
static function () use ( $container ) {
|
||||
$endpoint = $container->get( 'button.endpoint.data-client-id' );
|
||||
/**
|
||||
* The Data Client ID Endpoint.
|
||||
*
|
||||
* @var DataClientIdEndpoint $endpoint
|
||||
*/
|
||||
$endpoint->handle_request();
|
||||
}
|
||||
);
|
||||
|
||||
add_action(
|
||||
'wc_ajax_' . ChangeCartEndpoint::ENDPOINT,
|
||||
static function () use ( $container ) {
|
||||
$endpoint = $container->get( 'button.endpoint.change-cart' );
|
||||
/**
|
||||
* The Change Cart Endpoint.
|
||||
*
|
||||
* @var ChangeCartEndpoint $endpoint
|
||||
*/
|
||||
$endpoint->handle_request();
|
||||
}
|
||||
);
|
||||
|
||||
add_action(
|
||||
'wc_ajax_' . ApproveOrderEndpoint::ENDPOINT,
|
||||
static function () use ( $container ) {
|
||||
$endpoint = $container->get( 'button.endpoint.approve-order' );
|
||||
/**
|
||||
* The Approve Order Endpoint.
|
||||
*
|
||||
* @var ApproveOrderEndpoint $endpoint
|
||||
*/
|
||||
$endpoint->handle_request();
|
||||
}
|
||||
);
|
||||
|
||||
add_action(
|
||||
'wc_ajax_' . CreateOrderEndpoint::ENDPOINT,
|
||||
static function () use ( $container ) {
|
||||
$endpoint = $container->get( 'button.endpoint.create-order' );
|
||||
/**
|
||||
* The Create Order Endpoint.
|
||||
*
|
||||
* @var CreateOrderEndpoint $endpoint
|
||||
*/
|
||||
$endpoint->handle_request();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
36
modules/ppcp-button/webpack.config.js
Normal file
36
modules/ppcp-button/webpack.config.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
const path = require('path');
|
||||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
|
||||
module.exports = {
|
||||
devtool: 'sourcemap',
|
||||
mode: isProduction ? 'production' : 'development',
|
||||
target: 'web',
|
||||
entry: {
|
||||
button: path.resolve('./resources/js/button.js'),
|
||||
hostedfields: path.resolve('./resources/css/hosted-fields.scss'),
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'assets/'),
|
||||
filename: 'js/[name].js',
|
||||
},
|
||||
module: {
|
||||
rules: [{
|
||||
test: /\.js?$/,
|
||||
exclude: /node_modules/,
|
||||
loader: 'babel-loader',
|
||||
},
|
||||
{
|
||||
test: /\.scss$/,
|
||||
exclude: /node_modules/,
|
||||
use: [
|
||||
{
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: 'css/[name].css',
|
||||
}
|
||||
},
|
||||
{loader:'sass-loader'}
|
||||
]
|
||||
}]
|
||||
}
|
||||
};
|
4658
modules/ppcp-button/yarn.lock
Normal file
4658
modules/ppcp-button/yarn.lock
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue