Merge branch 'master' into feature-paypal-button-on-checkout

# Conflicts:
#	modules.local/ppcp-button/assets/js/button.js
#	modules.local/ppcp-button/assets/js/button.js.map
This commit is contained in:
Mészáros Róbert 2020-04-08 16:52:16 +03:00
commit 74b32a1369
16 changed files with 222 additions and 22 deletions

View file

@ -37,13 +37,11 @@ return [
);
},
'api.endpoint.order' => function (ContainerInterface $container) : OrderEndpoint {
$sessionHandler = $container->get('session.handler');
$orderFactory = $container->get('api.factory.order');
$patchCollectionFactory = $container->get('api.factory.patch-collection-factory');
return new OrderEndpoint(
$container->get('api.host'),
$container->get('api.bearer'),
$sessionHandler,
$orderFactory,
$patchCollectionFactory
);

View file

@ -16,20 +16,17 @@ class OrderEndpoint
private $host;
private $bearer;
private $sessionHandler;
private $orderFactory;
private $patchCollectionFactory;
public function __construct(
string $host,
Bearer $bearer,
SessionHandler $sessionHandler,
OrderFactory $orderFactory,
PatchCollectionFactory $patchCollectionFactory
) {
$this->host = $host;
$this->bearer = $bearer;
$this->sessionHandler = $sessionHandler;
$this->orderFactory = $orderFactory;
$this->patchCollectionFactory = $patchCollectionFactory;
}
@ -37,7 +34,6 @@ class OrderEndpoint
public function createForPurchaseUnits(PurchaseUnit ...$items) : Order
{
$bearer = $this->bearer->bearer();
$data = [
'intent' => 'CAPTURE',
'purchase_units' => array_map(
@ -62,7 +58,6 @@ class OrderEndpoint
}
$json = json_decode($response['body']);
$order = $this->orderFactory->fromPayPalResponse($json);
$this->sessionHandler->replaceOrder($order);
return $order;
}
@ -90,7 +85,6 @@ class OrderEndpoint
}
$json = json_decode($response['body']);
$order = $this->orderFactory->fromPayPalResponse($json);
$this->sessionHandler->replaceOrder($order);
return $order;
}
@ -136,7 +130,6 @@ class OrderEndpoint
}
$newOrder = $this->order($orderToUpdate->id());
$this->sessionHandler->replaceOrder($newOrder);
return $newOrder;
}
}

View file

@ -1,4 +1,4 @@
import onApprove from "./onApprove";
class CartConfig {
@ -26,12 +26,9 @@ class CartConfig {
return data.data.id;
});
}
const onApprove = (data, actions) => {
return actions.redirect(this.config.redirect);
}
return {
createOrder,
onApprove,
onApprove:onApprove(this),
onError: (error) => {
this.errorHandler.message(error);
}

View file

@ -1,5 +1,6 @@
import ButtonsToggleListener from "./ButtonsToggleListener";
import Product from "./Product";
import onApprove from "./onApprove";
class SingleProductConfig {
constructor(
@ -29,12 +30,10 @@ class SingleProductConfig {
);
observer.init();
}
const onApprove = (data, actions) => {
return actions.redirect(this.config.redirect);
}
return {
createOrder: this.createOrder(),
onApprove,
onApprove: onApprove(this),
onError: (error) => {
this.errorHandler.message(error);
}
@ -123,5 +122,4 @@ class SingleProductConfig {
return this.formElement.classList.contains('grouped_form');
}
}
export default SingleProductConfig;

View file

@ -0,0 +1,22 @@
const onApprove = (context) => {
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) {
//Todo: Error handling
return;
}
location.href = context.config.redirect;
});
}
}
export default onApprove;

View file

@ -5,6 +5,7 @@ namespace Inpsyde\PayPalCommerce\Button;
use Inpsyde\PayPalCommerce\Button\Assets\SmartButton;
use Dhii\Data\Container\ContainerInterface;
use Inpsyde\PayPalCommerce\Button\Endpoint\ApproveOrderEndpoint;
use Inpsyde\PayPalCommerce\Button\Endpoint\ChangeCartEndpoint;
use Inpsyde\PayPalCommerce\Button\Endpoint\CreateOrderEndpoint;
use Inpsyde\PayPalCommerce\Button\Endpoint\RequestData;
@ -40,4 +41,10 @@ return [
$apiClient = $container->get('api.endpoint.order');
return new CreateOrderEndpoint($requestData, $repository, $apiClient);
},
'button.endpoint.approve-order' => function (ContainerInterface $container) : ApproveOrderEndpoint {
$requestData = $container->get('button.request-data');
$apiClient = $container->get('api.endpoint.order');
$sessionHandler = $container->get('session.handler');
return new ApproveOrderEndpoint($requestData, $apiClient, $sessionHandler);
},
];

View file

@ -3,6 +3,7 @@ declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\Button\Assets;
use Inpsyde\PayPalCommerce\Button\Endpoint\ApproveOrderEndpoint;
use Inpsyde\PayPalCommerce\Button\Endpoint\ChangeCartEndpoint;
use Inpsyde\PayPalCommerce\Button\Endpoint\CreateOrderEndpoint;
@ -48,7 +49,7 @@ class SmartButton
);
add_action(
'woocommerce_widget_shopping_cart_buttons',
function() {
function () {
echo '<span id="ppc-button-minicart"></span>';
},
30
@ -81,6 +82,10 @@ class SmartButton
'endpoint' => home_url(\WC_AJAX::get_endpoint(CreateOrderEndpoint::ENDPOINT)),
'nonce' => wp_create_nonce(CreateOrderEndpoint::nonce()),
],
'approve_order' => [
'endpoint' => home_url(\WC_AJAX::get_endpoint(ApproveOrderEndpoint::ENDPOINT)),
'nonce' => wp_create_nonce(ApproveOrderEndpoint::nonce()),
],
],
'button' => [
'wrapper' => '#ppc-button',

View file

@ -6,6 +6,7 @@ namespace Inpsyde\PayPalCommerce\Button;
use Dhii\Container\ServiceProvider;
use Dhii\Modular\Module\ModuleInterface;
use Inpsyde\PayPalCommerce\Button\Assets\SmartButton;
use Inpsyde\PayPalCommerce\Button\Endpoint\ApproveOrderEndpoint;
use Inpsyde\PayPalCommerce\Button\Endpoint\ChangeCartEndpoint;
use Inpsyde\PayPalCommerce\Button\Endpoint\CreateOrderEndpoint;
use Inpsyde\PayPalCommerce\Button\Endpoint\RequestData;
@ -56,6 +57,17 @@ class ButtonModule implements ModuleInterface
}
);
add_action(
'wc_ajax_' . ApproveOrderEndpoint::ENDPOINT,
function () use ($container) {
$endpoint = $container->get('button.endpoint.approve-order');
/**
* @var ChangeCartEndpoint $endpoint
*/
$endpoint->handleRequest();
}
);
add_action(
'wc_ajax_' . CreateOrderEndpoint::ENDPOINT,
function () use ($container) {

View file

@ -0,0 +1,74 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\Button\Endpoint;
use Inpsyde\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
use Inpsyde\PayPalCommerce\ApiClient\Entity\OrderStatus;
use Inpsyde\PayPalCommerce\Button\Exception\RuntimeException;
use Inpsyde\PayPalCommerce\Session\SessionHandler;
class ApproveOrderEndpoint implements EndpointInterface
{
const ENDPOINT = 'ppc-approve-order';
private $requestData;
private $sessionHandler;
private $apiEndpoint;
public function __construct(
RequestData $requestData,
OrderEndpoint $apiEndpoint,
SessionHandler $sessionHandler
) {
$this->requestData = $requestData;
$this->apiEndpoint = $apiEndpoint;
$this->sessionHandler = $sessionHandler;
}
public static function nonce(): string
{
return self::ENDPOINT . get_current_user_id();
}
public function handleRequest(): bool
{
try {
$data = $this->requestData->readRequest($this->nonce());
if (! isset($data['order_id'])) {
throw new RuntimeException(__("No order id given", "woocommerce-paypal-commerce-gateway"));
}
$order = $this->apiEndpoint->order($data['order_id']);
if (! $order) {
throw new RuntimeException(
sprintf(
// translators: %s is the id of the order.
__('Order %s not found.', 'woocommerce-paypal-commerce-gateway'),
$data['order_id']
)
);
}
if (! $order->status()->is(OrderStatus::APPROVED)) {
throw new RuntimeException(
sprintf(
// translators: %s is the id of the order.
__('Order %s is not approved yet.', 'woocommerce-paypal-commerce-gateway'),
$data['order_id']
)
);
}
$this->sessionHandler->replaceOrder($order);
wp_send_json_success($order);
return true;
} catch (\RuntimeException $error) {
wp_send_json_error($error->getMessage());
return false;
}
}
}

View file

@ -40,7 +40,7 @@ class CreateOrderEndpoint implements EndpointInterface
...$purchaseUnits
);
wp_send_json_success($order->toArray());
return false;
return true;
} catch (\RuntimeException $error) {
wp_send_json_error($error->getMessage());
return false;

View file

@ -4,9 +4,12 @@ declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\Session;
use Dhii\Data\Container\ContainerInterface;
use Inpsyde\PayPalCommerce\Session\Cancellation\CancelController;
use Inpsyde\PayPalCommerce\Session\Cancellation\CancelView;
return [
'session.handler' => function (ContainerInterface $container) : SessionHandler {
if (is_admin()) {
return new SessionHandler();
}
@ -18,4 +21,13 @@ return [
WC()->session->set(SessionHandler::ID, $sessionHandler);
return $sessionHandler;
},
'session.cancellation.view' => function (ContainerInterface $container) : CancelView {
return new CancelView();
},
'session.cancellation.controller' => function (ContainerInterface $container) : CancelController {
return new CancelController(
$container->get('session.handler'),
$container->get('session.cancellation.view')
);
},
];

View file

@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\Session\Cancellation;
use Inpsyde\PayPalCommerce\Session\SessionHandler;
class CancelController
{
private $sessionHandler;
private $view;
public function __construct(
SessionHandler $sessionHandler,
CancelView $view
) {
$this->view = $view;
$this->sessionHandler = $sessionHandler;
}
public function run()
{
$paramName = 'ppcp-cancel';
$nonce = 'ppcp-cancel-' . get_current_user_id();
if (isset($_GET[$paramName]) && // Input var ok.
wp_verify_nonce(
sanitize_text_field(wp_unslash($_GET[$paramName])), // Input var ok.
$nonce
)
) { // Input var ok.
$this->sessionHandler->destroySessionData();
}
if (! $this->sessionHandler->order()) {
return;
}
$url = add_query_arg([$paramName => wp_create_nonce($nonce)], wc_get_checkout_url());
add_action(
'woocommerce_review_order_after_submit',
function () use ($url) {
$this->view->renderSessionCancelation($url);
}
);
}
}

View file

@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\Session\Cancellation;
class CancelView
{
public function renderSessionCancelation(string $url)
{
?>
<p
class="has-text-align-center ppcp-cancel"
>
<a
href="<?php echo esc_url($url); ?>"
><?php
esc_html_e('Cancel', 'woocommerce-paypal-commerce-gateway');
?></a>
</p>
<?php
}
}

View file

@ -22,6 +22,13 @@ class SessionHandler
return $this;
}
public function destroySessionData() : SessionHandler
{
$this->order = null;
$this->storeSession();
return $this;
}
private function storeSession()
{
WC()->session->set(self::ID, $this);

View file

@ -5,6 +5,7 @@ namespace Inpsyde\PayPalCommerce\Session;
use Dhii\Container\ServiceProvider;
use Dhii\Modular\Module\ModuleInterface;
use Inpsyde\PayPalCommerce\Session\Cancellation\CancelController;
use Interop\Container\ServiceProviderInterface;
use Psr\Container\ContainerInterface;
@ -24,7 +25,11 @@ class SessionModule implements ModuleInterface
add_action(
'woocommerce_init',
function () use ($container) {
$container->get('session.handler');
$controller = $container->get('session.cancellation.controller');
/**
* @var CancelController $controller
*/
$controller->run();
}
);
}

View file

@ -101,6 +101,7 @@ class WcGateway extends \WC_Payment_Gateway
$wcOrder->update_status('processing', __('Payment received.', 'woocommerce-paypal-gateway'));
}
$woocommerce->cart->empty_cart();
$this->sessionHandler->destroySessionData();
return [
'result' => 'success',