Des modules ajoutés et mise en page du CSS

This commit is contained in:
2021-01-20 12:37:48 +01:00
parent ae363c7447
commit 9ae46f8c88
409 changed files with 35050 additions and 6579 deletions

View File

@@ -0,0 +1,234 @@
# This is a fix for InnoDB in MySQL >= 4.1.x
# It "suspends judgement" for fkey relationships until are tables are set.
SET FOREIGN_KEY_CHECKS = 0;
-- ---------------------------------------------------------------------
-- paypal_customer
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `paypal_customer`
(
`id` INTEGER NOT NULL,
`paypal_user_id` INTEGER NOT NULL,
`credit_card_id` VARCHAR(40),
`name` VARCHAR(255),
`given_name` VARCHAR(255),
`family_name` VARCHAR(255),
`middle_name` VARCHAR(255),
`picture` VARCHAR(255),
`email_verified` TINYINT,
`gender` VARCHAR(255),
`birthday` VARCHAR(255),
`zoneinfo` VARCHAR(255),
`locale` VARCHAR(255),
`language` VARCHAR(255),
`verified` TINYINT,
`phone_number` VARCHAR(255),
`verified_account` VARCHAR(255),
`account_type` VARCHAR(255),
`age_range` VARCHAR(255),
`payer_id` VARCHAR(255),
`postal_code` VARCHAR(255),
`locality` VARCHAR(255),
`region` VARCHAR(255),
`country` VARCHAR(255),
`street_address` VARCHAR(255),
`created_at` DATETIME,
`updated_at` DATETIME,
PRIMARY KEY (`id`,`paypal_user_id`),
CONSTRAINT `fk_paypal_payer_customer_id`
FOREIGN KEY (`id`)
REFERENCES `customer` (`id`)
ON UPDATE RESTRICT
ON DELETE CASCADE
) ENGINE=InnoDB;
-- ---------------------------------------------------------------------
-- paypal_planified_payment
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `paypal_planified_payment`
(
`id` INTEGER NOT NULL AUTO_INCREMENT,
`frequency` VARCHAR(255) NOT NULL,
`frequency_interval` INTEGER NOT NULL,
`cycle` INTEGER NOT NULL,
`min_amount` DECIMAL(16,6) DEFAULT 0.000000,
`max_amount` DECIMAL(16,6) DEFAULT 0.000000,
`position` INTEGER DEFAULT 0 NOT NULL,
`created_at` DATETIME,
`updated_at` DATETIME,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
-- ---------------------------------------------------------------------
-- paypal_cart
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `paypal_cart`
(
`id` INTEGER NOT NULL,
`credit_card_id` VARCHAR(40),
`planified_payment_id` INTEGER,
`express_payment_id` VARCHAR(255),
`express_payer_id` VARCHAR(255),
`express_token` VARCHAR(255),
`created_at` DATETIME,
`updated_at` DATETIME,
PRIMARY KEY (`id`),
INDEX `FI_paypal_cart_planified_payment_id` (`planified_payment_id`),
CONSTRAINT `fk_paypal_cart_cart_id`
FOREIGN KEY (`id`)
REFERENCES `cart` (`id`)
ON UPDATE RESTRICT
ON DELETE CASCADE,
CONSTRAINT `fk_paypal_cart_planified_payment_id`
FOREIGN KEY (`planified_payment_id`)
REFERENCES `paypal_planified_payment` (`id`)
ON UPDATE RESTRICT
ON DELETE CASCADE
) ENGINE=InnoDB;
-- ---------------------------------------------------------------------
-- paypal_order
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `paypal_order`
(
`id` INTEGER NOT NULL,
`payment_id` VARCHAR(50),
`agreement_id` VARCHAR(255),
`credit_card_id` VARCHAR(40),
`state` VARCHAR(20),
`amount` DECIMAL(16,6) DEFAULT 0.000000,
`description` LONGTEXT,
`payer_id` VARCHAR(255),
`token` VARCHAR(255),
`planified_title` VARCHAR(255) NOT NULL,
`planified_description` LONGTEXT,
`planified_frequency` VARCHAR(255) NOT NULL,
`planified_frequency_interval` INTEGER NOT NULL,
`planified_cycle` INTEGER NOT NULL,
`planified_actual_cycle` INTEGER DEFAULT 0 NOT NULL,
`planified_min_amount` DECIMAL(16,6) DEFAULT 0.000000,
`planified_max_amount` DECIMAL(16,6) DEFAULT 0.000000,
`created_at` DATETIME,
`updated_at` DATETIME,
`version` INTEGER DEFAULT 0,
`version_created_at` DATETIME,
`version_created_by` VARCHAR(100),
PRIMARY KEY (`id`),
CONSTRAINT `fk_paypal_order_order_id`
FOREIGN KEY (`id`)
REFERENCES `order` (`id`)
ON UPDATE RESTRICT
ON DELETE CASCADE
) ENGINE=InnoDB;
-- ---------------------------------------------------------------------
-- paypal_plan
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `paypal_plan`
(
`id` INTEGER NOT NULL AUTO_INCREMENT,
`paypal_order_id` INTEGER NOT NULL,
`plan_id` VARCHAR(255),
`state` VARCHAR(255),
`created_at` DATETIME,
`updated_at` DATETIME,
PRIMARY KEY (`id`),
INDEX `FI_paypal_plan_paypal_order_id` (`paypal_order_id`),
CONSTRAINT `fk_paypal_plan_paypal_order_id`
FOREIGN KEY (`paypal_order_id`)
REFERENCES `paypal_order` (`id`)
ON UPDATE RESTRICT
ON DELETE CASCADE
) ENGINE=InnoDB;
-- ---------------------------------------------------------------------
-- paypal_log
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `paypal_log`
(
`id` INTEGER NOT NULL AUTO_INCREMENT,
`customer_id` INTEGER,
`order_id` INTEGER,
`hook` VARCHAR(255),
`channel` VARCHAR(255),
`level` INTEGER,
`message` LONGTEXT,
`time` INTEGER,
`created_at` DATETIME,
`updated_at` DATETIME,
PRIMARY KEY (`id`),
INDEX `FI_paypal_log_customer_id` (`customer_id`),
INDEX `FI_paypal_log_order_id` (`order_id`),
CONSTRAINT `fk_paypal_log_customer_id`
FOREIGN KEY (`customer_id`)
REFERENCES `customer` (`id`)
ON UPDATE RESTRICT
ON DELETE CASCADE,
CONSTRAINT `fk_paypal_log_order_id`
FOREIGN KEY (`order_id`)
REFERENCES `order` (`id`)
ON UPDATE RESTRICT
ON DELETE CASCADE
) ENGINE=InnoDB;
-- ---------------------------------------------------------------------
-- paypal_planified_payment_i18n
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `paypal_planified_payment_i18n`
(
`id` INTEGER NOT NULL,
`locale` VARCHAR(5) DEFAULT 'en_US' NOT NULL,
`title` VARCHAR(255) NOT NULL,
`description` LONGTEXT,
PRIMARY KEY (`id`,`locale`),
CONSTRAINT `paypal_planified_payment_i18n_FK_1`
FOREIGN KEY (`id`)
REFERENCES `paypal_planified_payment` (`id`)
ON DELETE CASCADE
) ENGINE=InnoDB;
-- ---------------------------------------------------------------------
-- paypal_order_version
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `paypal_order_version`
(
`id` INTEGER NOT NULL,
`payment_id` VARCHAR(50),
`agreement_id` VARCHAR(255),
`credit_card_id` VARCHAR(40),
`state` VARCHAR(20),
`amount` DECIMAL(16,6) DEFAULT 0.000000,
`description` LONGTEXT,
`payer_id` VARCHAR(255),
`token` VARCHAR(255),
`planified_title` VARCHAR(255) NOT NULL,
`planified_description` LONGTEXT,
`planified_frequency` VARCHAR(255) NOT NULL,
`planified_frequency_interval` INTEGER NOT NULL,
`planified_cycle` INTEGER NOT NULL,
`planified_actual_cycle` INTEGER DEFAULT 0 NOT NULL,
`planified_min_amount` DECIMAL(16,6) DEFAULT 0.000000,
`planified_max_amount` DECIMAL(16,6) DEFAULT 0.000000,
`created_at` DATETIME,
`updated_at` DATETIME,
`version` INTEGER DEFAULT 0 NOT NULL,
`version_created_at` DATETIME,
`version_created_by` VARCHAR(100),
`id_version` INTEGER DEFAULT 0,
PRIMARY KEY (`id`,`version`),
CONSTRAINT `paypal_order_version_FK_1`
FOREIGN KEY (`id`)
REFERENCES `paypal_order` (`id`)
ON DELETE CASCADE
) ENGINE=InnoDB;
# This restores the fkey checks, after having unset them earlier
SET FOREIGN_KEY_CHECKS = 1;

View File

@@ -0,0 +1,144 @@
<?xml version="1.0" encoding="UTF-8" ?>
<config xmlns="http://thelia.net/schema/dic/config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://thelia.net/schema/dic/config http://thelia.net/schema/dic/config/thelia-1.0.xsd">
<loops>
<loop name="paypal_order" class="PayPal\Loop\PayPalOrderLoop" />
<loop name="paypal_planified_payment" class="PayPal\Loop\PayPalPlanifiedPaymentLoop" />
<loop name="paypal_log" class="PayPal\Loop\PayPalLogLoop" />
</loops>
<forms>
<form name="paypal_form_configure" class="PayPal\Form\ConfigurationForm" />
<form name="paypal_planified_payment_create_form" class="PayPal\Form\PayPalPlanifiedPaymentCreateForm" />
<form name="paypal_planified_payment_update_form" class="PayPal\Form\PayPalPlanifiedPaymentUpdateForm" />
</forms>
<commands>
<!--
<command class="PayPal\Command\MySuperCommand" />
-->
</commands>
<services>
<!-- **************** -->
<!-- *** Services *** -->
<!-- **************** -->
<service id="paypal_base_service" class="PayPal\Service\Base\PayPalBaseService">
<argument type="service" id="event_dispatcher" />
<argument type="service" id="request_stack" />
<argument type="service" id="router.paypal" />
</service>
<service id="paypal_payment_service" class="PayPal\Service\PayPalPaymentService">
<argument type="service" id="event_dispatcher" />
<argument type="service" id="request_stack" />
<argument type="service" id="router.paypal" />
</service>
<service id="paypal_agreement_service" class="PayPal\Service\PayPalAgreementService">
<argument type="service" id="event_dispatcher" />
<argument type="service" id="request_stack" />
<argument type="service" id="router.paypal" />
</service>
<service id="paypal_customer_service" class="PayPal\Service\PayPalCustomerService">
<argument type="service" id="thelia.securityContext" />
</service>
<service id="paypal_logger_service" class="PayPal\Service\PayPalLoggerService">
</service>
<!-- ********************** -->
<!-- *** EventListeners *** -->
<!-- ********************** -->
<!-- ***** -->
<!-- Order -->
<!-- ***** -->
<service id="paypal.order.order.listener" class="PayPal\EventListeners\PayPalOrderListener">
<tag name="kernel.event_subscriber"/>
</service>
<service id="paypal.cart.listener" class="PayPal\EventListeners\PayPalCartListener">
<tag name="kernel.event_subscriber"/>
</service>
<service id="paypal.order.listener" class="PayPal\EventListeners\OrderListener">
<argument type="service" id="mailer"/>
<argument type="service" id="event_dispatcher"/>
<argument type="service" id="request_stack"/>
<argument type="service" id="paypal_payment_service"/>
<argument type="service" id="paypal_agreement_service"/>
<tag name="kernel.event_subscriber"/>
</service>
<service id="paypal.plan.listener" class="PayPal\EventListeners\PayPalPlanListener">
<tag name="kernel.event_subscriber"/>
</service>
<!-- ******** -->
<!-- Customer -->
<!-- ******** -->
<service id="paypal.customer.customer.listener" class="PayPal\EventListeners\PayPalCustomerListener">
<argument type="service" id="request_stack"/>
<argument type="service" id="event_dispatcher"/>
<tag name="kernel.event_subscriber"/>
</service>
<!-- ********************** -->
<!-- *** Form extension *** -->
<!-- ********************** -->
<service id="paypal.thelia.order.payment.form" class="PayPal\EventListeners\Form\TheliaOrderPaymentForm">
<argument type="service" id="request_stack"/>
<argument type="service" id="event_dispatcher"/>
<tag name="kernel.event_subscriber"/>
</service>
<!-- ************************* -->
<!-- *** Planified Payment *** -->
<!-- ************************* -->
<service id="paypal.planified.payment.listener" class="PayPal\EventListeners\PayPalPlanifiedPaymentListener">
<tag name="kernel.event_subscriber"/>
</service>
</services>
<hooks>
<!-- backOffice -->
<hook id="paypal.back.hook" class="PayPal\Hook\BackHookManager">
<tag name="hook.event_listener" event="module.configuration" type="back" method="onModuleConfigure" />
<tag name="hook.event_listener" event="order-edit.payment-module-bottom" type="back" method="onOrderEditPaymentModuleBottom"/>
<tag name="hook.event_listener" event="order.edit-js" type="back" method="onOrderEditJs"/>
</hook>
<!-- frontOffice -->
<hook id="paypal.front.hook" class="PayPal\Hook\FrontHookManager">
<argument type="service" id="request_stack"/>
<argument type="service" id="service_container" />
<tag name="hook.event_listener" event="login.main-bottom" type="front" method="onLoginMainBottom"/>
<tag name="hook.event_listener" event="order-invoice.payment-extra" type="front" method="onOrderInvoicePaymentExtra"/>
<tag name="hook.event_listener" event="order-invoice.bottom" type="front" method="onOrderInvoiceBottom"/>
<tag name="hook.event_listener" event="order-invoice.javascript-initialization" type="front" method="onOrderInvoiceJavascriptInitialization"/>
<tag name="hook.event_listener" event="order-placed.additional-payment-info" type="front" method="onOrderPlacedAdditionalPaymentInfo"/>
<tag name="hook.event_listener" event="cart.bottom" type="front" method="onCartBottom"/>
<tag name="hook.event_listener" event="order-delivery.form-bottom" type="front" method="onOrderDeliveryFormBottom"/>
<tag name="hook.event_listener" event="order-delivery.after-javascript-include" type="front" method="onOrderAfterJavascriptInclude"/>
</hook>
<!-- pdf -->
<hook id="paypal.pdf.hook" class="PayPal\Hook\PdfHookManager">
<tag name="hook.event_listener" event="invoice.after-payment-module" type="pdf" method="onAfterPaymentModule"/>
</hook>
</hooks>
<!--
<exports>
</exports>
-->
<!--
<imports>
</imports>
-->
</config>

View File

@@ -0,0 +1,195 @@
# This is a fix for InnoDB in MySQL >= 4.1.x
# It "suspends judgement" for fkey relationships until are tables are set.
SET FOREIGN_KEY_CHECKS = 0;
-- ---------------------------------------------------------------------
-- paypal_customer
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `paypal_customer`
(
`id` INTEGER NOT NULL,
`paypal_user_id` INTEGER NOT NULL,
`credit_card_id` VARCHAR(40),
`name` VARCHAR(255),
`given_name` VARCHAR(255),
`family_name` VARCHAR(255),
`middle_name` VARCHAR(255),
`picture` VARCHAR(255),
`email_verified` TINYINT,
`gender` VARCHAR(255),
`birthday` VARCHAR(255),
`zoneinfo` VARCHAR(255),
`locale` VARCHAR(255),
`language` VARCHAR(255),
`verified` TINYINT,
`phone_number` VARCHAR(255),
`verified_account` VARCHAR(255),
`account_type` VARCHAR(255),
`age_range` VARCHAR(255),
`payer_id` VARCHAR(255),
`postal_code` VARCHAR(255),
`locality` VARCHAR(255),
`region` VARCHAR(255),
`country` VARCHAR(255),
`street_address` VARCHAR(255),
`created_at` DATETIME,
`updated_at` DATETIME,
PRIMARY KEY (`id`,`paypal_user_id`),
CONSTRAINT `fk_paypal_payer_customer_id`
FOREIGN KEY (`id`)
REFERENCES `customer` (`id`)
ON UPDATE RESTRICT
ON DELETE CASCADE
) ENGINE=InnoDB;
-- ---------------------------------------------------------------------
-- paypal_planified_payment
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `paypal_planified_payment`
(
`id` INTEGER NOT NULL AUTO_INCREMENT,
`frequency` VARCHAR(255) NOT NULL,
`frequency_interval` INTEGER NOT NULL,
`cycle` INTEGER NOT NULL,
`min_amount` DECIMAL(16,6) DEFAULT 0.000000,
`max_amount` DECIMAL(16,6) DEFAULT 0.000000,
`position` INTEGER DEFAULT 0 NOT NULL,
`created_at` DATETIME,
`updated_at` DATETIME,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
-- ---------------------------------------------------------------------
-- paypal_cart
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `paypal_cart`
(
`id` INTEGER NOT NULL,
`credit_card_id` VARCHAR(40),
`planified_payment_id` INTEGER,
`express_payment_id` VARCHAR(255),
`express_payer_id` VARCHAR(255),
`express_token` VARCHAR(255),
`created_at` DATETIME,
`updated_at` DATETIME,
PRIMARY KEY (`id`),
INDEX `fi_paypal_cart_planified_payment_id` (`planified_payment_id`),
CONSTRAINT `fk_paypal_cart_cart_id`
FOREIGN KEY (`id`)
REFERENCES `cart` (`id`)
ON UPDATE RESTRICT
ON DELETE CASCADE,
CONSTRAINT `fk_paypal_cart_planified_payment_id`
FOREIGN KEY (`planified_payment_id`)
REFERENCES `paypal_planified_payment` (`id`)
ON UPDATE RESTRICT
ON DELETE CASCADE
) ENGINE=InnoDB;
-- ---------------------------------------------------------------------
-- paypal_order
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `paypal_order`
(
`id` INTEGER NOT NULL,
`payment_id` VARCHAR(50),
`agreement_id` VARCHAR(255),
`credit_card_id` VARCHAR(40),
`state` VARCHAR(20),
`amount` DECIMAL(16,6) DEFAULT 0.000000,
`description` LONGTEXT,
`payer_id` VARCHAR(255),
`token` VARCHAR(255),
`planified_title` VARCHAR(255) NOT NULL,
`planified_description` LONGTEXT,
`planified_frequency` VARCHAR(255) NOT NULL,
`planified_frequency_interval` INTEGER NOT NULL,
`planified_cycle` INTEGER NOT NULL,
`planified_actual_cycle` INTEGER DEFAULT 0 NOT NULL,
`planified_min_amount` DECIMAL(16,6) DEFAULT 0.000000,
`planified_max_amount` DECIMAL(16,6) DEFAULT 0.000000,
`created_at` DATETIME,
`updated_at` DATETIME,
PRIMARY KEY (`id`),
CONSTRAINT `fk_paypal_order_order_id`
FOREIGN KEY (`id`)
REFERENCES `order` (`id`)
ON UPDATE RESTRICT
ON DELETE CASCADE
) ENGINE=InnoDB;
-- ---------------------------------------------------------------------
-- paypal_plan
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `paypal_plan`
(
`id` INTEGER NOT NULL AUTO_INCREMENT,
`paypal_order_id` INTEGER NOT NULL,
`plan_id` VARCHAR(255),
`state` VARCHAR(255),
`created_at` DATETIME,
`updated_at` DATETIME,
PRIMARY KEY (`id`),
INDEX `fi_paypal_plan_paypal_order_id` (`paypal_order_id`),
CONSTRAINT `fk_paypal_plan_paypal_order_id`
FOREIGN KEY (`paypal_order_id`)
REFERENCES `paypal_order` (`id`)
ON UPDATE RESTRICT
ON DELETE CASCADE
) ENGINE=InnoDB;
-- ---------------------------------------------------------------------
-- paypal_log
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `paypal_log`
(
`id` INTEGER NOT NULL AUTO_INCREMENT,
`customer_id` INTEGER,
`order_id` INTEGER,
`hook` VARCHAR(255),
`channel` VARCHAR(255),
`level` INTEGER,
`message` LONGTEXT,
`time` INTEGER,
`created_at` DATETIME,
`updated_at` DATETIME,
PRIMARY KEY (`id`),
INDEX `fi_paypal_log_customer_id` (`customer_id`),
INDEX `fi_paypal_log_order_id` (`order_id`),
CONSTRAINT `fk_paypal_log_customer_id`
FOREIGN KEY (`customer_id`)
REFERENCES `customer` (`id`)
ON UPDATE RESTRICT
ON DELETE CASCADE,
CONSTRAINT `fk_paypal_log_order_id`
FOREIGN KEY (`order_id`)
REFERENCES `order` (`id`)
ON UPDATE RESTRICT
ON DELETE CASCADE
) ENGINE=InnoDB;
-- ---------------------------------------------------------------------
-- paypal_planified_payment_i18n
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `paypal_planified_payment_i18n`
(
`id` INTEGER NOT NULL,
`locale` VARCHAR(5) DEFAULT 'en_US' NOT NULL,
`title` VARCHAR(255) NOT NULL,
`description` LONGTEXT,
PRIMARY KEY (`id`,`locale`),
CONSTRAINT `paypal_planified_payment_i18n_fk_c9dfe7`
FOREIGN KEY (`id`)
REFERENCES `paypal_planified_payment` (`id`)
ON DELETE CASCADE
) ENGINE=InnoDB;
# This restores the fkey checks, after having unset them earlier
SET FOREIGN_KEY_CHECKS = 1;

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="http://thelia.net/schema/dic/module"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://thelia.net/schema/dic/module http://thelia.net/schema/dic/module/module-2_2.xsd">
<fullnamespace>PayPal\PayPal</fullnamespace>
<descriptive locale="en_US">
<title>PayPal</title>
<!--
<subtitle></subtitle>
<description></description>
<postscriptum></postscriptum>
-->
</descriptive>
<descriptive locale="fr_FR">
<title>PayPal</title>
</descriptive>
<!-- <logo></logo> -->
<!--<images-folder>images</images-folder>-->
<languages>
<language>en_US</language>
<language>fr_FR</language>
</languages>
<version>4.0.0</version>
<authors>
<author>
<name>gbarral</name>
<email>gbarral@openstudio.fr</email>
</author>
</authors>
<type>classic</type>
<!--
module dependencies
<required>
<module version="&gt;=0.1">Front</module>
<module version="~1.0">HookCart</module>
<module version="&gt;0.2">HookSearch</module>
</required>
-->
<thelia>2.4.0</thelia>
<stability>other</stability>
</module>

View File

@@ -0,0 +1,108 @@
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
<route id="paypal.configure" path="/admin/module/paypal/configure" methods="post">
<default key="_controller">PayPal:Configuration:configure</default>
</route>
<route id="paypal.admin.configuration.log" path="/admin/module/paypal/configure/log" methods="get">
<default key="_controller">PayPal:Configuration:log</default>
</route>
<route id="paypal.admin.configuration.general" path="/admin/module/paypal/configure" methods="post">
<default key="_controller">PayPal:Configuration:configure</default>
</route>
<route id="paypal.admin.configuration.planified" path="/admin/module/paypal/configure/planified" methods="get">
<default key="_controller">PayPal:PayPalPlanifiedPayment:default</default>
</route>
<route id="paypal.admin.configuration.planified.create" path="/admin/module/paypal/configure/planified/create" methods="post">
<default key="_controller">PayPal:PayPalPlanifiedPayment:create</default>
</route>
<route id="paypal.admin.configuration.planified.delete" path="/admin/module/paypal/configure/planified/create/delete" methods="post">
<default key="_controller">PayPal:PayPalPlanifiedPayment:delete</default>
</route>
<route id="paypal.admin.configuration.planified.update" path="/admin/module/paypal/configure/planified/{planifiedPaymentId}" methods="get">
<default key="_controller">PayPal:PayPalPlanifiedPayment:update</default>
<requirement key="planifiedPaymentId">\d+</requirement>
</route>
<route id="paypal.admin.configuration.planified.save" path="/admin/module/paypal/configure/planified/{planifiedPaymentId}" methods="post">
<default key="_controller">PayPal:PayPalPlanifiedPayment:processUpdate</default>
<requirement key="planifiedPaymentId">\d+</requirement>
</route>
<route id="paypal.cancel" path="/module/paypal/cancel/{orderId}" methods="get">
<default key="_controller">PayPal:PayPalResponse:cancel</default>
<requirement key="orderId">\d+</requirement>
</route>
<route id="paypal.ok" path="/module/paypal/ok/{orderId}" methods="get">
<default key="_controller">PayPal:PayPalResponse:ok</default>
<requirement key="orderId">\d+</requirement>
</route>
<route id="paypal.express.checkout" path="/module/paypal/express/checkout">
<default key="_controller">PayPal:PayPalResponse:expressCheckout</default>
</route>
<route id="paypal.express.checkout.ok" path="/module/paypal/express/checkout/ok/{cartId}">
<default key="_controller">PayPal:PayPalResponse:expressCheckoutOk</default>
<requirement key="cartId">\d+</requirement>
</route>
<route id="paypal.express.checkout.ko" path="/module/paypal/express/checkout/ko/{cartId}">
<default key="_controller">PayPal:PayPalResponse:expressCheckoutKo</default>
<requirement key="cartId">\d+</requirement>
</route>
<route id="paypal.invoice.express.checkout" path="/module/paypal/invoice/express/checkout">
<default key="_controller">PayPal:PayPalResponse:invoiceExpressCheckout</default>
</route>
<route id="paypal.invoice.express.checkout.ok" path="/module/paypal/invoice/express/checkout/ok/{cartId}">
<default key="_controller">PayPal:PayPalResponse:invoiceExpressCheckoutOk</default>
<requirement key="cartId">\d+</requirement>
</route>
<route id="paypal.invoice.express.checkout.ko" path="/module/paypal/invoice/express/checkout/ko/{cartId}">
<default key="_controller">PayPal:PayPalResponse:invoiceExpressCheckoutKo</default>
<requirement key="cartId">\d+</requirement>
</route>
<!-- OVERLOAD order management process -->
<route id="order.delivery.process" path="/order/delivery" methods="post">
<default key="_controller">PayPal:PayPalResponse:executeExpressCheckout</default>
<default key="_view">order-delivery</default>
</route>
<route id="paypal.login.ok" path="/module/paypal/login/ok" methods="get">
<default key="_controller">PayPal:PayPalResponse:loginOk</default>
</route>
<route id="paypal.agreement.ok" path="/module/paypal/agreement/ok/{orderId}" methods="get">
<default key="_controller">PayPal:PayPalResponse:agreementOk</default>
<requirement key="orderId">\d+</requirement>
</route>
<route id="paypal.agreement.ko" path="/module/paypal/agreement/ko/{orderId}" methods="get">
<default key="_controller">PayPal:PayPalResponse:agreementKo</default>
<requirement key="orderId">\d+</requirement>
</route>
<route id="paypal.ipn" path="/module/paypal/ipn/{orderId}">
<default key="_controller">PayPal:PayPalResponse:ipn</default>
<requirement key="orderId">\d+</requirement>
</route>
<route id="paypal.webhook.all" path="/module/paypal/webhook/all/events">
<default key="_controller">PayPal:PayPalWebHook:all</default>
</route>
</routes>

View File

@@ -0,0 +1,133 @@
<?xml version="1.0" encoding="UTF-8"?>
<database defaultIdMethod="native" name="thelia"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../../vendor/propel/propel/resources/xsd/database.xsd" >
<table name="paypal_customer" namespace="PayPal\Model">
<column name="id" primaryKey="true" required="true" type="INTEGER" />
<column name="paypal_user_id" primaryKey="true" required="true" type="INTEGER" />
<column name="credit_card_id" size="40" type="VARCHAR" />
<column name="name" size="255" type="VARCHAR" />
<column name="given_name" size="255" type="VARCHAR" />
<column name="family_name" size="255" type="VARCHAR" />
<column name="middle_name" size="255" type="VARCHAR" />
<column name="picture" size="255" type="VARCHAR" />
<column name="email_verified" type="TINYINT" />
<column name="gender" size="255" type="VARCHAR" />
<column name="birthday" size="255" type="VARCHAR" />
<column name="zoneinfo" size="255" type="VARCHAR" />
<column name="locale" size="255" type="VARCHAR" />
<column name="language" size="255" type="VARCHAR" />
<column name="verified" type="TINYINT" />
<column name="phone_number" size="255" type="VARCHAR" />
<column name="verified_account" size="255" type="VARCHAR" />
<column name="account_type" size="255" type="VARCHAR" />
<column name="age_range" size="255" type="VARCHAR" />
<column name="payer_id" size="255" type="VARCHAR" />
<column name="postal_code" size="255" type="VARCHAR" />
<column name="locality" size="255" type="VARCHAR" />
<column name="region" size="255" type="VARCHAR" />
<column name="country" size="255" type="VARCHAR" />
<column name="street_address" size="255" type="VARCHAR" />
<foreign-key foreignTable="customer" name="fk_paypal_payer_customer_id" onDelete="CASCADE" onUpdate="RESTRICT">
<reference foreign="id" local="id" />
</foreign-key>
<behavior name="timestampable" />
</table>
<table name="paypal_planified_payment" namespace="PayPal\Model">
<column name="id" autoIncrement="true" primaryKey="true" required="true" type="INTEGER" />
<column name="title" size="255" type="VARCHAR" required="true" />
<column name="description" type="CLOB" />
<column name="frequency" size="255" type="VARCHAR" required="true" />
<column name="frequency_interval" type="INTEGER" required="true" />
<column name="cycle" type="INTEGER" required="true" />
<column name="min_amount" type="DECIMAL" scale="6" size="16" defaultValue="0.000000" />
<column name="max_amount" type="DECIMAL" scale="6" size="16" defaultValue="0.000000" />
<column name="position" type="INTEGER" required="true" defaultValue="0" />
<behavior name="i18n">
<parameter name="i18n_columns" value="title, description" />
</behavior>
<behavior name="timestampable" />
</table>
<table name="paypal_cart" namespace="PayPal\Model">
<column name="id" primaryKey="true" required="true" type="INTEGER" />
<column name="credit_card_id" size="40" type="VARCHAR" />
<column name="planified_payment_id" type="INTEGER" />
<column name="express_payment_id" size="255" type="VARCHAR" />
<column name="express_payer_id" size="255" type="VARCHAR" />
<column name="express_token" size="255" type="VARCHAR" />
<foreign-key foreignTable="cart" name="fk_paypal_cart_cart_id" onDelete="CASCADE" onUpdate="RESTRICT">
<reference foreign="id" local="id" />
</foreign-key>
<foreign-key foreignTable="paypal_planified_payment" name="fk_paypal_cart_planified_payment_id" onDelete="CASCADE" onUpdate="RESTRICT">
<reference foreign="id" local="planified_payment_id" />
</foreign-key>
<behavior name="timestampable" />
</table>
<table name="paypal_order" namespace="PayPal\Model">
<column name="id" primaryKey="true" required="true" type="INTEGER" />
<column name="payment_id" size="50" type="VARCHAR" />
<column name="agreement_id" size="255" type="VARCHAR" />
<column name="credit_card_id" size="40" type="VARCHAR" />
<column name="state" size="20" type="VARCHAR" />
<column name="amount" type="DECIMAL" scale="6" size="16" defaultValue="0.000000" />
<column name="description" type="CLOB" />
<column name="payer_id" size="255" type="VARCHAR" />
<column name="token" size="255" type="VARCHAR" />
<column name="planified_title" size="255" type="VARCHAR" required="true" />
<column name="planified_description" type="CLOB" />
<column name="planified_frequency" size="255" type="VARCHAR" required="true" />
<column name="planified_frequency_interval" type="INTEGER" required="true" />
<column name="planified_cycle" type="INTEGER" required="true" />
<column name="planified_actual_cycle" type="INTEGER" required="true" defaultValue="0" />
<column name="planified_min_amount" type="DECIMAL" scale="6" size="16" defaultValue="0.000000" />
<column name="planified_max_amount" type="DECIMAL" scale="6" size="16" defaultValue="0.000000" />
<foreign-key foreignTable="order" name="fk_paypal_order_order_id" onDelete="CASCADE" onUpdate="RESTRICT">
<reference foreign="id" local="id" />
</foreign-key>
<behavior name="timestampable" />
</table>
<table name="paypal_plan" namespace="PayPal\Model">
<column name="id" autoIncrement="true" primaryKey="true" required="true" type="INTEGER" />
<column name="paypal_order_id" required="true" type="INTEGER" />
<column name="plan_id" size="255" type="VARCHAR" />
<column name="state" size="255" type="VARCHAR" />
<foreign-key foreignTable="paypal_order" name="fk_paypal_plan_paypal_order_id" onDelete="CASCADE" onUpdate="RESTRICT">
<reference foreign="id" local="paypal_order_id" />
</foreign-key>
<behavior name="timestampable" />
</table>
<table name="paypal_log" namespace="PayPal\Model">
<column name="id" autoIncrement="true" primaryKey="true" required="true" type="INTEGER" />
<column name="customer_id" type="INTEGER" />
<column name="order_id" type="INTEGER" />
<column name="hook" size="255" type="VARCHAR" />
<column name="channel" size="255" type="VARCHAR" />
<column name="level" type="INTEGER" />
<column name="message" type="CLOB" />
<column name="time" type="INTEGER" />
<foreign-key foreignTable="customer" name="fk_paypal_log_customer_id" onDelete="CASCADE" onUpdate="RESTRICT">
<reference foreign="id" local="customer_id" />
</foreign-key>
<foreign-key foreignTable="order" name="fk_paypal_log_order_id" onDelete="CASCADE" onUpdate="RESTRICT">
<reference foreign="id" local="order_id" />
</foreign-key>
<behavior name="timestampable" />
</table>
<external-schema filename="local/config/schema.xml" referenceOnly="true" />
</database>

View File

@@ -0,0 +1,2 @@
# Sqlfile -> Database map
thelia.sql=thelia

View File

@@ -0,0 +1,210 @@
# This is a fix for InnoDB in MySQL >= 4.1.x
# It "suspends judgement" for fkey relationships until are tables are set.
SET FOREIGN_KEY_CHECKS = 0;
-- ---------------------------------------------------------------------
-- paypal_customer
-- ---------------------------------------------------------------------
DROP TABLE IF EXISTS `paypal_customer`;
CREATE TABLE `paypal_customer`
(
`id` INTEGER NOT NULL,
`paypal_user_id` INTEGER NOT NULL,
`credit_card_id` VARCHAR(40),
`name` VARCHAR(255),
`given_name` VARCHAR(255),
`family_name` VARCHAR(255),
`middle_name` VARCHAR(255),
`picture` VARCHAR(255),
`email_verified` TINYINT,
`gender` VARCHAR(255),
`birthday` VARCHAR(255),
`zoneinfo` VARCHAR(255),
`locale` VARCHAR(255),
`language` VARCHAR(255),
`verified` TINYINT,
`phone_number` VARCHAR(255),
`verified_account` VARCHAR(255),
`account_type` VARCHAR(255),
`age_range` VARCHAR(255),
`payer_id` VARCHAR(255),
`postal_code` VARCHAR(255),
`locality` VARCHAR(255),
`region` VARCHAR(255),
`country` VARCHAR(255),
`street_address` VARCHAR(255),
`created_at` DATETIME,
`updated_at` DATETIME,
PRIMARY KEY (`id`,`paypal_user_id`),
CONSTRAINT `fk_paypal_payer_customer_id`
FOREIGN KEY (`id`)
REFERENCES `customer` (`id`)
ON UPDATE RESTRICT
ON DELETE CASCADE
) ENGINE=InnoDB;
-- ---------------------------------------------------------------------
-- paypal_planified_payment
-- ---------------------------------------------------------------------
DROP TABLE IF EXISTS `paypal_planified_payment`;
CREATE TABLE `paypal_planified_payment`
(
`id` INTEGER NOT NULL AUTO_INCREMENT,
`frequency` VARCHAR(255) NOT NULL,
`frequency_interval` INTEGER NOT NULL,
`cycle` INTEGER NOT NULL,
`min_amount` DECIMAL(16,6) DEFAULT 0.000000,
`max_amount` DECIMAL(16,6) DEFAULT 0.000000,
`position` INTEGER DEFAULT 0 NOT NULL,
`created_at` DATETIME,
`updated_at` DATETIME,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
-- ---------------------------------------------------------------------
-- paypal_cart
-- ---------------------------------------------------------------------
DROP TABLE IF EXISTS `paypal_cart`;
CREATE TABLE `paypal_cart`
(
`id` INTEGER NOT NULL,
`credit_card_id` VARCHAR(40),
`planified_payment_id` INTEGER,
`express_payment_id` VARCHAR(255),
`express_payer_id` VARCHAR(255),
`express_token` VARCHAR(255),
`created_at` DATETIME,
`updated_at` DATETIME,
PRIMARY KEY (`id`),
INDEX `fi_paypal_cart_planified_payment_id` (`planified_payment_id`),
CONSTRAINT `fk_paypal_cart_cart_id`
FOREIGN KEY (`id`)
REFERENCES `cart` (`id`)
ON UPDATE RESTRICT
ON DELETE CASCADE,
CONSTRAINT `fk_paypal_cart_planified_payment_id`
FOREIGN KEY (`planified_payment_id`)
REFERENCES `paypal_planified_payment` (`id`)
ON UPDATE RESTRICT
ON DELETE CASCADE
) ENGINE=InnoDB;
-- ---------------------------------------------------------------------
-- paypal_order
-- ---------------------------------------------------------------------
DROP TABLE IF EXISTS `paypal_order`;
CREATE TABLE `paypal_order`
(
`id` INTEGER NOT NULL,
`payment_id` VARCHAR(50),
`agreement_id` VARCHAR(255),
`credit_card_id` VARCHAR(40),
`state` VARCHAR(20),
`amount` DECIMAL(16,6) DEFAULT 0.000000,
`description` LONGTEXT,
`payer_id` VARCHAR(255),
`token` VARCHAR(255),
`planified_title` VARCHAR(255) NOT NULL,
`planified_description` LONGTEXT,
`planified_frequency` VARCHAR(255) NOT NULL,
`planified_frequency_interval` INTEGER NOT NULL,
`planified_cycle` INTEGER NOT NULL,
`planified_actual_cycle` INTEGER DEFAULT 0 NOT NULL,
`planified_min_amount` DECIMAL(16,6) DEFAULT 0.000000,
`planified_max_amount` DECIMAL(16,6) DEFAULT 0.000000,
`created_at` DATETIME,
`updated_at` DATETIME,
PRIMARY KEY (`id`),
CONSTRAINT `fk_paypal_order_order_id`
FOREIGN KEY (`id`)
REFERENCES `order` (`id`)
ON UPDATE RESTRICT
ON DELETE CASCADE
) ENGINE=InnoDB;
-- ---------------------------------------------------------------------
-- paypal_plan
-- ---------------------------------------------------------------------
DROP TABLE IF EXISTS `paypal_plan`;
CREATE TABLE `paypal_plan`
(
`id` INTEGER NOT NULL AUTO_INCREMENT,
`paypal_order_id` INTEGER NOT NULL,
`plan_id` VARCHAR(255),
`state` VARCHAR(255),
`created_at` DATETIME,
`updated_at` DATETIME,
PRIMARY KEY (`id`),
INDEX `fi_paypal_plan_paypal_order_id` (`paypal_order_id`),
CONSTRAINT `fk_paypal_plan_paypal_order_id`
FOREIGN KEY (`paypal_order_id`)
REFERENCES `paypal_order` (`id`)
ON UPDATE RESTRICT
ON DELETE CASCADE
) ENGINE=InnoDB;
-- ---------------------------------------------------------------------
-- paypal_log
-- ---------------------------------------------------------------------
DROP TABLE IF EXISTS `paypal_log`;
CREATE TABLE `paypal_log`
(
`id` INTEGER NOT NULL AUTO_INCREMENT,
`customer_id` INTEGER,
`order_id` INTEGER,
`hook` VARCHAR(255),
`channel` VARCHAR(255),
`level` INTEGER,
`message` LONGTEXT,
`time` INTEGER,
`created_at` DATETIME,
`updated_at` DATETIME,
PRIMARY KEY (`id`),
INDEX `fi_paypal_log_customer_id` (`customer_id`),
INDEX `fi_paypal_log_order_id` (`order_id`),
CONSTRAINT `fk_paypal_log_customer_id`
FOREIGN KEY (`customer_id`)
REFERENCES `customer` (`id`)
ON UPDATE RESTRICT
ON DELETE CASCADE,
CONSTRAINT `fk_paypal_log_order_id`
FOREIGN KEY (`order_id`)
REFERENCES `order` (`id`)
ON UPDATE RESTRICT
ON DELETE CASCADE
) ENGINE=InnoDB;
-- ---------------------------------------------------------------------
-- paypal_planified_payment_i18n
-- ---------------------------------------------------------------------
DROP TABLE IF EXISTS `paypal_planified_payment_i18n`;
CREATE TABLE `paypal_planified_payment_i18n`
(
`id` INTEGER NOT NULL,
`locale` VARCHAR(5) DEFAULT 'en_US' NOT NULL,
`title` VARCHAR(255) NOT NULL,
`description` LONGTEXT,
PRIMARY KEY (`id`,`locale`),
CONSTRAINT `paypal_planified_payment_i18n_fk_c9dfe7`
FOREIGN KEY (`id`)
REFERENCES `paypal_planified_payment` (`id`)
ON DELETE CASCADE
) ENGINE=InnoDB;
# This restores the fkey checks, after having unset them earlier
SET FOREIGN_KEY_CHECKS = 1;

View File

@@ -0,0 +1,113 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace PayPal\Controller;
use PayPal\Form\ConfigurationForm;
use PayPal\PayPal;
use Thelia\Controller\Admin\BaseAdminController;
use Thelia\Core\Security\AccessManager;
use Thelia\Core\Security\Resource\AdminResources;
use Thelia\Core\Thelia;
use Thelia\Form\Exception\FormValidationException;
use Thelia\Tools\URL;
use Thelia\Tools\Version\Version;
/**
* Class ConfigurePaypal
* @package Paypal\Controller
*/
class ConfigurationController extends BaseAdminController
{
/*
* Checks paypal.configure || paypal.configure.sandbox form and save config into json file
*/
/**
* @return mixed|\Symfony\Component\HttpFoundation\Response|\Thelia\Core\HttpFoundation\Response
*/
public function configureAction()
{
if (null !== $response = $this->checkAuth(AdminResources::MODULE, 'Paypal', AccessManager::UPDATE)) {
return $response;
}
$configurationForm = $this->createForm(ConfigurationForm::FORM_NAME);
try {
$form = $this->validateForm($configurationForm, "POST");
// Get the form field values
$data = $form->getData();
foreach ($data as $name => $value) {
if (is_array($value)) {
$value = implode(';', $value);
}
Paypal::setConfigValue($name, $value);
}
$this->adminLogAppend(
"paypal.configuration.message",
AccessManager::UPDATE,
sprintf("Paypal configuration updated")
);
if ($this->getRequest()->get('save_mode') == 'stay') {
// If we have to stay on the same page, redisplay the configuration page/
$url = '/admin/module/Paypal';
} else {
// If we have to close the page, go back to the module back-office page.
$url = '/admin/modules';
}
return $this->generateRedirect(URL::getInstance()->absoluteUrl($url));
} catch (FormValidationException $ex) {
$error_msg = $this->createStandardFormValidationErrorMessage($ex);
} catch (\Exception $ex) {
$error_msg = $ex->getMessage();
}
$this->setupFormErrorContext(
$this->getTranslator()->trans("Paypal configuration", [], PayPal::DOMAIN_NAME),
$error_msg,
$configurationForm,
$ex
);
// Before 2.2, the errored form is not stored in session
if (Version::test(Thelia::THELIA_VERSION, '2.2', false, "<")) {
return $this->render('module-configure', [ 'module_code' => PayPal::getModuleCode()]);
} else {
return $this->generateRedirect(URL::getInstance()->absoluteUrl('/admin/module/PayPal'));
}
}
/**
* @return \Thelia\Core\HttpFoundation\Response
*/
public function logAction()
{
return $this->render('paypal/paypal-log');
}
}

View File

@@ -0,0 +1,315 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace PayPal\Controller;
use PayPal\Event\PayPalEvents;
use PayPal\Event\PayPalPlanifiedPaymentEvent;
use PayPal\Form\PayPalFormFields;
use PayPal\Form\PayPalPlanifiedPaymentCreateForm;
use PayPal\Form\PayPalPlanifiedPaymentUpdateForm;
use PayPal\Model\PaypalPlanifiedPayment;
use PayPal\Model\PaypalPlanifiedPaymentQuery;
use PayPal\PayPal;
use Symfony\Component\HttpFoundation\Response;
use Thelia\Controller\Admin\AbstractCrudController;
use Thelia\Core\Security\AccessManager;
/**
* Class PayPalPlanifiedPaymentController
* @package PayPal\Controller
*/
class PayPalPlanifiedPaymentController extends AbstractCrudController
{
/** @var string */
protected $currentRouter = PayPal::ROUTER;
/**
* PayPalPlanifiedPaymentController constructor.
*/
public function __construct()
{
parent::__construct(
'team',
'id',
'order',
'paypal.back.planified.payment',
PayPalEvents::PAYPAL_PLANIFIED_PAYMENT_CREATE,
PayPalEvents::PAYPAL_PLANIFIED_PAYMENT_UPDATE,
PayPalEvents::PAYPAL_PLANIFIED_PAYMENT_DELETE
);
}
/**
* The default action is displaying the list.
*
* @return Response
*/
public function defaultAction()
{
// Check current user authorization
if (null !== $response = $this->checkAuth($this->resourceCode, $this->getModuleCode(), AccessManager::VIEW)) {
return $response;
}
return $this->renderList();
}
/**
* Return the creation form for this object
* @return PayPalPlanifiedPaymentCreateForm
*/
protected function getCreationForm()
{
return $this->createForm(PayPalPlanifiedPaymentCreateForm::FORM_NAME);
}
/**
* Return the update form for this object
* @return PayPalPlanifiedPaymentUpdateForm
*/
protected function getUpdateForm()
{
return $this->createForm(PayPalPlanifiedPaymentUpdateForm::FORM_NAME);
}
/**
* Hydrate the update form for this object, before passing it to the update template
*
* @param PaypalPlanifiedPayment $object
* @return PayPalPlanifiedPaymentUpdateForm
*/
protected function hydrateObjectForm($object)
{
/** @var \Thelia\Model\Lang $lang */
$lang = $this->getRequest()->getSession()->get('thelia.current.lang');
$object->getTranslation($lang->getLocale());
$data = [
PayPalFormFields::FIELD_PP_ID => $object->getId(),
PayPalFormFields::FIELD_PP_TITLE => $object->getTitle(),
PayPalFormFields::FIELD_PP_DESCRIPTION => $object->getDescription(),
PayPalFormFields::FIELD_PP_FREQUENCY => $object->getFrequency(),
PayPalFormFields::FIELD_PP_FREQUENCY_INTERVAL => $object->getFrequencyInterval(),
PayPalFormFields::FIELD_PP_CYCLE => $object->getCycle(),
PayPalFormFields::FIELD_PP_MIN_AMOUNT => $object->getMinAmount(),
PayPalFormFields::FIELD_PP_MAX_AMOUNT => $object->getMaxAmount(),
PayPalFormFields::FIELD_PP_POSITION => $object->getPosition()
];
return $this->createForm(PayPalPlanifiedPaymentUpdateForm::FORM_NAME, 'form', $data);
}
/**
* Creates the creation event with the provided form data
*
* @param mixed $formData
* @return PayPalPlanifiedPaymentEvent
*/
protected function getCreationEvent($formData)
{
$planifiedPayment = new PaypalPlanifiedPayment();
$planifiedPayment = $this->fillObjectWithDataForm($planifiedPayment, $formData);
$planifiedPaymentEvent = new PayPalPlanifiedPaymentEvent($planifiedPayment);
return $planifiedPaymentEvent;
}
/**
* Creates the update event with the provided form data
*
* @param mixed $formData
* @return PayPalPlanifiedPaymentEvent
*/
protected function getUpdateEvent($formData)
{
if (null === $planifiedPayment = PaypalPlanifiedPaymentQuery::create()->findOneById($formData[PayPalFormFields::FIELD_PP_ID])) {
throw new \InvalidArgumentException(
$this->getTranslator()->trans(
'Invalid planified payment id : %id',
['%id' => $formData[PayPalFormFields::FIELD_PP_ID]],
PayPal::DOMAIN_NAME
)
);
}
$planifiedPayment = $this->fillObjectWithDataForm($planifiedPayment, $formData);
$planifiedPaymentEvent = new PayPalPlanifiedPaymentEvent($planifiedPayment);
return $planifiedPaymentEvent;
}
/**
* @param PaypalPlanifiedPayment $planifiedPayment
* @param $formData
* @return PaypalPlanifiedPayment
*/
protected function fillObjectWithDataForm(PaypalPlanifiedPayment $planifiedPayment, $formData)
{
$planifiedPayment
->setFrequency($formData[PayPalFormFields::FIELD_PP_FREQUENCY])
->setFrequencyInterval($formData[PayPalFormFields::FIELD_PP_FREQUENCY_INTERVAL])
->setCycle($formData[PayPalFormFields::FIELD_PP_CYCLE])
->setMinAmount($formData[PayPalFormFields::FIELD_PP_MIN_AMOUNT])
->setMaxAmount($formData[PayPalFormFields::FIELD_PP_MAX_AMOUNT])
->setLocale($formData[PayPalFormFields::FIELD_PP_LOCALE])
->setTitle($formData[PayPalFormFields::FIELD_PP_TITLE])
->setDescription($formData[PayPalFormFields::FIELD_PP_DESCRIPTION])
;
return $planifiedPayment;
}
/**
* Creates the delete event with the provided form data
* @return PayPalPlanifiedPaymentEvent
*/
protected function getDeleteEvent()
{
return new PayPalPlanifiedPaymentEvent(
$this->getExistingObject()
);
}
/**
* Return true if the event contains the object, e.g. the action has updated the object in the event.
*
* @param PayPalPlanifiedPaymentEvent $event
* @return bool
*/
protected function eventContainsObject($event)
{
return $event->getPayPalPlanifiedPayment() ? true : false;
}
/**
* Get the created object from an event.
* @param PayPalPlanifiedPaymentEvent $event
* @return PaypalPlanifiedPayment
*/
protected function getObjectFromEvent($event)
{
return $event->getPayPalPlanifiedPayment();
}
/**
* Load an existing object from the database
* @return PaypalPlanifiedPayment
*/
protected function getExistingObject()
{
if (null === $planifiedPayment = PaypalPlanifiedPaymentQuery::create()->findOneById((int)$this->getRequest()->get('planifiedPaymentId'))) {
throw new \InvalidArgumentException(
$this->getTranslator()->trans('Invalid planified payment id : %id',
['%id' => (int)$this->getRequest()->get('planifiedPaymentId')], PayPal::DOMAIN_NAME)
);
}
return $planifiedPayment;
}
/**
* Returns the object label form the object event (name, title, etc.)
*
* @param PaypalPlanifiedPayment $object
* @return string
*/
protected function getObjectLabel($object)
{
return $object->getTitle();
}
/**
* Returns the object ID from the object
*
* @param PaypalPlanifiedPayment $object
* @return int
*/
protected function getObjectId($object)
{
return $object->getId();
}
/**
* Render the main list template
*
* @param mixed $currentOrder , if any, null otherwise.
* @return Response
*/
protected function renderListTemplate($currentOrder)
{
$this->getListOrderFromSession('planified_payment', 'order', 'manual');
return $this->render(
'paypal/planified-payment',
[
'order' => $currentOrder,
'selected_menu' => 'planified'
]
);
}
/**
* Render the edition template
* @return Response
*/
protected function renderEditionTemplate()
{
return $this->render('paypal/planified-payment-edit', $this->getEditionArguments());
}
/**
* Must return a RedirectResponse instance
* @return Response
*/
protected function redirectToEditionTemplate()
{
return $this->generateRedirectFromRoute(
'paypal.admin.configuration.planified.update',
[],
$this->getEditionArguments()
);
}
/**
* Must return a RedirectResponse instance
* @return Response
*/
protected function redirectToListTemplate()
{
return $this->generateRedirectFromRoute('paypal.admin.configuration.planified');
}
/**
* @return array
*/
private function getEditionArguments()
{
return [
'planifiedPaymentId' => (int)$this->getRequest()->get('planifiedPaymentId')
];
}
}

View File

@@ -0,0 +1,936 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace PayPal\Controller;
use Front\Controller\OrderController;
use Monolog\Logger;
use PayPal\Api\Details;
use PayPal\Api\PayerInfo;
use PayPal\Event\PayPalCartEvent;
use PayPal\Event\PayPalCustomerEvent;
use PayPal\Event\PayPalEvents;
use PayPal\Event\PayPalOrderEvent;
use PayPal\Exception\PayPalConnectionException;
use PayPal\Model\PaypalCart;
use PayPal\Model\PaypalCartQuery;
use PayPal\Model\PaypalCustomer;
use PayPal\Model\PaypalCustomerQuery;
use PayPal\Model\PaypalOrder;
use PayPal\Model\PaypalOrderQuery;
use PayPal\PayPal;
use PayPal\Service\PayPalAgreementService;
use PayPal\Service\PayPalCustomerService;
use PayPal\Service\PayPalLoggerService;
use PayPal\Service\PayPalPaymentService;
use Propel\Runtime\Propel;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Router;
use Thelia\Core\Event\Address\AddressCreateOrUpdateEvent;
use Thelia\Core\Event\Customer\CustomerCreateOrUpdateEvent;
use Thelia\Core\Event\Customer\CustomerLoginEvent;
use Thelia\Core\Event\Delivery\DeliveryPostageEvent;
use Thelia\Core\Event\Order\OrderEvent;
use Thelia\Core\Event\Order\OrderManualEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Core\Translation\Translator;
use Thelia\Model\AddressQuery;
use Thelia\Model\CartQuery;
use Thelia\Model\Country;
use Thelia\Model\CountryQuery;
use Thelia\Model\CustomerQuery;
use Thelia\Model\CustomerTitleQuery;
use Thelia\Model\ModuleQuery;
use Thelia\Model\Order;
use Thelia\Model\OrderQuery;
use Thelia\Model\OrderStatusQuery;
use Thelia\Module\Exception\DeliveryException;
use Thelia\Tools\URL;
/**
* Class PayPalResponseController
* @package PayPal\Controller
*/
class PayPalResponseController extends OrderController
{
/**
* @param $orderId
*/
public function cancelAction($orderId)
{
if (null !== $order = OrderQuery::create()->findOneById($orderId)) {
$event = new OrderEvent($order);
$event->setStatus(OrderStatusQuery::getCancelledStatus()->getId());
$this->dispatch(TheliaEvents::ORDER_UPDATE_STATUS, $event);
}
}
/**
* @param $orderId
* @return RedirectResponse
*/
public function okAction($orderId)
{
$con = Propel::getConnection();
$con->beginTransaction();
try {
$payerId = $this->getRequest()->query->get('PayerID');
$token = $this->getRequest()->query->get('token');
$payPalOrder = PaypalOrderQuery::create()->findOneById($orderId);
if (null !== $payPalOrder && null !== $payerId) {
$response = $this->executePayment($payPalOrder, $payPalOrder->getPaymentId(), $payerId, $token);
} else {
$con->rollBack();
$message = Translator::getInstance()->trans(
'Method okAction => One of this parameter is invalid : $payerId = %payer_id, $orderId = %order_id',
[
'%payer_id' => $payerId,
'%order_id' => $orderId
],
PayPal::DOMAIN_NAME
);
PayPalLoggerService::log(
$message,
[
'order_id' => $orderId
],
Logger::CRITICAL
);
$response = $this->getPaymentFailurePageUrl($orderId, $message);
}
} catch (PayPalConnectionException $e) {
$message = sprintf('url : %s. data : %s. message : %s', $e->getUrl(), $e->getData(), $e->getMessage());
PayPalLoggerService::log(
$message,
[
'order_id' => $orderId
],
Logger::CRITICAL
);
$response = $this->getPaymentFailurePageUrl($orderId, $e->getMessage());
} catch (\Exception $e) {
PayPalLoggerService::log(
$e->getMessage(),
[
'order_id' => $orderId
],
Logger::CRITICAL
);
$response = $this->getPaymentFailurePageUrl($orderId, $e->getMessage());
}
$con->commit();
return $response;
}
/**
* @param string $routeId
* @return RedirectResponse
*/
public function expressCheckoutAction($routeId = 'cart.view', $fromCartView = true)
{
$session = $this->getRequest()->getSession();
$cart = $session->getSessionCart($this->getDispatcher());
if (null !== $cart) {
/** @var PayPalPaymentService $payPalService */
$payPalService = $this->getContainer()->get(PayPal::PAYPAL_PAYMENT_SERVICE_ID);
$payment = $payPalService->makePaymentFromCart(
$cart,
null,
false,
$fromCartView
);
$response = new RedirectResponse($payment->getApprovalLink());
return $response;
}
return $this->getUrlFromRouteId('cart.view');
}
public function invoiceExpressCheckoutAction()
{
return $this->expressCheckoutAction('order.invoice', false);
}
/**
* @param int $cartId
* @return RedirectResponse
* @throws PayPalConnectionException
* @throws \Exception
*/
public function invoiceExpressCheckoutOkAction($cartId)
{
$con = Propel::getConnection();
$con->beginTransaction();
try {
$this->fillCartWithExpressCheckout();
$response = $this->executeExpressCheckoutAction(false);
} catch (PayPalConnectionException $e) {
$con->rollBack();
$message = sprintf('url : %s. data : %s. message : %s', $e->getUrl(), $e->getData(), $e->getMessage());
$customerId = null;
if (isset($customer)) {
$customerId = $customer->getId();
}
PayPalLoggerService::log(
$message,
[
'customer_id' => $customerId
],
Logger::CRITICAL
);
throw $e;
} catch(\Exception $e) {
$con->rollBack();
$customerId = null;
if (isset($customer)) {
$customerId = $customer->getId();
}
PayPalLoggerService::log(
$e->getMessage(),
[
'customer_id' => $customerId
],
Logger::CRITICAL
);
throw $e;
}
$con->commit();
return $response;
}
public function invoiceExpressCheckoutKoAction($cartId)
{
return $this->getUrlFromRouteId('order.invoice');
}
/**
* @return RedirectResponse
* @throws PayPalConnectionException
* @throws \Exception
*/
public function expressCheckoutOkAction()
{
$con = Propel::getConnection();
$con->beginTransaction();
try {
$this->fillCartWithExpressCheckout();
$response = $this->getUrlFromRouteId('order.delivery');
} catch (PayPalConnectionException $e) {
$con->rollBack();
$message = sprintf('url : %s. data : %s. message : %s', $e->getUrl(), $e->getData(), $e->getMessage());
$customerId = null;
if (isset($customer)) {
$customerId = $customer->getId();
}
PayPalLoggerService::log(
$message,
[
'customer_id' => $customerId
],
Logger::CRITICAL
);
throw $e;
} catch(\Exception $e) {
$con->rollBack();
$customerId = null;
if (isset($customer)) {
$customerId = $customer->getId();
}
PayPalLoggerService::log(
$e->getMessage(),
[
'customer_id' => $customerId
],
Logger::CRITICAL
);
throw $e;
}
$con->commit();
return $response;
}
/**
* @return RedirectResponse|\Symfony\Component\HttpFoundation\Response
*/
public function executeExpressCheckoutAction($fromCartView = true)
{
if (null === $responseParent = parent::deliver()) {
if ($fromCartView) {
return $responseParent;
}
}
$con = Propel::getConnection();
$con->beginTransaction();
try {
$session = $this->getRequest()->getSession();
$cart = $session->getSessionCart($this->getDispatcher());
if (null === $payPalCart = PaypalCartQuery::create()->findOneById($cart->getId())) {
$con->rollBack();
return $responseParent;
}
if (null === $payPalCart->getExpressPaymentId() || null === $payPalCart->getExpressPayerId() || null === $payPalCart->getExpressToken()) {
$con->rollBack();
return $responseParent;
}
/** @var PayPalPaymentService $payPalPaymentService */
$payPalPaymentService = $this->container->get(PayPal::PAYPAL_PAYMENT_SERVICE_ID);
$payment = $payPalPaymentService->getPaymentDetails($payPalCart->getExpressPaymentId());
$payerInfo = $payment->getPayer()->getPayerInfo();
//Check if invoice adresse already exist
if (null === $payerInfo->getBillingAddress()) {
$line1 = $payerInfo->getShippingAddress()->getLine1();
$zipCode = $payerInfo->getShippingAddress()->getPostalCode();
} else {
$line1 = $payerInfo->getBillingAddress()->getLine1();
$zipCode = $payerInfo->getBillingAddress()->getPostalCode();
}
/** @var \Thelia\Model\Address $invoiceAddress */
if (null === $invoiceAddress = AddressQuery::create()
->filterByCustomerId($cart->getCustomerId())
->filterByIsDefault(0)
->filterByAddress1($line1)
->filterByZipcode($zipCode)
->findOne()) {
$event = $this->createAddressEvent($payerInfo);
$event->setCustomer($cart->getCustomer());
$this->dispatch(TheliaEvents::ADDRESS_CREATE, $event);
$invoiceAddress = $event->getAddress();
}
if (null === $payPalCustomer = PaypalCustomerQuery::create()->findOneById($cart->getCustomerId())) {
$payPalCustomer = new PaypalCustomer();
$payPalCustomer->setId($cart->getCustomerId());
}
$payPalCustomer
->setPaypalUserId($payerInfo->getPayerId())
->setName($payerInfo->getFirstName())
->setGivenName($payerInfo->getFirstName() . ' ' . $payerInfo->getLastName())
->setFamilyName($payerInfo->getLastName())
->setMiddleName($payerInfo->getMiddleName())
->setBirthday($payerInfo->getBirthDate())
->setLocale($this->getRequest()->getSession()->getLang()->getLocale())
->setPhoneNumber($payerInfo->getPhone())
->setPayerId($payerInfo->getPayerId())
->setPostalCode($payerInfo->getShippingAddress()->getPostalCode())
->setCountry($payerInfo->getShippingAddress()->getCountryCode())
->setStreetAddress($payerInfo->getShippingAddress()->getLine1() . $payerInfo->getShippingAddress()->getLine2())
;
$payPalCustomerEvent = new PayPalCustomerEvent($payPalCustomer);
$this->dispatch(PayPalEvents::PAYPAL_CUSTOMER_UPDATE, $payPalCustomerEvent);
/** @var \Thelia\Model\Address $deliveryAddress */
$deliveryAddress = $cart->getCustomer()->getDefaultAddress();
/** @var \Thelia\Model\Module $deliveryModule */
$deliveryModule = ModuleQuery::create()->filterByActivate(1)->findOne();
/** @var \Thelia\Model\Module $paymentModule */
$paymentModule = ModuleQuery::create()->findPk(PayPal::getModuleId());
/** @var \Thelia\Model\Currency $currency */
$currency = $cart->getCurrency();
$lang = $this->getRequest()->getSession()->getLang();
$order = new Order();
$order
->setCustomerId($cart->getCustomerId())
->setCurrencyId($currency->getId())
->setCurrencyRate($currency->getRate())
->setStatusId(OrderStatusQuery::getNotPaidStatus()->getId())
->setLangId($lang->getDefaultLanguage()->getId())
->setChoosenDeliveryAddress($deliveryAddress)
->setChoosenInvoiceAddress($invoiceAddress)
;
$orderEvent = new OrderEvent($order);
/* get postage amount */
$moduleInstance = $deliveryModule->getDeliveryModuleInstance($this->container);
$deliveryPostageEvent = new DeliveryPostageEvent($moduleInstance, $cart, $deliveryAddress);
$this->getDispatcher()->dispatch(
TheliaEvents::MODULE_DELIVERY_GET_POSTAGE,
$deliveryPostageEvent
);
if (!$deliveryPostageEvent->isValidModule() || null === $deliveryPostageEvent->getPostage()) {
throw new DeliveryException(
$this->getTranslator()->trans('The delivery module is not valid.', [], PayPal::DOMAIN_NAME)
);
}
$postage = $deliveryPostageEvent->getPostage();
$orderEvent->setPostage($postage->getAmount());
$orderEvent->setPostageTax($postage->getAmountTax());
$orderEvent->setPostageTaxRuleTitle($postage->getTaxRuleTitle());
$orderEvent->setDeliveryAddress($deliveryAddress->getId());
$orderEvent->setInvoiceAddress($invoiceAddress->getId());
$orderEvent->setDeliveryModule($deliveryModule->getId());
$orderEvent->setPaymentModule($paymentModule->getId());
$this->getDispatcher()->dispatch(TheliaEvents::ORDER_SET_DELIVERY_ADDRESS, $orderEvent);
$this->getDispatcher()->dispatch(TheliaEvents::ORDER_SET_INVOICE_ADDRESS, $orderEvent);
$this->getDispatcher()->dispatch(TheliaEvents::ORDER_SET_POSTAGE, $orderEvent);
$this->getDispatcher()->dispatch(TheliaEvents::ORDER_SET_DELIVERY_MODULE, $orderEvent);
$this->getDispatcher()->dispatch(TheliaEvents::ORDER_SET_PAYMENT_MODULE, $orderEvent);
$orderManualEvent = new OrderManualEvent(
$orderEvent->getOrder(),
$orderEvent->getOrder()->getCurrency(),
$orderEvent->getOrder()->getLang(),
$cart,
$cart->getCustomer()
);
$this->getDispatcher()->dispatch(TheliaEvents::ORDER_CREATE_MANUAL, $orderManualEvent);
$order = $orderManualEvent->getPlacedOrder();
$payPalOrderEvent = $payPalPaymentService->generatePayPalOrder($order);
$payPalPaymentService->updatePayPalOrder($payPalOrderEvent->getPayPalOrder(), $payment->getState(), $payment->getId());
$response = $this->executePayment(
$payPalOrderEvent->getPayPalOrder(),
$payPalCart->getExpressPaymentId(),
$payPalCart->getExpressPayerId(),
$payPalCart->getExpressToken(),
PayPal::PAYPAL_METHOD_EXPRESS_CHECKOUT,
$payPalPaymentService->createDetails(
$order->getPostage(),
$order->getPostageTax(),
$order->getTotalAmount($tax, false)
)
);
$con->commit();
} catch (PayPalConnectionException $e) {
$con->rollBack();
$message = sprintf('url : %s. data : %s. message : %s', $e->getUrl(), $e->getData(), $e->getMessage());
$customerId = null;
if (isset($customer)) {
$customerId = $customer->getId();
}
PayPalLoggerService::log(
$message,
[
'customer_id' => $customerId
],
Logger::CRITICAL
);
$response = $responseParent;
} catch(\Exception $e) {
$con->rollBack();
$customerId = null;
if (isset($customer)) {
$customerId = $customer->getId();
}
PayPalLoggerService::log(
$e->getMessage(),
[
'customer_id' => $customerId
],
Logger::CRITICAL
);
$response = $responseParent;
}
$con->commit();
return $response;
}
/**
*
*/
public function expressCheckoutKoAction()
{
PayPalLoggerService::log(
Translator::getInstance()->trans('Express Checkout login failed', [], PayPal::DOMAIN_NAME),
[],
Logger::WARNING
);
return $this->getUrlFromRouteId('cart.view');
}
/**
* Method called when a customer log in with PayPal.
* @return RedirectResponse
* @throws \Exception
*/
public function loginOkAction()
{
if (null !== $authorizationCode = $this->getRequest()->query->get('code')) {
/** @var PayPalCustomerService $payPalCustomerService */
$payPalCustomerService = $this->container->get(PayPal::PAYPAL_CUSTOMER_SERVICE_ID);
$openIdUserinfo = $payPalCustomerService->getUserInfoWithAuthorizationCode($authorizationCode);
$payPalCustomer = $payPalCustomerService->getCurrentPayPalCustomer();
$payPalCustomer
->setPaypalUserId($openIdUserinfo->getUserId())
->setName($openIdUserinfo->getName())
->setGivenName($openIdUserinfo->getGivenName())
->setFamilyName($openIdUserinfo->getFamilyName())
->setMiddleName($openIdUserinfo->getMiddleName())
->setPicture($openIdUserinfo->getPicture())
->setEmailVerified($openIdUserinfo->getEmailVerified())
->setGender($openIdUserinfo->getGender())
->setBirthday($openIdUserinfo->getBirthday())
->setZoneinfo($openIdUserinfo->getZoneinfo())
->setLocale($openIdUserinfo->getLocale())
->setLanguage($openIdUserinfo->getLanguage())
->setVerified($openIdUserinfo->getVerified())
->setPhoneNumber($openIdUserinfo->getPhoneNumber())
->setVerifiedAccount($openIdUserinfo->getVerifiedAccount())
->setAccountType($openIdUserinfo->getAccountType())
->setAgeRange($openIdUserinfo->getAgeRange())
->setPayerId($openIdUserinfo->getPayerId())
->setPostalCode($openIdUserinfo->getAddress()->getPostalCode())
->setLocality($openIdUserinfo->getAddress()->getLocality())
->setRegion($openIdUserinfo->getAddress()->getRegion())
->setCountry($openIdUserinfo->getAddress()->getCountry())
->setStreetAddress($openIdUserinfo->getAddress()->getStreetAddress())
;
$payPalCustomerEvent = new PayPalCustomerEvent($payPalCustomer);
$this->dispatch(PayPalEvents::PAYPAL_CUSTOMER_UPDATE, $payPalCustomerEvent);
$this->dispatch(TheliaEvents::CUSTOMER_LOGIN, new CustomerLoginEvent($payPalCustomerEvent->getPayPalCustomer()->getCustomer()));
}
return new RedirectResponse(URL::getInstance()->absoluteUrl($this->getSession()->getReturnToUrl()));
}
/**
* @param $orderId
* @return RedirectResponse
*/
public function agreementOkAction($orderId)
{
$con = Propel::getConnection();
$con->beginTransaction();
$token = $this->getRequest()->query->get('token');
$payPalOrder = PaypalOrderQuery::create()->findOneById($orderId);
if (null !== $payPalOrder && null !== $token) {
try {
/** @var PayPalAgreementService $payPalAgreementService */
$payPalAgreementService = $this->container->get(PayPal::PAYPAL_AGREEMENT_SERVICE_ID);
$agreement = $payPalAgreementService->activateBillingAgreementByToken($token);
$payPalOrder
->setState($agreement->getState())
->setAgreementId($agreement->getId())
->setPayerId($agreement->getPayer()->getPayerInfo()->getPayerId())
->setToken($token)
;
$payPalOrderEvent = new PayPalOrderEvent($payPalOrder);
$this->dispatch(PayPalEvents::PAYPAL_ORDER_UPDATE, $payPalOrderEvent);
$event = new OrderEvent($payPalOrder->getOrder());
$event->setStatus(OrderStatusQuery::getPaidStatus()->getId());
$this->dispatch(TheliaEvents::ORDER_UPDATE_STATUS, $event);
$response = $this->getPaymentSuccessPageUrl($orderId);
PayPalLoggerService::log(
Translator::getInstance()->trans(
'Order payed with success in PayPal with method : %method',
[
'%method' => PayPal::PAYPAL_METHOD_PLANIFIED_PAYMENT
],
PayPal::DOMAIN_NAME
),
[
'order_id' => $payPalOrder->getId(),
'customer_id' => $payPalOrder->getOrder()->getCustomerId()
],
Logger::INFO
);
} catch (PayPalConnectionException $e) {
$con->rollBack();
$message = sprintf('url : %s. data : %s. message : %s', $e->getUrl(), $e->getData(), $e->getMessage());
PayPalLoggerService::log(
$message,
[
'customer_id' => $orderId
],
Logger::CRITICAL
);
$response = $this->getPaymentFailurePageUrl($orderId, $e->getMessage());
} catch (\Exception $e) {
$con->rollBack();
PayPalLoggerService::log(
$e->getMessage(),
[
'order_id' => $orderId
],
Logger::CRITICAL
);
$response = $this->getPaymentFailurePageUrl($orderId, $e->getMessage());
}
} else {
$con->rollBack();
$message = Translator::getInstance()->trans(
'Method agreementOkAction => One of this parameter is invalid : $token = %token, $orderId = %order_id',
[
'%token' => $token,
'%order_id' => $orderId
],
PayPal::DOMAIN_NAME
);
PayPalLoggerService::log(
$message,
[
'order_id' => $orderId
],
Logger::CRITICAL
);
$response = $this->getPaymentFailurePageUrl($orderId, $message);
}
$con->commit();
return $response;
}
/**
* @param $orderId
*/
public function ipnAction($orderId)
{
PayPalLoggerService::log('GUIGIT', ['hook' => 'guigit', 'order_id' => $orderId], Logger::DEBUG);
PayPalLoggerService::log(
print_r($this->getRequest()->request, true),
[
'hook' => 'guigit',
'order_id' => $orderId
],
Logger::DEBUG
);
PayPalLoggerService::log(
print_r($this->getRequest()->attributes, true),
[
'hook' => 'guigit',
'order_id' => $orderId
],
Logger::DEBUG
);
}
/**
* Return the order payment success page URL
*
* @param $orderId
* @return RedirectResponse
*/
public function getPaymentSuccessPageUrl($orderId)
{
return $this->getUrlFromRouteId('order.placed', ['order_id' => $orderId]);
}
/**
* @throws \Exception
* @throws \Propel\Runtime\Exception\PropelException
*/
protected function fillCartWithExpressCheckout()
{
$paymentId = $this->getRequest()->get('paymentId');
$token = $this->getRequest()->get('token');
$payerId = $this->getRequest()->get('PayerID');
$cartId = $this->getRequest()->get('cartId');
$cart = CartQuery::create()->findOneById($this->getRequest()->get('cartId'));
if (null === $paymentId || null === $token || null === $payerId || null === $cart) {
PayPalLoggerService::log(
Translator::getInstance()->trans('Express checkout failed in expressCheckoutOkAction() function', [], PayPal::DOMAIN_NAME),
[],
Logger::CRITICAL
);
}
PayPalLoggerService::log(
Translator::getInstance()->trans('Express checkout begin with cart %id', ['%id' => $cartId], PayPal::DOMAIN_NAME)
);
/** @var PayPalPaymentService $payPalPaymentService */
$payPalPaymentService = $this->container->get(PayPal::PAYPAL_PAYMENT_SERVICE_ID);
$payment = $payPalPaymentService->getPaymentDetails($paymentId);
$payerInfo = $payment->getPayer()->getPayerInfo();
if (null === $customer = CustomerQuery::create()->findOneByEmail($payment->getPayer()->getPayerInfo()->getEmail())) {
$customerCreateEvent = $this->createEventInstance($payerInfo);
$this->dispatch(TheliaEvents::CUSTOMER_CREATEACCOUNT, $customerCreateEvent);
$customer = $customerCreateEvent->getCustomer();
}
//Save informations to use them after customer has choosen the delivery method
if (null === $payPalCart = PaypalCartQuery::create()->findOneById($cartId)) {
$payPalCart = new PaypalCart();
$payPalCart->setId($cartId);
}
$payPalCart
->setExpressPaymentId($paymentId)
->setExpressPayerId($payerId)
->setExpressToken($token)
;
$payPalCartEvent = new PayPalCartEvent($payPalCart);
$this->getDispatcher()->dispatch(PayPalEvents::PAYPAL_CART_UPDATE, $payPalCartEvent);
$cart->setCustomerId($customer->getId())->save();
$clonedCart = clone $cart;
$this->dispatch(TheliaEvents::CUSTOMER_LOGIN, new CustomerLoginEvent($customer));
//In case of the current customer has changed, re affect the correct cart and customer session
$this->getSecurityContext()->setCustomerUser($customer);
$clonedCart->save();
$this->getRequest()->getSession()->set("thelia.cart_id", $clonedCart->getId());
}
/**
* @param $routeId
* @param array $params
* @return RedirectResponse
*/
protected function getUrlFromRouteId($routeId, $params = [])
{
$frontOfficeRouter = $this->getContainer()->get('router.front');
return new RedirectResponse(
URL::getInstance()->absoluteUrl(
$frontOfficeRouter->generate(
$routeId,
$params,
Router::ABSOLUTE_URL
)
)
);
}
/**
* Redirect the customer to the failure payment page. if $message is null, a generic message is displayed.
*
* @param $orderId
* @param $message
* @return RedirectResponse
*/
public function getPaymentFailurePageUrl($orderId, $message)
{
$frontOfficeRouter = $this->getContainer()->get('router.front');
return new RedirectResponse(
URL::getInstance()->absoluteUrl(
$frontOfficeRouter->generate(
"order.failed",
array(
"order_id" => $orderId,
"message" => $message
),
Router::ABSOLUTE_URL
)
)
);
}
/**
* @param PaypalOrder $payPalOrder
* @param $paymentId
* @param $payerId
* @param $token
* @param string $method
* @param Details|null $details
* @return RedirectResponse
*/
protected function executePayment(PaypalOrder $payPalOrder, $paymentId, $payerId, $token, $method = PayPal::PAYPAL_METHOD_PAYPAL, Details $details = null)
{
/** @var PayPalPaymentService $payPalService */
$payPalService = $this->getContainer()->get(PayPal::PAYPAL_PAYMENT_SERVICE_ID);
$payment = $payPalService->executePayment($paymentId, $payerId, $details);
$payPalOrder
->setState($payment->getState())
->setPayerId($payerId)
->setToken($token)
;
$payPalOrderEvent = new PayPalOrderEvent($payPalOrder);
$this->dispatch(PayPalEvents::PAYPAL_ORDER_UPDATE, $payPalOrderEvent);
$event = new OrderEvent($payPalOrder->getOrder());
$event->setStatus(OrderStatusQuery::getPaidStatus()->getId());
$this->dispatch(TheliaEvents::ORDER_UPDATE_STATUS, $event);
$response = $this->getPaymentSuccessPageUrl($payPalOrder->getId());
PayPalLoggerService::log(
Translator::getInstance()->trans(
'Order payed with success in PayPal with method : %method',
[
'%method' => $method
],
PayPal::DOMAIN_NAME
),
[
'order_id' => $payPalOrder->getId(),
'customer_id' => $payPalOrder->getOrder()->getCustomerId()
],
Logger::INFO
);
return $response;
}
/**
* @param PayerInfo $payerInfo
* @return \Thelia\Core\Event\Customer\CustomerCreateOrUpdateEvent
*/
protected function createEventInstance(PayerInfo $payerInfo)
{
if (null === $country = CountryQuery::create()->findOneByIsoalpha2($payerInfo->getShippingAddress()->getCountryCode())) {
$country = Country::getDefaultCountry();
}
$customerCreateEvent = new CustomerCreateOrUpdateEvent(
CustomerTitleQuery::create()->findOne()->getId(),
$payerInfo->getFirstName(),
$payerInfo->getLastName(),
$payerInfo->getShippingAddress()->getLine1(),
$payerInfo->getShippingAddress()->getLine2(),
null,
$payerInfo->getPhone(),
null,
$payerInfo->getShippingAddress()->getPostalCode(),
$payerInfo->getShippingAddress()->getCity(),
$country->getId(),
$payerInfo->getEmail(),
'random',
$this->getRequest()->getSession()->getLang()->getId(),
null,
null,
null,
null,
null,
null
);
return $customerCreateEvent;
}
/**
* @param PayerInfo $payerInfo
* @return AddressCreateOrUpdateEvent
*/
protected function createAddressEvent(PayerInfo $payerInfo)
{
if (null !== $payerInfo->getBillingAddress()) {
$countryCode = $payerInfo->getBillingAddress()->getCountryCode();
$line1 = $payerInfo->getBillingAddress()->getLine1();
$line2 = $payerInfo->getBillingAddress()->getLine2();
$zipCode = $payerInfo->getBillingAddress()->getPostalCode();
$city = $payerInfo->getBillingAddress()->getCity();
} else {
$countryCode = $payerInfo->getShippingAddress()->getCountryCode();
$line1 = $payerInfo->getShippingAddress()->getLine1();
$line2 = $payerInfo->getShippingAddress()->getLine2();
$zipCode = $payerInfo->getShippingAddress()->getPostalCode();
$city = $payerInfo->getShippingAddress()->getCity();
}
if (null === $country = CountryQuery::create()->findOneByIsoalpha2($countryCode)) {
$country = Country::getDefaultCountry();
}
return new AddressCreateOrUpdateEvent(
'Express checkout PayPal',
CustomerTitleQuery::create()->findOne()->getId(),
$payerInfo->getFirstName(),
$payerInfo->getLastName(),
$line1,
($line2)?$line2:'',
'',
$zipCode,
$city,
$country->getId(),
$payerInfo->getPhone(),
$payerInfo->getPhone(),
'',
0,
null
);
}
}

View File

@@ -0,0 +1,336 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace PayPal\Controller;
use Monolog\Logger;
use PayPal\Event\PayPalEvents;
use PayPal\Event\PayPalOrderEvent;
use PayPal\Exception\PayPalConnectionException;
use PayPal\Model\PaypalOrderQuery;
use PayPal\Model\PaypalPlanQuery;
use PayPal\PayPal;
use PayPal\Service\PayPalAgreementService;
use PayPal\Service\PayPalLoggerService;
use Propel\Runtime\Propel;
use Thelia\Controller\Front\BaseFrontController;
use Thelia\Core\Event\Order\OrderEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Core\HttpFoundation\Request;
use Thelia\Core\Translation\Translator;
use Thelia\Model\OrderStatusQuery;
/**
* Class PayPalWebHookController
* @package PayPal\Controller
*/
class PayPalWebHookController extends BaseFrontController
{
const HOOK_BILLING_PLAN_CREATED = 'BILLING.PLAN.CREATED';
const HOOK_BILLING_PLAN_UPDATED = 'BILLING.PLAN.UPDATED';
const HOOK_BILLING_SUBSCRIPTION_CREATED = 'BILLING.SUBSCRIPTION.CREATED';
const HOOK_PAYMENT_SALE_COMPLETED = 'PAYMENT.SALE.COMPLETED';
const HOOK_PAYMENT_SALE_DENIED = 'PAYMENT.SALE.DENIED';
//Classic PayPal payment
const RESOURCE_TYPE_SALE = 'sale';
//Planified payment
const RESOURCE_TYPE_PLAN = 'plan';
const RESOURCE_TYPE_AGREEMENT = 'agreement';
/**
* Example of array received in posted params :
*
*
* Array (
* 'id' => 'WH-0LU96374794024348-4WG31854RU4949452',
* 'event_version' => 1.0,
* 'create_time' => '2017-02-03T15:31:29Z',
* 'resource_type' => 'plan',
* 'event_type' => 'BILLING.PLAN.CREATED',
* 'summary' => 'A billing plan was created',
* 'resource' => Array (
* 'merchant_preferences' => Array (
* 'setup_fee' => Array (
* 'currency' => 'EUR',
* 'value' => 0
* ),
* 'return_url' => 'http://25b3ee89.ngrok.io/thelia_2_3_3/web/module/paypal/agreement/ok/208',
* 'cancel_url' => 'http://25b3ee89.ngrok.io/thelia_2_3_3/web/module/paypal/agreement/ko/208',
* 'auto_bill_amount' => 'NO',
* 'initial_fail_amount_action' => 'CONTINUE',
* 'max_fail_attempts' => 0
* ),
* 'update_time' => '2017-02-03T15:31:29.348Z',
* 'create_time' => '2017-02-03T15:31:29.348Z',
* 'name' => 'plan for order 208',
* 'description' => false,
* 'links' => Array (
* 0 => Array (
* 'href' => 'api.sandbox.paypal.com/v1/payments/billing-plans/P-2DV20774VJ3968037ASNA3RA',
* 'rel' => 'self',
* 'method' => 'GET'
* )
* ),
* 'payment_definitions' => Array (
* 0 => Array (
* 'name' => 'payment definition for order 208',
* 'type' => 'REGULAR',
* 'frequency' => 'Day',
* 'frequency_interval' => 1,
* 'amount' => Array (
* 'currency' => 'EUR',
* 'value' => 3.9
* ),
* 'cycles' => 5,
* 'charge_models' => Array (
* 0 => Array (
* 'type' => 'SHIPPING',
* 'amount' => Array (
* 'currency' => 'EUR',
* 'value' => 0
* ),
* 'id' => 'CHM-26B03456D8799461GASNA3RA'
* )
* ),
* 'id' => 'PD-3FB00313143031422ASNA3RA'
* )
* ),
* 'id' => 'P-2DV20774VJ3968037ASNA3RA',
* 'state' => 'CREATED',
* 'type' => 'FIXED'
* ),
* 'links' => Array (
* 0 => Array (
* 'href' => 'https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-0LU96374794024348-4WG31854RU4949452',
* 'rel' => 'self',
* 'method' => 'GET'
* ),
* 1 => Array (
* 'href' => 'https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-0LU96374794024348-4WG31854RU4949452/resend',
* 'rel' => 'resend',
* 'method' => 'POST'
* )
* )
* );
*/
public function allAction()
{
$eventType = $this->getRequest()->request->get('event_type');
$resource = $this->getRequest()->request->get('resource');
$resourceType = $this->getRequest()->request->get('resource_type');
$details = [
'request' => $this->getRequest()->request->all()
];
$params = [
'hook' => $eventType
];
$con = Propel::getConnection();
$con->beginTransaction();
try {
$title = $this->getTitle($this->getRequest());
if (is_array($resource)) {
switch (strtolower($resourceType)) {
case self::RESOURCE_TYPE_SALE:
if (isset($resource['parent_payment'])) {
$params = $this->getParamsForSale($resource['parent_payment'], $params, $eventType);
}
if (isset($resource['billing_agreement_id'])) {
$params = $this->getParamsForAgreement($resource['billing_agreement_id'], $params);
}
break;
case self::RESOURCE_TYPE_PLAN:
if (isset($resource['id'])) {
$params = $this->getParamsForPlan($resource['id'], $params);
}
break;
case self::RESOURCE_TYPE_AGREEMENT:
if (isset($resource['id'])) {
$params = $this->getParamsForAgreement($resource['id'], $params);
}
break;
default:
break;
}
}
PayPalLoggerService::log(
'<h3>' . $title . '</h3>' . $this->printRecursiveData($details),
$params,
Logger::INFO
);
$con->commit();
} catch (PayPalConnectionException $e) {
$con->rollBack();
$message = sprintf('url : %s. data : %s. message : %s', $e->getUrl(), $e->getData(), $e->getMessage());
PayPalLoggerService::log($message, $params, Logger::CRITICAL);
PayPalLoggerService::log($this->printRecursiveData($this->getRequest()->request), $params, Logger::CRITICAL);
} catch (\Exception $e) {
$con->rollBack();
PayPalLoggerService::log($e->getMessage(), $params, Logger::CRITICAL);
PayPalLoggerService::log($this->printRecursiveData($this->getRequest()->request), $params, Logger::CRITICAL);
}
}
/**
* @param Request $request
* @return string
*/
protected function getTitle(Request $request)
{
$summary = $request->request->get('summary');
$title = '';
if (null !== $request->get('event_type')) {
$title .= $request->get('event_type') . ' : ';
}
$title .= $summary;
return $title;
}
/**
* @param null $paymentId
* @param array $params
* @param null $eventType
* @return array
*/
protected function getParamsForSale($paymentId = null, $params = [], $eventType = null)
{
if (null !== $payPalOrder = PaypalOrderQuery::create()->findOneByPaymentId($paymentId)) {
$params['order_id'] = $payPalOrder->getId();
$params['customer_id'] = $payPalOrder->getOrder()->getCustomerId();
if ($eventType === self::HOOK_PAYMENT_SALE_DENIED) {
$event = new OrderEvent($payPalOrder->getOrder());
$event->setStatus(OrderStatusQuery::getCancelledStatus()->getId());
$this->dispatch(TheliaEvents::ORDER_UPDATE_STATUS, $event);
}
}
return $params;
}
/**
* @param null $planId
* @param array $params
* @return array
*/
protected function getParamsForPlan($planId = null, $params = [])
{
if (null !== $payPalPlan = PaypalPlanQuery::create()->findOneByPlanId($planId)) {
$params['order_id'] = $payPalPlan->getPaypalOrderId();
$params['customer_id'] = $payPalPlan->getPaypalOrder()->getOrder()->getCustomerId();
}
return $params;
}
/**
* @param null $agreementId
* @param array $params
* @return array
*/
protected function getParamsForAgreement($agreementId = null, $params = [])
{
if (null !== $payPalOrder = PaypalOrderQuery::create()->filterByAgreementId($agreementId)->orderById()->findOne()) {
// Do not duplicate order for the first PayPal payment because order has just been created.
// We will duplicate this order for the next PayPal payment :)
if ($payPalOrder->getPlanifiedActualCycle() > 0) {
$params['order_id'] = $payPalOrder->getId();
$params['customer_id'] = $payPalOrder->getOrder()->getCustomerId();
/** @var PayPalAgreementService $payPalAgreementService */
$payPalAgreementService = $this->container->get(PayPal::PAYPAL_AGREEMENT_SERVICE_ID);
$newOrder = $payPalAgreementService->duplicateOrder($payPalOrder->getOrder());
Translator::getInstance()->trans(
'New recursive invoice from order %id',
['%id' => $payPalOrder->getId()],
PayPal::DOMAIN_NAME
);
PayPalLoggerService::log(
'<h3>New recursive invoice from order ' . $payPalOrder->getId() . '</h3>',
[
'order_id' => $newOrder->getId(),
'customer_id' => $payPalOrder->getOrder()->getCustomerId()
],
Logger::INFO
);
}
$payPalOrder->setPlanifiedActualCycle($payPalOrder->getPlanifiedActualCycle() + 1);
$payPalOrderEvent = new PayPalOrderEvent($payPalOrder);
$this->getDispatcher()->dispatch(PayPalEvents::PAYPAL_ORDER_UPDATE, $payPalOrderEvent);
}
return $params;
}
/**
* @param array $data
* @param int $deep
* @return string
*/
protected function printRecursiveData($data = [], $deep = 0)
{
$formatedString = '';
foreach ($data as $key => $value) {
for ($i = 0; $i <= $deep; $i++) {
$formatedString .= '&nbsp;&nbsp;&nbsp;&nbsp;';
}
if (is_array($value)) {
$formatedString .= '<strong>' . $key . '&nbsp;:&nbsp;</strong><br />' . $this->printRecursiveData($value, $deep + 1);
} else {
$formatedString .= '<strong>' . $key . '&nbsp;:&nbsp;</strong>' . $value . '<br />';
}
}
return $formatedString;
}
}

View File

@@ -0,0 +1,66 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace PayPal\Event;
use PayPal\Model\PaypalCart;
use Thelia\Core\Event\ActionEvent;
/**
* Class PayPalCartEvent
* @package PayPal\Event
*/
class PayPalCartEvent extends ActionEvent
{
/** @var PaypalCart */
protected $payPalCart;
/**
* PayPalCartEvent constructor.
* @param PaypalCart $payPalCart
*/
public function __construct(PaypalCart $payPalCart)
{
$this->payPalCart = $payPalCart;
}
/**
* @return PaypalCart
*/
public function getPayPalCart()
{
return $this->payPalCart;
}
/**
* @param PaypalCart $payPalCart
*
* @return $this
*/
public function setPayPalCart($payPalCart)
{
$this->payPalCart = $payPalCart;
return $this;
}
}

View File

@@ -0,0 +1,66 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace PayPal\Event;
use PayPal\Model\PaypalCustomer;
use Thelia\Core\Event\ActionEvent;
/**
* Class PayPalCustomerEvent
* @package PayPal\Event
*/
class PayPalCustomerEvent extends ActionEvent
{
/** @var PaypalCustomer */
protected $payPalCustomer;
/**
* PayPalCustomerEvent constructor.
* @param PaypalCustomer $payPalCustomer
*/
public function __construct(PaypalCustomer $payPalCustomer)
{
$this->payPalCustomer = $payPalCustomer;
}
/**
* @return PaypalCustomer
*/
public function getPayPalCustomer()
{
return $this->payPalCustomer;
}
/**
* @param PaypalCustomer $payPalCustomer
*
* @return $this
*/
public function setPayPalCustomer($payPalCustomer)
{
$this->payPalCustomer = $payPalCustomer;
return $this;
}
}

View File

@@ -0,0 +1,57 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace PayPal\Event;
/**
* Class PayPalEvents
* @package PayPal\Event
*/
class PayPalEvents
{
const PAYPAL_ORDER_CREATE = 'action.paypal.order.create';
const PAYPAL_ORDER_UPDATE = 'action.paypal.order.update';
const PAYPAL_ORDER_DELETE = 'action.paypal.order.delete';
const PAYPAL_RECURSIVE_PAYMENT_CREATE = 'action.paypal.recursive.payment.create';
const PAYPAL_AGREEMENT_CREATE = 'action.paypal.agreement.create';
const PAYPAL_AGREEMENT_UPDATE = 'action.paypal.agreement.update';
const PAYPAL_AGREEMENT_DELETE = 'action.paypal.agreement.delete';
const PAYPAL_PLAN_CREATE = 'action.paypal.plan.create';
const PAYPAL_PLAN_UPDATE = 'action.paypal.plan.update';
const PAYPAL_PLAN_DELETE = 'action.paypal.plan.delete';
const PAYPAL_CUSTOMER_CREATE = 'action.paypal.customer.create';
const PAYPAL_CUSTOMER_UPDATE = 'action.paypal.customer.update';
const PAYPAL_CUSTOMER_DELETE = 'action.paypal.customer.delete';
const PAYPAL_CART_CREATE = 'action.paypal.cart.create';
const PAYPAL_CART_UPDATE = 'action.paypal.cart.update';
const PAYPAL_CART_DELETE = 'action.paypal.cart.delete';
const PAYPAL_PLANIFIED_PAYMENT_CREATE = 'action.paypal.planified.payment.create';
const PAYPAL_PLANIFIED_PAYMENT_UPDATE = 'action.paypal.planified.payment.update';
const PAYPAL_PLANIFIED_PAYMENT_DELETE = 'action.paypal.planified.payment.delete';
}

View File

@@ -0,0 +1,66 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace PayPal\Event;
use PayPal\Model\PaypalOrder;
use Thelia\Core\Event\ActionEvent;
/**
* Class PayPalOrderEvent
* @package PayPal\Event
*/
class PayPalOrderEvent extends ActionEvent
{
/** @var PaypalOrder */
protected $payPalOrder;
/**
* PayPalOrderEvent constructor.
* @param PaypalOrder $payPalOrder
*/
public function __construct(PaypalOrder $payPalOrder)
{
$this->payPalOrder = $payPalOrder;
}
/**
* @return PaypalOrder
*/
public function getPayPalOrder()
{
return $this->payPalOrder;
}
/**
* @param PaypalOrder $payPalOrder
*
* @return $this
*/
public function setPayPalOrder($payPalOrder)
{
$this->payPalOrder = $payPalOrder;
return $this;
}
}

View File

@@ -0,0 +1,66 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace PayPal\Event;
use PayPal\Model\PaypalPlan;
use Thelia\Core\Event\ActionEvent;
/**
* Class PayPalPlanEvent
* @package PayPal\Event
*/
class PayPalPlanEvent extends ActionEvent
{
/** @var PaypalPlan */
protected $payPalPlan;
/**
* PayPalPlanEvent constructor.
* @param PaypalPlan $payPalPlan
*/
public function __construct(PaypalPlan $payPalPlan)
{
$this->payPalPlan = $payPalPlan;
}
/**
* @return PaypalPlan
*/
public function getPayPalPlan()
{
return $this->payPalPlan;
}
/**
* @param PaypalPlan $payPalPlan
*
* @return $this
*/
public function setPayPalPlan($payPalPlan)
{
$this->payPalPlan = $payPalPlan;
return $this;
}
}

View File

@@ -0,0 +1,66 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace PayPal\Event;
use PayPal\Model\PaypalPlanifiedPayment;
use Thelia\Core\Event\ActionEvent;
/**
* Class PayPalPlanifiedPaymentEvent
* @package PayPal\Event
*/
class PayPalPlanifiedPaymentEvent extends ActionEvent
{
/** @var PaypalPlanifiedPayment */
protected $payPalPlanifiedPayment;
/**
* PayPalPlanifiedPaymentEvent constructor.
* @param PaypalPlanifiedPayment $payPalPlanifiedPayment
*/
public function __construct(PaypalPlanifiedPayment $payPalPlanifiedPayment)
{
$this->payPalPlanifiedPayment = $payPalPlanifiedPayment;
}
/**
* @return PaypalPlanifiedPayment
*/
public function getPayPalPlanifiedPayment()
{
return $this->payPalPlanifiedPayment;
}
/**
* @param PaypalPlanifiedPayment $payPalPlanifiedPayment
*
* @return $this
*/
public function setPayPalPlanifiedPayment($payPalPlanifiedPayment)
{
$this->payPalPlanifiedPayment = $payPalPlanifiedPayment;
return $this;
}
}

View File

@@ -0,0 +1,172 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace PayPal\EventListeners\Form;
use PayPal\Form\PayPalFormFields;
use PayPal\Form\Type\PayPalCreditCardType;
use PayPal\Model\PaypalPlanifiedPayment;
use PayPal\Model\PaypalPlanifiedPaymentQuery;
use PayPal\PayPal;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Core\Event\TheliaFormEvent;
use Thelia\Core\HttpFoundation\Session\Session;
use Thelia\Core\Translation\Translator;
use Thelia\Model\Cart;
use Thelia\Model\Country;
use Thelia\Model\Order;
/**
* Class TheliaOrderPaymentForm
* @package PayPal\EventListeners\Form
*/
class TheliaOrderPaymentForm implements EventSubscriberInterface
{
/** @var RequestStack */
protected $requestStack;
/** @var EventDispatcherInterface */
protected $dispatcher;
/**
* TheliaOrderPaymentForm constructor.
* @param RequestStack $requestStack
*/
public function __construct(RequestStack $requestStack, EventDispatcherInterface $dispatcher)
{
$this->requestStack = $requestStack;
$this->dispatcher = $dispatcher;
}
/**
* @param TheliaFormEvent $event
*/
public function afterBuildTheliaOrderPayment(TheliaFormEvent $event)
{
$event->getForm()->getFormBuilder()
->add(
PayPalFormFields::FIELD_PAYPAL_METHOD,
'choice',
[
'choices' => [
PayPal::PAYPAL_METHOD_PAYPAL => PayPal::PAYPAL_METHOD_PAYPAL,
PayPal::PAYPAL_METHOD_EXPRESS_CHECKOUT => PayPal::PAYPAL_METHOD_EXPRESS_CHECKOUT,
PayPal::PAYPAL_METHOD_CREDIT_CARD => PayPal::PAYPAL_METHOD_CREDIT_CARD,
PayPal::PAYPAL_METHOD_PLANIFIED_PAYMENT => PayPal::PAYPAL_METHOD_PLANIFIED_PAYMENT
],
'label' => Translator::getInstance()->trans('PayPal method', [], PayPal::DOMAIN_NAME),
'label_attr' => ['for' => PayPalFormFields::FIELD_PAYPAL_METHOD],
'required' => false,
]
)
->add(
PayPalCreditCardType::TYPE_NAME,
new PayPalCreditCardType(),
[
'label_attr' => [
'for' => PayPalCreditCardType::TYPE_NAME
]
]
)
->add(
PayPalFormFields::FIELD_PAYPAL_PLANIFIED_PAYMENT,
'choice',
[
'choices' => $this->getAllowedPlanifiedPayments(),
'choices_as_values' => true,
'choice_label' => function ($value, $key, $index) {
return $value->getTitle();
},
'choice_value' => function ($value) {
if ($value !== null) {
return $value->getId();
}
return null;
},
"required" => false,
'empty_data' => null,
'label' => Translator::getInstance()->trans('Frequency', [], PayPal::DOMAIN_NAME),
'label_attr' => ['for' => PayPalFormFields::FIELD_PAYPAL_PLANIFIED_PAYMENT],
]
)
;
}
/**
* @return array|mixed|\Propel\Runtime\Collection\ObjectCollection
*/
protected function getAllowedPlanifiedPayments()
{
/** @var Session $session */
$session = $this->requestStack->getCurrentRequest()->getSession();
/** @var \Thelia\Model\Lang $lang */
$lang = $session->getLang();
/** @var Cart $cart */
$cart = $session->getSessionCart($this->dispatcher);
/** @var Order $order */
$order = $session->get('thelia.order');
$country = Country::getDefaultCountry();
$planifiedPayments = (new PaypalPlanifiedPaymentQuery())->joinWithI18n($lang->getLocale())->find();
if (null !== $cart && null !== $order && null !== $country) {
$totalAmount = $cart->getTaxedAmount($country) + (float)$order->getPostage();
$restrictedPlanifiedAmounts = [];
/** @var PaypalPlanifiedPayment $planifiedPayment */
foreach ($planifiedPayments as $planifiedPayment) {
if ($planifiedPayment->getMinAmount() > 0 && $planifiedPayment->getMinAmount() > $totalAmount) {
continue;
}
if ($planifiedPayment->getMaxAmount() > 0 && $planifiedPayment->getMaxAmount() < $totalAmount) {
continue;
}
$restrictedPlanifiedAmounts[] = $planifiedPayment;
}
$planifiedPayments = $restrictedPlanifiedAmounts;
}
return $planifiedPayments;
}
/**
* @return array The event names to listen to
*/
public static function getSubscribedEvents()
{
return [
TheliaEvents::FORM_AFTER_BUILD . '.thelia_order_payment' => ['afterBuildTheliaOrderPayment', 128]
];
}
}

View File

@@ -0,0 +1,273 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace PayPal\EventListeners;
use PayPal\Event\PayPalCartEvent;
use PayPal\Event\PayPalEvents;
use PayPal\Form\PayPalFormFields;
use PayPal\Form\Type\PayPalCreditCardType;
use PayPal\PayPal;
use PayPal\Service\PayPalAgreementService;
use PayPal\Service\PayPalPaymentService;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Thelia\Core\Event\Order\OrderEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Mailer\MailerFactory;
/**
* Class OrderListener
* @package PayPal\EventListeners
*/
class OrderListener implements EventSubscriberInterface
{
/** @var MailerFactory */
protected $mailer;
/** @var EventDispatcherInterface */
protected $dispatcher;
/** @var RequestStack */
protected $requestStack;
/** @var PayPalPaymentService */
protected $payPalPaymentService;
/** @var PayPalAgreementService */
protected $payPalAgreementService;
/**
* @param MailerFactory $mailer
* @param EventDispatcherInterface $dispatcher
* @param RequestStack $requestStack
* @param PayPalPaymentService $payPalPaymentService
* @param PayPalAgreementService $payPalAgreementService
*/
public function __construct(MailerFactory $mailer, EventDispatcherInterface $dispatcher, RequestStack $requestStack, PayPalPaymentService $payPalPaymentService, PayPalAgreementService $payPalAgreementService)
{
$this->dispatcher = $dispatcher;
$this->mailer = $mailer;
$this->requestStack = $requestStack;
$this->payPalPaymentService = $payPalPaymentService;
$this->payPalAgreementService = $payPalAgreementService;
}
/**
* @param OrderEvent $event
*/
public function CancelPayPalTransaction(OrderEvent $event)
{
// @TODO : Inform PayPal that this payment is canceled ?
}
/**
* @param OrderEvent $event
*
* @throws \Exception if the message cannot be loaded.
*/
public function sendConfirmationEmail(OrderEvent $event)
{
if (PayPal::getConfigValue('send_confirmation_message_only_if_paid')) {
// We send the order confirmation email only if the order is paid
$order = $event->getOrder();
if (! $order->isPaid() && $order->getPaymentModuleId() == Paypal::getModuleId()) {
$event->stopPropagation();
}
}
}
/**
* Checks if order payment module is paypal and if order new status is paid, send an email to the customer.
*
* @param OrderEvent $event
*/
public function updateStatus(OrderEvent $event)
{
$order = $event->getOrder();
if ($order->isPaid() && $order->getPaymentModuleId() === Paypal::getModuleId()) {
if (Paypal::getConfigValue('send_payment_confirmation_message')) {
$this->mailer->sendEmailToCustomer(
PayPal::CONFIRMATION_MESSAGE_NAME,
$order->getCustomer(),
[
'order_id' => $order->getId(),
'order_ref' => $order->getRef()
]
);
}
// Send confirmation email if required.
if (Paypal::getConfigValue('send_confirmation_message_only_if_paid')) {
$this->dispatcher->dispatch(TheliaEvents::ORDER_SEND_CONFIRMATION_EMAIL, $event);
}
}
}
/**
* @param OrderEvent $event
* @throws \Exception
*/
public function checkPayPalMethod(OrderEvent $event)
{
//First be sure that there is no OLD CREDIT card saved in paypal_cart because of fatal error
$payPalCartEvent = new PayPalCartEvent($this->payPalPaymentService->getCurrentPayPalCart());
$this->dispatcher->dispatch(PayPalEvents::PAYPAL_CART_DELETE, $payPalCartEvent);
$postedData = $this->requestStack->getCurrentRequest()->request->get('thelia_order_payment');
if (isset($postedData[PayPalFormFields::FIELD_PAYMENT_MODULE]) && PayPal::getModuleId() === $event->getOrder()->getPaymentModuleId()) {
$this->usePayPalMethod($postedData);
}
}
/**
* @param OrderEvent $event
*/
public function recursivePayment(OrderEvent $event)
{
$this->payPalAgreementService->duplicateOrder($event->getOrder());
if (PayPal::getConfigValue('send_recursive_message')) {
$this->mailer->sendEmailToCustomer(
PayPal::RECURSIVE_MESSAGE_NAME,
$event->getOrder()->getCustomer(),
[
'order_id' => $event->getOrder()->getId(),
'order_ref' => $event->getOrder()->getRef()
]
);
}
}
/**
* @param array $postedData
*/
protected function usePayPalMethod($postedData = [])
{
if (isset($postedData[PayPalFormFields::FIELD_PAYPAL_METHOD])) {
$payPalMethod = $postedData[PayPalFormFields::FIELD_PAYPAL_METHOD];
switch ($payPalMethod) {
case PayPal::PAYPAL_METHOD_CREDIT_CARD:
$this->usePayPalCreditCardMethod($postedData);
break;
case PayPal::PAYPAL_METHOD_PLANIFIED_PAYMENT:
$this->usePayPalPlanifiedPaymentMethod($postedData);
break;
}
}
}
/**
* @param array $postedData
* @throws \Exception
*/
protected function usePayPalCreditCardMethod($postedData = [])
{
if ($this->isValidPaidByPayPalCreditCard($postedData)) {
//save credit card in cart because we will need it in pay() method for payment module
$creditCardId = $this->payPalPaymentService->getPayPalCreditCardId(
$postedData[PayPalCreditCardType::TYPE_NAME][PayPalFormFields::FIELD_CARD_TYPE],
$postedData[PayPalCreditCardType::TYPE_NAME][PayPalFormFields::FIELD_CARD_NUMBER],
$postedData[PayPalCreditCardType::TYPE_NAME][PayPalFormFields::FIELD_CARD_EXPIRE_MONTH],
$postedData[PayPalCreditCardType::TYPE_NAME][PayPalFormFields::FIELD_CARD_EXPIRE_YEAR],
$postedData[PayPalCreditCardType::TYPE_NAME][PayPalFormFields::FIELD_CARD_CVV]
);
$payPalCart = $this->payPalPaymentService->getCurrentPayPalCart();
$payPalCart->setCreditCardId($creditCardId);
$payPalCartEvent = new PayPalCartEvent($payPalCart);
$this->dispatcher->dispatch(PayPalEvents::PAYPAL_CART_UPDATE, $payPalCartEvent);
}
}
/**
* @param array $postedData
* @return bool
*/
protected function isValidPaidByPayPalCreditCard($postedData = [])
{
$isValid = false;
if (isset($postedData[PayPalCreditCardType::TYPE_NAME][PayPalFormFields::FIELD_CARD_TYPE]) && $this->isNotBlank($postedData[PayPalCreditCardType::TYPE_NAME][PayPalFormFields::FIELD_CARD_TYPE]) &&
isset($postedData[PayPalCreditCardType::TYPE_NAME][PayPalFormFields::FIELD_CARD_NUMBER]) && $this->isNotBlank($postedData[PayPalCreditCardType::TYPE_NAME][PayPalFormFields::FIELD_CARD_NUMBER]) &&
isset($postedData[PayPalCreditCardType::TYPE_NAME][PayPalFormFields::FIELD_CARD_EXPIRE_MONTH]) && $this->isNotBlank($postedData[PayPalCreditCardType::TYPE_NAME][PayPalFormFields::FIELD_CARD_EXPIRE_MONTH]) &&
isset($postedData[PayPalCreditCardType::TYPE_NAME][PayPalFormFields::FIELD_CARD_EXPIRE_YEAR]) && $this->isNotBlank($postedData[PayPalCreditCardType::TYPE_NAME][PayPalFormFields::FIELD_CARD_EXPIRE_YEAR]) &&
isset($postedData[PayPalCreditCardType::TYPE_NAME][PayPalFormFields::FIELD_CARD_CVV]) && $this->isNotBlank($postedData[PayPalCreditCardType::TYPE_NAME][PayPalFormFields::FIELD_CARD_CVV])) {
$isValid = true;
}
return $isValid;
}
/**
* @param array $postedData
*/
protected function usePayPalPlanifiedPaymentMethod($postedData = [])
{
if (isset($postedData[PayPalFormFields::FIELD_PAYPAL_PLANIFIED_PAYMENT]) &&
$this->isNotBlank($postedData[PayPalFormFields::FIELD_PAYPAL_PLANIFIED_PAYMENT])) {
$payPalCart = $this->payPalPaymentService->getCurrentPayPalCart();
$payPalCart->setPlanifiedPaymentId($postedData[PayPalFormFields::FIELD_PAYPAL_PLANIFIED_PAYMENT]);
$payPalCartEvent = new PayPalCartEvent($payPalCart);
$this->dispatcher->dispatch(PayPalEvents::PAYPAL_CART_UPDATE, $payPalCartEvent);
}
}
/**
* @param $value
* @return bool
*/
protected function isNotBlank($value)
{
if (false === $value || (empty($value) && '0' != $value)) {
return false;
}
return true;
}
/**
* @return array The event names to listen to
*/
public static function getSubscribedEvents()
{
return [
TheliaEvents::ORDER_UPDATE_STATUS => [
['CancelPayPalTransaction', 128],
['updateStatus', 128],
],
TheliaEvents::ORDER_SEND_CONFIRMATION_EMAIL => ['sendConfirmationEmail', 129],
TheliaEvents::ORDER_SEND_NOTIFICATION_EMAIL => ['sendConfirmationEmail', 129],
TheliaEvents::ORDER_SET_PAYMENT_MODULE => ['checkPayPalMethod', 120],
PayPalEvents::PAYPAL_RECURSIVE_PAYMENT_CREATE => ['recursivePayment', 128]
];
}
}

View File

@@ -0,0 +1,67 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace PayPal\EventListeners;
use PayPal\Event\PayPalCartEvent;
use PayPal\Event\PayPalEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Class PayPalCartListener
* @package PayPal\EventListeners
*/
class PayPalCartListener implements EventSubscriberInterface
{
/**
* @param PayPalCartEvent $event
* @throws \Exception
* @throws \Propel\Runtime\Exception\PropelException
*/
public function createOrUpdate(PayPalCartEvent $event)
{
$event->getPayPalCart()->save();
}
/**
* @param PayPalCartEvent $event
* @throws \Exception
* @throws \Propel\Runtime\Exception\PropelException
*/
public function delete(PayPalCartEvent $event)
{
$event->getPayPalCart()->delete();
}
/**
* @return array The event names to listen to
*/
public static function getSubscribedEvents()
{
return [
PayPalEvents::PAYPAL_CART_CREATE => ['createOrUpdate', 128],
PayPalEvents::PAYPAL_CART_UPDATE => ['createOrUpdate', 128],
PayPalEvents::PAYPAL_CART_DELETE => ['delete', 128]
];
}
}

View File

@@ -0,0 +1,86 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace PayPal\EventListeners;
use PayPal\Event\PayPalCustomerEvent;
use PayPal\Event\PayPalEvents;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RequestStack;
/**
* Class PayPalCustomerListener
* @package PayPal\EventListeners
*/
class PayPalCustomerListener implements EventSubscriberInterface
{
/** @var RequestStack */
protected $requestStack;
/** @var EventDispatcher */
protected $dispatcher;
/**
* PayPalCustomerListener constructor.
* @param RequestStack $requestStack
* @param EventDispatcher $dispatcher
*/
public function __construct(RequestStack $requestStack, EventDispatcher $dispatcher)
{
$this->requestStack = $requestStack;
$this->dispatcher = $dispatcher;
}
/**
* @param PayPalCustomerEvent $event
* @throws \Exception
* @throws \Propel\Runtime\Exception\PropelException
*/
public function createOrUpdate(PayPalCustomerEvent $event)
{
$event->getPayPalCustomer()->save();
}
/**
* @param PayPalCustomerEvent $event
* @throws \Exception
* @throws \Propel\Runtime\Exception\PropelException
*/
public function delete(PayPalCustomerEvent $event)
{
$event->getPayPalCustomer()->delete();
}
/**
* @return array The event names to listen to
*/
public static function getSubscribedEvents()
{
return [
PayPalEvents::PAYPAL_CUSTOMER_CREATE => ['createOrUpdate', 128],
PayPalEvents::PAYPAL_CUSTOMER_UPDATE => ['createOrUpdate', 128],
PayPalEvents::PAYPAL_CUSTOMER_DELETE => ['delete', 128]
];
}
}

View File

@@ -0,0 +1,68 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace PayPal\EventListeners;
use PayPal\Event\PayPalEvents;
use PayPal\Event\PayPalOrderEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Class PayPalOrderListener
* @package PayPal\EventListeners
*/
class PayPalOrderListener implements EventSubscriberInterface
{
/**
* @param PayPalOrderEvent $event
* @throws \Exception
* @throws \Propel\Runtime\Exception\PropelException
*/
public function createOrUpdate(PayPalOrderEvent $event)
{
$event->getPayPalOrder()->save();
}
/**
* @param PayPalOrderEvent $event
* @throws \Exception
* @throws \Propel\Runtime\Exception\PropelException
*/
public function delete(PayPalOrderEvent $event)
{
$event->getPayPalOrder()->delete();
}
/**
* @return array The event names to listen to
*/
public static function getSubscribedEvents()
{
return [
PayPalEvents::PAYPAL_ORDER_CREATE => ['createOrUpdate', 128],
PayPalEvents::PAYPAL_ORDER_UPDATE => ['createOrUpdate', 128],
PayPalEvents::PAYPAL_ORDER_DELETE => ['delete', 128]
];
}
}

View File

@@ -0,0 +1,63 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace PayPal\EventListeners;
use PayPal\Event\PayPalEvents;
use PayPal\Event\PayPalPlanEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class PayPalPlanListener implements EventSubscriberInterface
{
/**
* @param PayPalPlanEvent $event
* @throws \Exception
* @throws \Propel\Runtime\Exception\PropelException
*/
public function createOrUpdate(PayPalPlanEvent $event)
{
$event->getPayPalPlan()->save();
}
/**
* @param PayPalPlanEvent $event
* @throws \Exception
* @throws \Propel\Runtime\Exception\PropelException
*/
public function delete(PayPalPlanEvent $event)
{
$event->getPayPalPlan()->delete();
}
/**
* @return array The event names to listen to
*/
public static function getSubscribedEvents()
{
return [
PayPalEvents::PAYPAL_PLAN_CREATE => ['createOrUpdate', 128],
PayPalEvents::PAYPAL_PLAN_UPDATE => ['createOrUpdate', 128],
PayPalEvents::PAYPAL_PLAN_DELETE => ['delete', 128]
];
}
}

View File

@@ -0,0 +1,63 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace PayPal\EventListeners;
use PayPal\Event\PayPalEvents;
use PayPal\Event\PayPalPlanifiedPaymentEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class PayPalPlanifiedPaymentListener implements EventSubscriberInterface
{
/**
* @param PayPalPlanifiedPaymentEvent $event
* @throws \Exception
* @throws \Propel\Runtime\Exception\PropelException
*/
public function createOrUpdate(PayPalPlanifiedPaymentEvent $event)
{
$event->getPayPalPlanifiedPayment()->save();
}
/**
* @param PayPalPlanifiedPaymentEvent $event
* @throws \Exception
* @throws \Propel\Runtime\Exception\PropelException
*/
public function delete(PayPalPlanifiedPaymentEvent $event)
{
$event->getPayPalPlanifiedPayment()->delete();
}
/**
* @return array The event names to listen to
*/
public static function getSubscribedEvents()
{
return [
PayPalEvents::PAYPAL_PLANIFIED_PAYMENT_CREATE => ['createOrUpdate', 128],
PayPalEvents::PAYPAL_PLANIFIED_PAYMENT_UPDATE => ['createOrUpdate', 128],
PayPalEvents::PAYPAL_PLANIFIED_PAYMENT_DELETE => ['delete', 128]
];
}
}

View File

@@ -0,0 +1,330 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace PayPal\Form;
use PayPal\PayPal;
use Symfony\Component\Validator\Constraints\GreaterThanOrEqual;
use Symfony\Component\Validator\Constraints\NotBlank;
use Thelia\Form\BaseForm;
/**
* Class ConfigurePaypal
* @package Paypal\Form
* @author Thelia <info@thelia.net>
*/
class ConfigurationForm extends BaseForm
{
const FORM_NAME = 'paypal_form_configure';
protected function buildForm()
{
$this->formBuilder
->add(
'login',
'text',
[
'constraints' => [ new NotBlank() ],
'label' => $this->translator->trans('login', [], PayPal::DOMAIN_NAME),
'label_attr' => [
'help' => $this->translator->trans('Your Paypal login', [], PayPal::DOMAIN_NAME)
]
]
)
->add(
'password',
'text',
[
'constraints' => [ new NotBlank() ],
'label' => $this->translator->trans('password', [], PayPal::DOMAIN_NAME),
'label_attr' => [
'help' => $this->translator->trans('Your Paypal password', [], PayPal::DOMAIN_NAME)
]
]
)
->add(
'merchant_id',
'text',
[
'label' => $this->translator->trans('Merchant ID', [], PayPal::DOMAIN_NAME),
'label_attr' => [
'help' => $this->translator->trans('The Paypal <a target="_blank" href="%url">identity merchant account</a>', ['%url' => 'https://www.paypal.com/businessprofile/settings/'], PayPal::DOMAIN_NAME)
]
]
)
->add(
'sandbox',
'checkbox',
[
'value' => 1,
'required' => false,
'label' => $this->translator->trans('Activate sandbox mode', [], PayPal::DOMAIN_NAME),
]
)
->add(
'sandbox_login',
'text',
[
'required' => false,
'label' => $this->translator->trans('login', [], PayPal::DOMAIN_NAME),
'label_attr' => [
'help' => $this->translator->trans('Your Paypal sandbox login', [], PayPal::DOMAIN_NAME)
]
]
)
->add(
'sandbox_password',
'text',
[
'required' => false,
'label' => $this->translator->trans('password', [], PayPal::DOMAIN_NAME),
'label_attr' => [
'help' => $this->translator->trans('Your Paypal sandbox password', [], PayPal::DOMAIN_NAME)
]
]
)
->add(
'sandbox_merchant_id',
'text',
[
'required' => false,
'label' => $this->translator->trans('Merchant ID', [], PayPal::DOMAIN_NAME),
'label_attr' => [
'help' => $this->translator->trans('The Paypal <a target="_blank" href="%url">identity merchant account</a>', ['%url' => 'https://www.paypal.com/businessprofile/settings/'], PayPal::DOMAIN_NAME)
]
]
)
->add(
'allowed_ip_list',
'textarea',
[
'required' => false,
'label' => $this->translator->trans('Allowed IPs in test mode', [], PayPal::DOMAIN_NAME),
'label_attr' => [
'help' => $this->translator->trans(
'List of IP addresses allowed to use this payment on the front-office when in test mode (your current IP is %ip). One address per line',
[ '%ip' => $this->getRequest()->getClientIp() ],
PayPal::DOMAIN_NAME
)
],
'attr' => [
'rows' => 3
]
]
)
->add(
'minimum_amount',
'text',
[
'constraints' => [
new NotBlank(),
new GreaterThanOrEqual(array('value' => 0))
],
'required' => false,
'label' => $this->translator->trans('Minimum order total', [], PayPal::DOMAIN_NAME),
'label_attr' => [
'help' => $this->translator->trans(
'Minimum order total in the default currency for which this payment method is available. Enter 0 for no minimum',
[],
PayPal::DOMAIN_NAME
)
]
]
)
->add(
'maximum_amount',
'text',
[
'constraints' => [
new NotBlank(),
new GreaterThanOrEqual(array('value' => 0))
],
'required' => false,
'label' => $this->translator->trans('Maximum order total', [], PayPal::DOMAIN_NAME),
'label_attr' => [
'help' => $this->translator->trans(
'Maximum order total in the default currency for which this payment method is available. Enter 0 for no maximum',
[],
PayPal::DOMAIN_NAME
)
]
]
)
->add(
'cart_item_count',
'text',
[
'constraints' => [
new NotBlank(),
new GreaterThanOrEqual(array('value' => 0))
],
'required' => false,
'label' => $this->translator->trans('Maximum items in cart', [], PayPal::DOMAIN_NAME),
'label_attr' => [
'help' => $this->translator->trans(
'Maximum number of items in the customer cart for which this payment method is available.',
[],
PayPal::DOMAIN_NAME
)
]
]
)
->add(
'method_paypal',
'checkbox',
[
'value' => 1,
'required' => false,
'label' => $this->translator->trans('Activate payment with PayPal account', [], PayPal::DOMAIN_NAME),
'label_attr' => [
'help' => $this->translator->trans(
'If checked, the order can be paid by PayPal account.',
[],
PayPal::DOMAIN_NAME
)
]
]
)
->add(
'method_paypal_with_in_context',
'checkbox',
[
'value' => 1,
'required' => false,
'label' => $this->translator->trans('Use InContext mode for classic PayPal payment', [], PayPal::DOMAIN_NAME),
'label_attr' => [
'help' => $this->translator->trans(
'If checked, a PayPal popup will be used to execute the payment.',
[],
PayPal::DOMAIN_NAME
)
]
]
)
->add(
'method_express_checkout',
'checkbox',
[
'value' => 1,
'required' => false,
'label' => $this->translator->trans('Activate Express Checkout payment with PayPal', [], PayPal::DOMAIN_NAME),
'label_attr' => [
'help' => $this->translator->trans(
'If checked, the order can be paid directly from cart.',
[],
PayPal::DOMAIN_NAME
)
]
]
)
->add(
'method_credit_card',
'checkbox',
[
'value' => 1,
'required' => false,
'label' => $this->translator->trans('Activate payment with credit card', [], PayPal::DOMAIN_NAME),
'label_attr' => [
'help' => $this->translator->trans(
'If checked, the order can be paid by credit card.',
[],
PayPal::DOMAIN_NAME
)
]
]
)
->add(
'method_planified_payment',
'checkbox',
[
'value' => 1,
'required' => false,
'label' => $this->translator->trans('Activate payment with planified payment', [], PayPal::DOMAIN_NAME),
'label_attr' => [
'help' => $this->translator->trans(
'If checked, the order can be paid by planified payement.',
[],
PayPal::DOMAIN_NAME
)
]
]
)
->add(
'send_confirmation_message_only_if_paid',
'checkbox',
[
'value' => 1,
'required' => false,
'label' => $this->translator->trans('Send order confirmation on payment success', [], PayPal::DOMAIN_NAME),
'label_attr' => [
'help' => $this->translator->trans(
'If checked, the order confirmation message is sent to the customer only when the payment is successful. The order notification is always sent to the shop administrator',
[],
PayPal::DOMAIN_NAME
)
]
]
)
->add(
'send_payment_confirmation_message',
'checkbox',
[
'value' => 1,
'required' => false,
'label' => $this->translator->trans('Send a payment confirmation e-mail', [], PayPal::DOMAIN_NAME),
'label_attr' => [
'help' => $this->translator->trans(
'If checked, a payment confirmation e-mail is sent to the customer.',
[],
PayPal::DOMAIN_NAME
)
]
]
)
->add(
'send_recursive_message',
'checkbox',
[
'value' => 1,
'required' => false,
'label' => $this->translator->trans('Send a recursive payment confirmation e-mail', [], PayPal::DOMAIN_NAME),
'label_attr' => [
'help' => $this->translator->trans(
'If checked, a payment confirmation e-mail is sent to the customer after each PayPal transaction.',
[],
PayPal::DOMAIN_NAME
)
]
]
)
;
}
/**
* @return string the name of your form. This name must be unique
*/
public function getName()
{
return self::FORM_NAME;
}
}

View File

@@ -0,0 +1,56 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace PayPal\Form;
/**
* Class PayPalFormFields
* @package PayPal\Form
*/
class PayPalFormFields
{
const FIELD_PAYMENT_MODULE = 'payment-module';
// \Thelia\Form\OrderPayment
const FIELD_PAYPAL_METHOD = 'paypal_method';
const FIELD_PAYPAL_PLANIFIED_PAYMENT = 'paypal_planified_payment';
// \Form\Type\PayPalCreditCardType
const FIELD_CARD_TYPE = 'card_type';
const FIELD_CARD_NUMBER = 'card_number';
const FIELD_CARD_EXPIRE_MONTH = 'card_expire_month';
const FIELD_CARD_EXPIRE_YEAR = 'card_expire_year';
const FIELD_CARD_CVV = 'card_cvv';
// \Form\PayPalPlanifiedPaymentForm
const FIELD_PP_ID = 'id';
const FIELD_PP_LOCALE = 'locale';
const FIELD_PP_TITLE = 'title';
const FIELD_PP_DESCRIPTION = 'description';
const FIELD_PP_FREQUENCY = 'frequency';
const FIELD_PP_FREQUENCY_INTERVAL = 'frequency_interval';
const FIELD_PP_CYCLE = 'cycle';
const FIELD_PP_MIN_AMOUNT = 'min_amount';
const FIELD_PP_MAX_AMOUNT = 'max_amount';
const FIELD_PP_POSITION = 'position';
}

View File

@@ -0,0 +1,191 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace PayPal\Form;
use PayPal\PayPal;
use PayPal\Service\PayPalAgreementService;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Validator\Constraints\GreaterThan;
use Symfony\Component\Validator\Constraints\GreaterThanOrEqual;
use Symfony\Component\Validator\Constraints\NotBlank;
use Thelia\Core\Translation\Translator;
use Thelia\Form\BaseForm;
class PayPalPlanifiedPaymentCreateForm extends BaseForm
{
const FORM_NAME = 'paypal_planified_payment_create_form';
/**
* @return null
*/
protected function buildForm()
{
/** @var \Thelia\Model\Lang $lang */
$lang = $this->getRequest()->getSession()->get('thelia.current.lang');
$this->formBuilder
->add(
PayPalFormFields::FIELD_PP_LOCALE,
HiddenType::class,
[
'constraints' => [
new NotBlank()
],
'required' => true,
'data' => $lang->getLocale(),
'label' => $this->trans('The locale of the planified payment'),
'label_attr' => ['for' => PayPalFormFields::FIELD_PP_LOCALE]
]
)
->add(
PayPalFormFields::FIELD_PP_TITLE,
TextType::class,
[
'constraints' => [
new NotBlank()
],
'required' => true,
'label' => $this->trans('The title of the planified payment'),
'label_attr' => ['for' => PayPalFormFields::FIELD_PP_TITLE]
]
)
->add(
PayPalFormFields::FIELD_PP_DESCRIPTION,
TextType::class,
[
'required' => false,
'label' => $this->trans('The description of the planified payment'),
'label_attr' => ['for' => PayPalFormFields::FIELD_PP_DESCRIPTION]
]
)
->add(
PayPalFormFields::FIELD_PP_FREQUENCY_INTERVAL,
'integer',
[
'label' => $this->trans('Frequency interval'),
'label_attr' => ['for' => PayPalFormFields::FIELD_PP_FREQUENCY_INTERVAL],
'required' => true,
'constraints' => [
new NotBlank(),
new GreaterThan(['value' => 0])
]
]
)
->add(
PayPalFormFields::FIELD_PP_FREQUENCY,
'choice',
[
'choices' => PayPalAgreementService::getAllowedPaymentFrequency(),
'label' => $this->trans('Frequency'),
'label_attr' => ['for' => PayPalFormFields::FIELD_PP_FREQUENCY],
'required' => true,
'constraints' => [
new NotBlank()
]
]
)
->add(
PayPalFormFields::FIELD_PP_CYCLE,
'integer',
[
'label' => $this->trans('Cycle'),
'label_attr' => ['for' => PayPalFormFields::FIELD_PP_CYCLE],
'required' => true,
'constraints' => [
new NotBlank(),
new GreaterThan(['value' => 0])
]
]
)
->add(
PayPalFormFields::FIELD_PP_MIN_AMOUNT,
'number',
[
'label' => $this->trans('Min amount'),
'label_attr' => [
'for' => PayPalFormFields::FIELD_PP_MIN_AMOUNT,
'help' => $this->trans("Let value to 0 if you don't want a minimum")
],
'required' => false,
'constraints' => [
new GreaterThanOrEqual(['value' => 0])
]
]
)
->add(
PayPalFormFields::FIELD_PP_MAX_AMOUNT,
'number',
[
'label' => $this->trans('Max amount'),
'label_attr' => [
'for' => PayPalFormFields::FIELD_PP_MAX_AMOUNT,
'help' => $this->trans("Let value to 0 if you don't want a maximum")
],
'required' => false,
'constraints' => [
new GreaterThanOrEqual(['value' => 0])
]
]
)
->add(
PayPalFormFields::FIELD_PP_POSITION,
'integer',
[
'label' => $this->trans('Position'),
'label_attr' => ['for' => PayPalFormFields::FIELD_PP_POSITION],
'required' => false
]
)
;
}
/**
* @return string the name of your form. This name must be unique
*/
public function getName()
{
return self::FORM_NAME;
}
/**
* Translates the given message.
*
* @param string $id The message id (may also be an object that can be cast to string)
* @param array $parameters An array of parameters for the message
* @param string|null $domain The domain for the message or null to use the default
*
* @throws \InvalidArgumentException If the locale contains invalid characters
*
* @return string The translated string
*/
protected function trans($id, array $parameters = [], $domain = null)
{
return Translator::getInstance()->trans(
$id,
$parameters,
$domain === null ? PayPal::DOMAIN_NAME : $domain
);
}
}

View File

@@ -0,0 +1,56 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace PayPal\Form;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Validator\Constraints\NotBlank;
class PayPalPlanifiedPaymentUpdateForm extends PayPalPlanifiedPaymentCreateForm
{
const FORM_NAME = 'paypal_planified_payment_update_form';
protected function buildForm()
{
parent::buildForm();
$this->formBuilder
->add(
PayPalFormFields::FIELD_PP_ID,
HiddenType::class,
[
'required' => true,
'label_attr' => ['for' => PayPalFormFields::FIELD_PP_ID],
'constraints' => [
new NotBlank()
]
]
)
;
}
public function getName()
{
return self::FORM_NAME;
}
}

View File

@@ -0,0 +1,265 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace PayPal\Form\Type;
use PayPal\Form\PayPalFormFields;
use PayPal\PayPal;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints\Callback;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Thelia\Core\Form\Type\AbstractTheliaType;
use Thelia\Core\Translation\Translator;
/**
* Class PayPalCreditCardType
* @package PayPal\Form\Type
*/
class PayPalCreditCardType extends AbstractTheliaType
{
const TYPE_NAME = 'paypal_credit_card_type';
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add(
PayPalFormFields::FIELD_CARD_TYPE,
'choice',
[
'choices' => $this->getTypes(),
'label' => Translator::getInstance()->trans('Card type', [], PayPal::DOMAIN_NAME),
'label_attr' => ['for' => PayPalFormFields::FIELD_CARD_TYPE],
'required' => false,
'constraints' => [
new Callback(
[
'methods' => [
[$this, 'verifyCardType']
],
]
)
]
]
)
->add(
PayPalFormFields::FIELD_CARD_NUMBER,
'text',
[
'label' => Translator::getInstance()->trans('Card number', [], PayPal::DOMAIN_NAME),
'label_attr' => ['for' => PayPalFormFields::FIELD_CARD_NUMBER],
'required' => false,
'constraints' => [
new Callback(
[
'methods' => [
[$this, 'verifyCardNumber']
],
]
)
]
]
)
->add(
PayPalFormFields::FIELD_CARD_EXPIRE_MONTH,
'choice',
[
'choices' => $this->getMonths(),
'label' => Translator::getInstance()->trans('Expire month', [], PayPal::DOMAIN_NAME),
'label_attr' => ['for' => PayPalFormFields::FIELD_CARD_EXPIRE_MONTH],
'required' => false,
'constraints' => [
new Callback(
[
'methods' => [
[$this, 'verifyCardExpireMonth']
],
]
)
]
]
)
->add(
PayPalFormFields::FIELD_CARD_EXPIRE_YEAR,
'choice',
[
'choices' => $this->getYears(),
'label' => Translator::getInstance()->trans('Expire year', [], PayPal::DOMAIN_NAME),
'label_attr' => ['for' => PayPalFormFields::FIELD_CARD_EXPIRE_YEAR],
'required' => false,
'constraints' => [
new Callback(
[
'methods' => [
[$this, 'verifyCardExpireYear']
],
]
)
]
]
)
->add(
PayPalFormFields::FIELD_CARD_CVV,
'text',
[
'label' => Translator::getInstance()->trans('CVV', [], PayPal::DOMAIN_NAME),
'label_attr' => ['for' => PayPalFormFields::FIELD_CARD_CVV],
'required' => false,
'constraints' => [
new Callback(
[
'methods' => [
[$this, 'verifyCardCVV']
],
]
)
]
]
)
;
}
/**
* @param $value
* @param ExecutionContextInterface $context
*/
public function verifyCardType($value, ExecutionContextInterface $context)
{
$this->checkNotBlank($value, $context);
}
/**
* @param $value
* @param ExecutionContextInterface $context
*/
public function verifyCardNumber($value, ExecutionContextInterface $context)
{
$this->checkNotBlank($value, $context);
}
/**
* @param $value
* @param ExecutionContextInterface $context
*/
public function verifyCardExpireMonth($value, ExecutionContextInterface $context)
{
$this->checkNotBlank($value, $context);
}
/**
* @param $value
* @param ExecutionContextInterface $context
*/
public function verifyCardExpireYear($value, ExecutionContextInterface $context)
{
$this->checkNotBlank($value, $context);
}
/**
* @param $value
* @param ExecutionContextInterface $context
*/
public function verifyCardCVV($value, ExecutionContextInterface $context)
{
$this->checkNotBlank($value, $context);
}
/**
* @param $value
* @param ExecutionContextInterface $context
*/
protected function checkNotBlank($value, ExecutionContextInterface $context)
{
$data = $context->getRoot()->getData();
if (isset($data[PayPalFormFields::FIELD_PAYMENT_MODULE]) && PayPal::getModuleId() === $data[PayPalFormFields::FIELD_PAYMENT_MODULE]) {
if (isset($data[PayPalFormFields::FIELD_PAYPAL_METHOD]) && PayPal::PAYPAL_METHOD_CREDIT_CARD === $data[PayPalFormFields::FIELD_PAYPAL_METHOD]) {
if (false === $value || (empty($value) && '0' != $value)) {
$context->addViolation(
Translator::getInstance()->trans('This value should not be blank', [], PayPal::DOMAIN_NAME)
);
}
}
}
}
/**
* @inheritDoc
*/
public function getName()
{
return self::TYPE_NAME;
}
/**
* @return array
*/
protected function getTypes()
{
return [
PayPal::CREDIT_CARD_TYPE_VISA => 'Visa',
PayPal::CREDIT_CARD_TYPE_MASTERCARD => 'MasterCard',
PayPal::CREDIT_CARD_TYPE_DISCOVER => 'Discover',
PayPal::CREDIT_CARD_TYPE_AMEX => 'Amex'
];
}
/**
* @return array
*/
protected function getMonths()
{
return [
1 => '01',
2 => '02',
3 => '03',
4 => '04',
5 => '05',
6 => '06',
7 => '07',
8 => '08',
9 => '09',
10 => '10',
11 => '11',
12 => '12'
];
}
/**
* @return array
*/
protected function getYears()
{
$actualYear = date("Y");
$years = [];
$years[(int)$actualYear] = $actualYear;
for ($i = 1; $i <= 10; $i++) {
$years[(int)($actualYear + $i)] = $actualYear + $i;
}
return $years;
}
}

View File

@@ -0,0 +1,95 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace PayPal\Hook;
use PayPal\Model\PaypalOrderQuery;
use PayPal\PayPal;
use PayPal\Service\Base\PayPalBaseService;
use Thelia\Core\Event\Hook\HookRenderEvent;
use Thelia\Core\Hook\BaseHook;
use Thelia\Model\ModuleConfig;
use Thelia\Model\ModuleConfigQuery;
/**
* Class BackHookManager
* @package PayPal\Hook
*/
class BackHookManager extends BaseHook
{
/**
* @param HookRenderEvent $event
*/
public function onModuleConfigure(HookRenderEvent $event)
{
$vars = [];
if (null !== $moduleConfigs = ModuleConfigQuery::create()->findByModuleId(PayPal::getModuleId())) {
/** @var ModuleConfig $moduleConfig */
foreach ($moduleConfigs as $moduleConfig) {
$vars[ $moduleConfig->getName() ] = $moduleConfig->getValue();
}
}
$vars['paypal_appid'] = PayPalBaseService::getLogin();
$vars['paypal_authend'] = PayPalBaseService::getMode();
$event->add(
$this->render('paypal/module-configuration.html', $vars)
);
}
/**
* @param HookRenderEvent $event
*/
public function onOrderEditPaymentModuleBottom(HookRenderEvent $event)
{
$templateData = $event->getArguments();
if (null !== $payPalOrder = PaypalOrderQuery::create()->findOneById($event->getArgument('order_id'))) {
$event->add(
$this->render(
'paypal/payment-information.html',
$templateData
)
);
}
}
/**
* @param HookRenderEvent $event
*/
public function onOrderEditJs(HookRenderEvent $event)
{
$templateData = $event->getArguments();
if (null !== $payPalOrder = PaypalOrderQuery::create()->findOneById($event->getArgument('order_id'))) {
$event->add(
$this->render(
'paypal/order-edit-js.html',
$templateData
)
);
}
}
}

View File

@@ -0,0 +1,208 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace PayPal\Hook;
use PayPal\Model\PaypalCartQuery;
use PayPal\PayPal;
use PayPal\Service\Base\PayPalBaseService;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Thelia\Core\Event\Hook\HookRenderEvent;
use Thelia\Core\Hook\BaseHook;
use Thelia\Core\HttpFoundation\Session\Session;
/**
* Class FrontHookManager
* @package PayPal\Hook
*/
class FrontHookManager extends BaseHook
{
/** @var RequestStack */
protected $requestStack;
/** @var ContainerInterface */
protected $container;
/**
* FrontHookManager constructor.
* @param RequestStack $requestStack
* @param ContainerInterface $container
*/
public function __construct(RequestStack $requestStack, ContainerInterface $container)
{
$this->requestStack = $requestStack;
$this->container = $container;
}
/**
* @param HookRenderEvent $event
*/
public function onLoginMainBottom(HookRenderEvent $event)
{
$templateData = $event->getArguments();
$templateData['paypal_appid'] = PayPalBaseService::getLogin();
$templateData['paypal_authend'] = PayPalBaseService::getMode();
$event->add(
$this->render(
'paypal/login-bottom.html',
$templateData
)
);
}
/**
* @param HookRenderEvent $event
*/
public function onOrderInvoicePaymentExtra(HookRenderEvent $event)
{
$templateData = $event->getArguments();
$templateData['method_paypal_with_in_context'] = PayPal::getConfigValue('method_paypal_with_in_context');
$event->add(
$this->render(
'paypal/order-invoice-payment-extra.html',
$templateData
)
);
}
/**
* @param HookRenderEvent $event
*/
public function onOrderInvoiceBottom(HookRenderEvent $event)
{
$templateData = $event->getArguments();
$templateData['paypal_mode'] = PayPalBaseService::getMode();
$templateData['paypal_merchantid'] = PayPalBaseService::getMerchantId();
$event->add(
$this->render(
'paypal/order-invoice-bottom.html',
$templateData
)
);
}
public function onOrderInvoiceJavascriptInitialization(HookRenderEvent $event)
{
$render = $this->render(
'paypal/order-invoice-js.html',
[
'module_id' => PayPal::getModuleId(),
]
);
$event->add($render);
}
/**
* @param HookRenderEvent $event
*/
public function onOrderPlacedAdditionalPaymentInfo(HookRenderEvent $event)
{
$templateData = $event->getArguments();
$event->add(
$this->render(
'paypal/order-placed-additional-payment-info.html',
$templateData
)
);
}
/**
* @param HookRenderEvent $event
*/
public function onCartBottom(HookRenderEvent $event)
{
$payPal = new PayPal();
$payPal->setContainer($this->container);
if (PayPal::getConfigValue('method_express_checkout') == 1 && $payPal->isValidPayment()) {
$templateData = $event->getArguments();
$templateData['paypal_mode'] = PayPalBaseService::getMode();
$templateData['paypal_merchantid'] = PayPalBaseService::getMerchantId();
$event->add(
$this->render(
'paypal/cart-bottom.html',
$templateData
)
);
}
}
/**
* @param HookRenderEvent $event
*/
public function onOrderDeliveryFormBottom(HookRenderEvent $event)
{
if ($this->isValidExpressCheckout()) {
$templateData = $event->getArguments();
$event->add(
$this->render(
'paypal/order-delivery-bottom.html',
$templateData
)
);
}
}
/**
* @param HookRenderEvent $event
*/
public function onOrderAfterJavascriptInclude(HookRenderEvent $event)
{
if ($this->isValidExpressCheckout()) {
$templateData = $event->getArguments();
$event->add(
$this->render(
'paypal/order-delivery-bottom-js.html',
$templateData
)
);
}
}
protected function isValidExpressCheckout()
{
$isValid = false;
/** @var Session $session */
$session = $this->requestStack->getCurrentRequest()->getSession();
$cart = $session->getSessionCart($this->dispatcher);
$payPal = new PayPal();
$payPal->setContainer($this->container);
if (PayPal::getConfigValue('method_express_checkout') == 1 && $payPal->isValidPayment()) {
if (null !== $payPalCart = PaypalCartQuery::create()->findOneById($cart->getId())) {
if ($payPalCart->getExpressPaymentId() && $payPalCart->getExpressPayerId() && $payPalCart->getExpressToken()) {
$isValid = true;
}
}
}
return $isValid;
}
}

View File

@@ -0,0 +1,45 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace PayPal\Hook;
use Thelia\Core\Event\Hook\HookRenderEvent;
use Thelia\Core\Hook\BaseHook;
class PdfHookManager extends BaseHook
{
/**
* @param HookRenderEvent $event
*/
public function onAfterPaymentModule(HookRenderEvent $event)
{
$templateData = $event->getArguments();
$event->add(
$this->render(
'paypal/after-payment-module.html',
$templateData
)
);
}
}

View File

@@ -0,0 +1,92 @@
<?php
return array(
'Accept payments' => 'Accept payments',
'Account Information' => 'Account Information',
'Add Webhook' => 'Cliquer sur Add Webhook',
'Add a planified payment' => 'Ajouter un paiement planifié',
'Address Information' => 'Address Information',
'Allow the customers who haven\'t yet confirmed their email address with PayPal, to log in to your app' => 'Allow the customers who haven\'t yet confirmed their email address with PayPal, to log in to your app',
'And configure it like the SandBox' => 'Et remplissez le formulaire comme pour la SandBox',
'Automatic PayPal logs' => 'Logs automatiques de PayPal',
'Billing agreements' => 'Billing agreements',
'Check' => 'Cocher',
'Click on Create App' => ' Cliquer sur Create App ',
'Click on the Live Button' => 'Cliquer sur le button "Live"',
'Configuration' => 'Configuration',
'Copy & Paste the Client ID in the form below' => 'Copier & Coller le Client ID dans le formulaire ci-dessous',
'Copy & Paste the Client SECRET in the form below' => 'Copier & Coller le Client SECRET dans le formulaire ci-dessous',
'Create REST API apps <a target=\'_blank\' href=\'https://developer.paypal.com/developer/applications/\'>here</a>' => 'Créer une REST API apps <a target=\'_blank\' href=\'https://developer.paypal.com/developer/applications/\'>ici</a> ',
'Create a new planified payment' => 'Créer un nouveau paiement récurrent',
'Create this planified payment' => 'Créer ce paiement récurrent',
'critical_100' => 'DEBUG',
'critical_200' => 'INFO',
'critical_250' => 'NOTICE',
'critical_300' => 'WARNING',
'critical_400' => 'ERROR',
'critical_500' => 'CRITICAL',
'critical_550' => 'ALERT',
'critical_600' => 'EMERGENCY',
'Customer ID' => 'Client ID',
'Cycle' => 'Cycle',
'Date' => 'Date',
'Delete planified payment' => 'Supprimer paiement récurrent',
'Delete this planified payment' => 'Supprimer ce paiement récurrent',
'Details' => 'Détails',
'Do you really want to delete this planified payment ?' => 'Voulez-vous vraiment supprimer ce paiement récurrent ?',
'Edit planified payment' => 'Modifier un paiement récurrent',
'Edit planified payment %title' => 'Modifier du paiement récurrent "%title" ',
'Edit this customer' => 'Modifier ce client',
'Edit this planified payment' => 'Modifier ce paiement récurrent',
'Editing planified payment "%title"' => 'Modification du paiement récurrent "%title" ',
'Fill the fields : App Name & Sandbox developer account' => 'Remplir les champs : App Name & Sandbox developer account ',
'Frequency' => 'Fréquence',
'Frequency interval' => 'Interval de la fréquence',
'Future Payments' => 'Future Payments',
'General configuration' => 'Configuration générale',
'General description' => 'Description générale',
'Global informations of this planified payment' => 'Informations générales de ce paiement récurrent',
'Help' => 'Aide',
'Home' => 'Accueil',
'How to configure Plannified payment' => 'Comment configurer un paiement récurrent',
'In SANDBOX APP SETTINGS' => 'Dans la section SANDBOX APP SETTINGS ',
'In SANDBOX WEBHOOKS' => 'Dans la section SANDBOX WEBHOOKS',
'In your PayPal page API configuration' => 'Dans votre page de configuration de votre API',
'Invoicing' => 'Invoicing',
'Level' => 'Niveau',
'List of planified payments' => 'Liste des paiements récurrents',
'Log' => 'Log',
'Log In on <a target=\'_blank\' href=\'https://developer.paypal.com\'>developer.paypal.com</a>' => 'Se connecter sur <a target=\'_blank\' href=\'https://developer.paypal.com\'>https://developer.paypal.com</a> ',
'Log In with PayPal' => 'Log In with PayPal',
'Max amount' => 'Montant maximum',
'Min amount' => 'Montant minium',
'New recursive invoice from order %id' => 'Nouvelle commande récursive créée à partir de la commande %id',
'No planified payment has been created yet. Click the + button to create one.' => 'Aucun paiement récurrent trouvé. Cliquer sur le bouton + ci-dessu pour en créer un',
'None' => 'Aucun',
'Order ID' => 'Commande ID',
'PayPal Here' => 'PayPal Here',
'Payment configuration' => 'Configuration paiement',
'Payouts' => 'Payouts',
'Personal Information' => 'Personal Information',
'Planified payment' => 'Paiement récurrent',
'Planified payment configuration' => 'Configuration paiement récurrent',
'Planified payment created on %date_create. Last modification: %date_change' => 'Paiement récurrent créé le %date_create. Dernière modification : %date_change ',
'Planified payments' => 'Paiements récurrents',
'Production configuration' => 'Configuration mode Production',
'Return URL' => ' Return URL ',
'SandBox configuration' => 'Configuration mode Bac à Sable',
'See webhook details' => 'Voir détails du webhook',
'That\'s it !' => 'Et voilà !',
'These planned payments will appear in step 4 of the purchase tunnel when selecting the payment method.' => 'Ces paiements récurrents apparaitront à l\'étape 4 du tunnel d\'achat lors de la sélection du moyen de paiement.',
'This feature uses PayPal\'s Billing Plan and Agreement. It allows debiting a client recursively directly from PayPal.' => 'Cette fonctionnalité se sert des Billing Plan et Agreement de PayPal. Elle permet de débiter un client de manière récursive directement depuis PayPal.',
'This informations can be found directly in concerned order details.' => 'Ces informations peuvent se retrouver directement sur les détails des commandes concernées.',
'This is where we log all the transactions made with PayPal. PayPal webhooks also automatically feed these logs.' => 'C\'est ici que nous loggons l\'ensemble des transactions réalisées avec PayPal. Les webhooks de PayPal viennent aussi alimenter automatiquement ces logs.',
'This method use PayPal webhooks and works only in HTTPS !' => 'Cette méthode utilise les WEBHOOKs de PayPal et ne fonctionne donc QUE ET UNIQUEMENT QUE en HTTPS !',
'This method works only with PayPal PRO UK account. Please contact PayPal to upgrade your account if you need this service. For more informations, go <a target="_blank" href="https://developer.paypal.com/docs/integration/direct/payments/accept-credit-cards/">here</a>' => 'Ce moyen de paiement ne fonctionne QUE ET UNIQUEMENT QUE si vous avez un compte PayPal PRO UK. Merci de contacter PayPal pour mettre à jour votre compte si vous avez besoin de ce service. Pour plus d\'informations, <a target="_blank" href="https://developer.paypal.com/docs/integration/direct/payments/accept-credit-cards/">rendez-vous ici</a>',
'This urls can take 3 hours to be taken in consideration' => ' Ces urls peuvent mettre 3 heures pour être prises en considération',
'Title' => 'Titre',
'Use Seamless Checkout' => 'Use Seamless Checkout',
'You can <a href="%url">edit the payment confirmation email</a> sent to the customer after a successful payment.' => 'Vous pouvez <a href="%url">modifier l\'email de confirmation de paiement</a> envoyé au client après un paiement réalisé avec succès.',
'You can add some planified payment <a href="%url">here</a>.' => 'Vous pouvez ajouter des paiements récurrents <a href="%url">ici</a>. ',
'critical_{$log->getLevel()}' => 'critical_{$log->getLevel()}',
);

View File

@@ -0,0 +1,4 @@
<?php
return array(
// 'an english string' => 'The displayed english string',
);

View File

@@ -0,0 +1,76 @@
<?php
return array(
'Activate Express Checkout payment with PayPal' => 'Activer le paiement : "PAYPAL EXPRESS"',
'Activate payment with PayPal account' => 'Activer le paiement par : "PAYPAL"',
'Activate payment with credit card' => 'Activer le paiement par : "CARTE BANCAIRE"',
'Activate payment with planified payment' => 'Activer le paiement par : "PAIEMENT RECURRENT"',
'Activate sandbox mode' => 'Activer le mode Bac à Sable',
'Allowed IPs in test mode' => 'IP autorisées pour le mode Bac à sable',
'CVV' => 'Code secret (3 chiffres)',
'Card number' => 'Numéro de la carte',
'Card type' => 'Type de carte',
'Credit card is invalid' => 'Carte bancaire invalide',
'Cycle' => 'Cycle',
'Expire month' => 'Mois d\'expiration',
'Expire year' => 'Année d\'expiration',
'Express checkout begin with cart %id' => 'Début du paiement EXPRESS CHECKOUT avec la panier : %id',
'Express checkout failed in expressCheckoutOkAction() function' => 'Echec de la méthode Express Checkout de PayPal dans la function expressCheckoutOkAction()',
'Express Checkout login failed' => 'Echec de la connexion avec EXPRESS CHECKOUT depuis le panier',
'Frequency' => 'Fréquence',
'Frequency interval' => 'Interval de la fréquence',
'If checked, a payment confirmation e-mail is sent to the customer after each PayPal transaction.' => 'Si cochée, un mail de confirmation de paiement sera envoyés grâce aux webhook directement rattachés à PayPal',
'If checked, a payment confirmation e-mail is sent to the customer.' => 'Si cochée, le client sera informé dès que sa commande passera en payée.',
'If checked, a PayPal popup will be used to execute the payment.' => 'Si cochée, le paiement se déroulera via une popup PayPal pour rester sur le site marchand.',
'If checked, the order can be paid by PayPal account.' => 'Si cochée, la commande pourra être payée par un simple compte PayPal',
'If checked, the order can be paid by credit card.' => 'Si cochée, la commande pourra être payée par carte bancaire (PayPal se chargera de vérifier sa validité)',
'If checked, the order can be paid by planified payement.' => 'Si cochée, la commande pourra être payée par paiement récurrent (PayPal agreement)',
'If checked, the order can be paid directly from cart.' => 'Si cochée, la commande pourra être payée directement depuis le panier',
'If checked, the order confirmation message is sent to the customer only when the payment is successful. The order notification is always sent to the shop administrator' => 'Si cochée, le mail de confirmation de commande ne sera pas envoyé au client dès que celui-ci cliquera sur l\'une des méthodes de paiement de PayPal',
'Invalid charge type send to create charge model' => 'Paramètre "type" invalide pour générer un "Charge Model"',
'Invalid fail action send to create merchant preference' => 'Paramètre "fail action" invalide pour générer un "Merchant Preference"',
'Invalid number of charge models send to create payment definition' => 'Nombre de "Charge Models" insuffisant pour générer un "Payment Definition"',
'Invalid number of payment definition send to generate billing plan' => 'Nombre de "Payment definition" insuffisant pour générer un "Billing Plan"',
'Invalid payment frequency send to create payment definition' => 'Paramètre "frequency" invalide pour générer un "Payment Definition"',
'Invalid payment type send to create payment definition' => 'Paramètre "type" invalide pour générer un "Payment Definition"',
'Invalid planified payment id : %id' => 'ID du paiement récurrent incorrect : %id',
'Invalid type send to generate billing plan' => 'Paramètre "type" invalide pour générer un "Billing Plan"',
'Let value to 0 if you don\'t want a maximum' => 'Laisser 0 si vous ne voulez pas de maximum',
'Let value to 0 if you don\'t want a minimum' => 'Laisser 0 si vous ne voulez pas de minimum',
'List of IP addresses allowed to use this payment on the front-office when in test mode (your current IP is %ip). One address per line' => 'Liste des adresses IP autorisées pour payer en Front lorsque le mmode Bac à Sable est activé (votre adresse IP actuelle est %ip). Une adresse IP par ligne.',
'Max amount' => 'Montant maximum',
'Maximum items in cart' => 'Nombre d\'articles maximum dans le panier',
'Maximum number of items in the customer cart for which this payment method is available.' => 'Nombre maximum d\'articles dans le panier pour que le moyen de paiement soit valide.',
'Maximum order total' => 'Montant maximum de la commande',
'Maximum order total in the default currency for which this payment method is available. Enter 0 for no maximum' => 'Montant maximum de la commande dans la devise courante pour autoriser le paiement. Mettre 0 pour ne pas avoir de maximum.',
'Merchant ID' => 'Identifiant du marchand',
'Method agreementOkAction => One of this parameter is invalid : $token = %token, $orderId = %order_id' => 'Method agreementOkAction => L\'un de ces paramètres est incorrecte : $token = %token, $orderId = %order_id',
'Method okAction => One of this parameter is invalid : $payerId = %payer_id, $orderId = %order_id' => 'Method okAction => L\'un de ces paramètres est incorrecte : $payerId = %payer_id, $orderId = %order_id',
'Min amount' => 'Montant minium',
'Minimum order total' => 'Montant minimum de la commande',
'Minimum order total in the default currency for which this payment method is available. Enter 0 for no minimum' => ' Montant minimum de la commande dans la devise courante pour autoriser le paiement. Mettre 0 pour ne pas avoir de minimum.',
'Order address no found to generate PayPal shipping address' => 'Adresse de la commande non trouvée pour générer l\'adresse de livraison PayPal',
'Order created with success in PayPal with method : %method' => 'Commande créée avec succès success via PayPal avec la méthode : %method ',
'Order failed with method : %method' => 'Echec du paiement avec la méthode : %method',
'Order payed with success in PayPal with method : %method' => 'Commande créée avec succès avec PayPal avec la méthode : %method ',
'Order payed with success with method : %method' => 'Paiement réalisé avec succès avec la méthode : %method',
'PayPal method' => 'Méthode PayPal',
'Paypal configuration' => 'Configuration PayPal',
'Position' => 'Position',
'Send a payment confirmation e-mail' => 'Envoyer le mail de confirmation de paiement',
'Send a recursive payment confirmation e-mail' => 'Envoyer le mail de confirmation de paiement pour les commandes récursives',
'Send order confirmation on payment success' => 'Bloquer le mail de confirmation de commande (mail envoyé dès qu\'une commande est créée même si elle n\'est pas payée)',
'The Paypal <a target="_blank" href="%url">identity merchant account</a>' => 'L\'indentifiant PayPal unique du <a target="_blank" href="%url">compte marchand</a> ',
'The delivery module is not valid.' => 'Le module de transport n\'est pas valide.',
'The description of the planified payment' => 'La description du paiement récurrent',
'The locale of the planified payment' => 'La locale du paiement récurrent',
'The title of the planified payment' => 'Le titre du paiement récurrent',
'This value should not be blank' => 'Cette valeur ne doit pas être vide',
'Use InContext mode for classic PayPal payment' => 'Utiliser le mode InContext pour le payment classic PayPal',
'Your Paypal login' => 'Client ID',
'Your Paypal password' => 'Client SECRET',
'Your Paypal sandbox login' => 'Client ID',
'Your Paypal sandbox password' => 'Client SECRET',
'login' => 'Client ID',
'password' => 'Client SECRET',
);

View File

@@ -0,0 +1,12 @@
<?php
return array(
'DAY' => 'jours',
'MONTH' => 'Mois',
'Finish payment with PayPal' => 'Terminer le paiement avec PayPal',
'Payment in %x times every %frequency_interval %frequency' => 'Paiement en %x fois, tout les %frequency_interval %frequency',
'Planified payment' => 'Paiement récurrent',
'planified_payment' => 'Paiement récurrent',
'WEEK' => 'Semaines',
'YEAR' => 'Années',
);

View File

@@ -0,0 +1,10 @@
<?php
return array(
'DAY' => 'Jours',
'MONTH' => 'Mois',
'Payment in %x times every %frequency_interval %frequency' => 'Paiement en %x fois, tout les %frequency_interval %frequency',
'Planified payment' => 'Paiement récurrent',
'WEEK' => 'Semaines',
'YEAR' => 'Années',
);

View File

@@ -0,0 +1,154 @@
<?php
/**
* Created by PhpStorm.
* User: guigit
* Date: 30/01/2017
* Time: 14:08
*/
namespace PayPal\Loop;
use PayPal\Model\PaypalLog;
use PayPal\Model\PaypalLogQuery;
use Propel\Runtime\ActiveQuery\Criteria;
use Thelia\Core\Template\Element\BaseLoop;
use Thelia\Core\Template\Element\LoopResult;
use Thelia\Core\Template\Element\LoopResultRow;
use Thelia\Core\Template\Element\PropelSearchLoopInterface;
use Thelia\Core\Template\Loop\Argument\Argument;
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
/**
* Class PayPalPlanifiedPaymentLoop
* @package PayPal\Loop
*
* @method int getOrderId()
* @method int getCustomerId()
* @method string getChannel()
* @method string getLevel()
* @method string[] getOrder()
*/
class PayPalLogLoop extends BaseLoop implements PropelSearchLoopInterface
{
// Allow to use substitution CREATED_AT, UPDATED_AT in loop
protected $timestampable = true;
/**
* @param LoopResult $loopResult
*
* @return LoopResult
*/
public function parseResults(LoopResult $loopResult)
{
/**
* @var PaypalLog $model
*/
foreach ($loopResult->getResultDataCollection() as $model) {
$row = new LoopResultRow($model);
$row->set('log', $model);
$this->addOutputFields($row, $model);
$loopResult->addRow($row);
}
return $loopResult;
}
/**
* @return PaypalLogQuery
*/
public function buildModelCriteria()
{
$query = new PaypalLogQuery();
if (null != $orderId = $this->getOrderId()) {
$query->filterByOrderId($orderId);
}
if (null != $customerId = $this->getCustomerId()) {
$query->filterByCustomerId($customerId);
}
if (null != $channel = $this->getChannel()) {
$query->filterByChannel($channel);
}
if (null != $level = $this->getLevel()) {
$query->filterByLevel($level);
}
$this->buildModelCriteriaOrder($query);
$query->groupById();
return $query;
}
/**
* @param PaypalLogQuery $query
*/
protected function buildModelCriteriaOrder(PaypalLogQuery $query)
{
foreach ($this->getOrder() as $order) {
switch ($order) {
case 'id':
$query->orderById();
break;
case 'id-reverse':
$query->orderById(Criteria::DESC);
break;
case 'order-id':
$query->orderById();
break;
case 'order-id-reverse':
$query->orderById(Criteria::DESC);
break;
case 'customer-id':
$query->addAscendingOrderByColumn('i18n_TITLE');
break;
case 'customer-id-reverse':
$query->addDescendingOrderByColumn('i18n_TITLE');
break;
case 'date':
$query->orderByCreatedAt();
break;
case 'date-reverse':
$query->orderByCreatedAt(Criteria::DESC);
break;
default:
$query->orderById();
break;
}
}
}
/**
* @return \Thelia\Core\Template\Loop\Argument\ArgumentCollection
*/
protected function getArgDefinitions()
{
return new ArgumentCollection(
Argument::createIntTypeArgument('order_id'),
Argument::createIntTypeArgument('customer_id'),
Argument::createAnyTypeArgument('channel'),
Argument::createIntTypeArgument('level'),
Argument::createEnumListTypeArgument(
'order',
[
'id',
'id-reverse',
'order-id',
'order-id-reverse',
'customer-id',
'customer-id-reverse',
'date',
'date-reverse',
],
'id'
)
);
}
}

View File

@@ -0,0 +1,109 @@
<?php
/**
* Created by PhpStorm.
* User: guigit
* Date: 20/01/2017
* Time: 11:50
*/
namespace PayPal\Loop;
use PayPal\Model\PaypalOrder;
use PayPal\Model\PaypalOrderQuery;
use Propel\Runtime\ActiveQuery\Criteria;
use Thelia\Core\Template\Element\BaseLoop;
use Thelia\Core\Template\Element\LoopResult;
use Thelia\Core\Template\Element\LoopResultRow;
use Thelia\Core\Template\Element\PropelSearchLoopInterface;
use Thelia\Core\Template\Loop\Argument\Argument;
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
/**
* Class PayPalOrderLoop
* @package PayPal\Loop
*
* @method int getId()
* @method string[] getOrder()
*/
class PayPalOrderLoop extends BaseLoop implements PropelSearchLoopInterface
{
// Allow to use substitution CREATED_AT, UPDATED_AT in loop
protected $timestampable = true;
/**
* @param LoopResult $loopResult
*
* @return LoopResult
*/
public function parseResults(LoopResult $loopResult)
{
/**
* @var PaypalOrder $model
*/
foreach ($loopResult->getResultDataCollection() as $model) {
$row = new LoopResultRow($model);
$row->set('paypal_order', $model);
$this->addOutputFields($row, $model);
$loopResult->addRow($row);
}
return $loopResult;
}
/**
* @return PaypalOrderQuery
*/
public function buildModelCriteria()
{
$query = new PaypalOrderQuery();
if (null != $id = $this->getId()) {
$query->filterById($id);
}
$this->buildModelCriteriaOrder($query);
return $query;
}
/**
* @param PaypalOrderQuery $query
*/
protected function buildModelCriteriaOrder(PaypalOrderQuery $query)
{
foreach ($this->getOrder() as $order) {
switch ($order) {
case 'id':
$query->orderById();
break;
case 'id-reverse':
$query->orderById(Criteria::DESC);
break;
default:
break;
}
}
}
/**
* @return \Thelia\Core\Template\Loop\Argument\ArgumentCollection
*/
protected function getArgDefinitions()
{
return new ArgumentCollection(
Argument::createIntListTypeArgument('id'),
Argument::createEnumListTypeArgument(
'order',
[
'id',
'id-reverse'
],
'id'
)
);
}
}

View File

@@ -0,0 +1,133 @@
<?php
namespace PayPal\Loop;
use PayPal\Model\PaypalPlanifiedPayment;
use PayPal\Model\PaypalPlanifiedPaymentQuery;
use Propel\Runtime\ActiveQuery\Criteria;
use Thelia\Core\Template\Element\BaseI18nLoop;
use Thelia\Core\Template\Element\LoopResult;
use Thelia\Core\Template\Element\LoopResultRow;
use Thelia\Core\Template\Element\PropelSearchLoopInterface;
use Thelia\Core\Template\Loop\Argument\Argument;
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
/**
* Class PayPalPlanifiedPaymentLoop
* @package PayPal\Loop
*
* @method int getId()
* @method string[] getOrder()
*/
class PayPalPlanifiedPaymentLoop extends BaseI18nLoop implements PropelSearchLoopInterface
{
// Allow to use substitution CREATED_AT, UPDATED_AT in loop
protected $timestampable = true;
/**
* @param LoopResult $loopResult
*
* @return LoopResult
*/
public function parseResults(LoopResult $loopResult)
{
/** @var \Thelia\Model\Lang $lang */
$lang = $this->getCurrentRequest()->getSession()->get('thelia.current.lang');
/**
* @var PaypalPlanifiedPayment $model
*/
foreach ($loopResult->getResultDataCollection() as $model) {
$model->getTranslation($lang->getLocale());
$row = new LoopResultRow($model);
$row->set('planifiedPayment', $model);
$this->addOutputFields($row, $model);
$loopResult->addRow($row);
}
return $loopResult;
}
/**
* @return PaypalPlanifiedPaymentQuery
*/
public function buildModelCriteria()
{
$query = new PaypalPlanifiedPaymentQuery();
if (null != $id = $this->getId()) {
$query->filterById($id);
}
/* manage translations */
$this->configureI18nProcessing(
$query,
array(
'TITLE',
'DESCRIPTION'
)
);
$this->buildModelCriteriaOrder($query);
$query->groupById();
return $query;
}
/**
* @param PaypalPlanifiedPaymentQuery $query
*/
protected function buildModelCriteriaOrder(PaypalPlanifiedPaymentQuery $query)
{
foreach ($this->getOrder() as $order) {
switch ($order) {
case 'id':
$query->orderById();
break;
case 'id-reverse':
$query->orderById(Criteria::DESC);
break;
case 'position':
$query->orderById();
break;
case 'position-reverse':
$query->orderById(Criteria::DESC);
break;
case 'title':
$query->addAscendingOrderByColumn('i18n_TITLE');
break;
case 'title-reverse':
$query->addDescendingOrderByColumn('i18n_TITLE');
break;
default:
$query->orderById();
break;
}
}
}
/**
* @return \Thelia\Core\Template\Loop\Argument\ArgumentCollection
*/
protected function getArgDefinitions()
{
return new ArgumentCollection(
Argument::createIntListTypeArgument('id'),
Argument::createEnumListTypeArgument(
'order',
[
'id',
'id-reverse',
'position',
'position-reverse',
'title',
'title-reverse',
],
'id'
)
);
}
}

View File

@@ -0,0 +1,48 @@
<?php
namespace PayPal\Model;
use PayPal\Model\Base\PaypalCart as BasePaypalCart;
use Propel\Runtime\Connection\ConnectionInterface;
use Propel\Runtime\Exception\PropelException;
use Thelia\Model\Cart;
use Thelia\Model\CartQuery;
class PaypalCart extends BasePaypalCart
{
/**
* Get the associated ChildCart object
*
* @param ConnectionInterface $con Optional Connection object.
* @return Cart The associated ChildCart object.
* @throws PropelException
*/
public function getCart(ConnectionInterface $con = null)
{
if ($this->aCart === null && ($this->id !== null)) {
$this->aCart = CartQuery::create()->findPk($this->id, $con);
}
return $this->aCart;
}
/**
* Declares an association between this object and a ChildCart object.
*
* @param Cart $cart
* @return \PayPal\Model\PaypalCart The current object (for fluent API support)
* @throws PropelException
*/
public function setCart(Cart $cart = null)
{
if ($cart === null) {
$this->setId(NULL);
} else {
$this->setId($cart->getId());
}
$this->aCart = $cart;
return $this;
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace PayPal\Model;
use PayPal\Model\Base\PaypalCartQuery as BasePaypalCartQuery;
/**
* Skeleton subclass for performing query and update operations on the 'paypal_cart' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
*/
class PaypalCartQuery extends BasePaypalCartQuery
{
} // PaypalCartQuery

View File

@@ -0,0 +1,52 @@
<?php
namespace PayPal\Model;
use PayPal\Api\OpenIdUserinfo;
use PayPal\Model\Base\PaypalCustomer as BasePaypalCustomer;
use Propel\Runtime\Connection\ConnectionInterface;
use Propel\Runtime\Exception\PropelException;
use Thelia\Model\Customer;
use Thelia\Model\CustomerQuery;
class PaypalCustomer extends BasePaypalCustomer
{
/** @var OpenIdUserinfo */
protected $openIdUserinfo;
/**
* Get the associated ChildCustomer object
*
* @param ConnectionInterface $con Optional Connection object.
* @return Customer The associated ChildCustomer object.
* @throws PropelException
*/
public function getCustomer(ConnectionInterface $con = null)
{
if ($this->aCustomer === null && ($this->id !== null)) {
$this->aCustomer = CustomerQuery::create()->findPk($this->id, $con);
}
return $this->aCustomer;
}
/**
* Declares an association between this object and a ChildCustomer object.
*
* @param Customer $customer
* @return \PayPal\Model\PaypalCustomer The current object (for fluent API support)
* @throws PropelException
*/
public function setCustomer(Customer $customer = null)
{
if ($customer === null) {
$this->setId(NULL);
} else {
$this->setId($customer->getId());
}
$this->aCustomer = $customer;
return $this;
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace PayPal\Model;
use PayPal\Model\Base\PaypalCustomerQuery as BasePaypalCustomerQuery;
/**
* Skeleton subclass for performing query and update operations on the 'paypal_customer' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
*/
class PaypalCustomerQuery extends BasePaypalCustomerQuery
{
} // PaypalCustomerQuery

View File

@@ -0,0 +1,10 @@
<?php
namespace PayPal\Model;
use PayPal\Model\Base\PaypalLog as BasePaypalLog;
class PaypalLog extends BasePaypalLog
{
}

View File

@@ -0,0 +1,21 @@
<?php
namespace PayPal\Model;
use PayPal\Model\Base\PaypalLogQuery as BasePaypalLogQuery;
/**
* Skeleton subclass for performing query and update operations on the 'paypal_log' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
*/
class PaypalLogQuery extends BasePaypalLogQuery
{
} // PaypalLogQuery

View File

@@ -0,0 +1,48 @@
<?php
namespace PayPal\Model;
use PayPal\Model\Base\PaypalOrder as BasePaypalOrder;
use Propel\Runtime\Connection\ConnectionInterface;
use Propel\Runtime\Exception\PropelException;
use Thelia\Model\Order;
use Thelia\Model\OrderQuery;
class PaypalOrder extends BasePaypalOrder
{
/**
* Get the associated ChildOrder object
*
* @param ConnectionInterface $con Optional Connection object.
* @return Order The associated ChildOrder object.
* @throws PropelException
*/
public function getOrder(ConnectionInterface $con = null)
{
if ($this->aOrder === null && ($this->id !== null)) {
$this->aOrder = OrderQuery::create()->findPk($this->id, $con);
}
return $this->aOrder;
}
/**
* Declares an association between this object and a ChildOrder object.
*
* @param Order $order
* @return \PayPal\Model\PaypalOrder The current object (for fluent API support)
* @throws PropelException
*/
public function setOrder(Order $order = null)
{
if ($order === null) {
$this->setId(NULL);
} else {
$this->setId($order->getId());
}
$this->aOrder = $order;
return $this;
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace PayPal\Model;
use PayPal\Model\Base\PaypalOrderQuery as BasePaypalOrderQuery;
/**
* Skeleton subclass for performing query and update operations on the 'paypal_order' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
*/
class PaypalOrderQuery extends BasePaypalOrderQuery
{
} // PaypalOrderQuery

View File

@@ -0,0 +1,10 @@
<?php
namespace PayPal\Model;
use PayPal\Model\Base\PaypalPlan as BasePaypalPlan;
class PaypalPlan extends BasePaypalPlan
{
}

View File

@@ -0,0 +1,21 @@
<?php
namespace PayPal\Model;
use PayPal\Model\Base\PaypalPlanQuery as BasePaypalPlanQuery;
/**
* Skeleton subclass for performing query and update operations on the 'paypal_plan' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
*/
class PaypalPlanQuery extends BasePaypalPlanQuery
{
} // PaypalPlanQuery

View File

@@ -0,0 +1,10 @@
<?php
namespace PayPal\Model;
use PayPal\Model\Base\PaypalPlanifiedPayment as BasePaypalPlanifiedPayment;
class PaypalPlanifiedPayment extends BasePaypalPlanifiedPayment
{
}

View File

@@ -0,0 +1,10 @@
<?php
namespace PayPal\Model;
use PayPal\Model\Base\PaypalPlanifiedPaymentI18n as BasePaypalPlanifiedPaymentI18n;
class PaypalPlanifiedPaymentI18n extends BasePaypalPlanifiedPaymentI18n
{
}

View File

@@ -0,0 +1,21 @@
<?php
namespace PayPal\Model;
use PayPal\Model\Base\PaypalPlanifiedPaymentI18nQuery as BasePaypalPlanifiedPaymentI18nQuery;
/**
* Skeleton subclass for performing query and update operations on the 'paypal_planified_payment_i18n' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
*/
class PaypalPlanifiedPaymentI18nQuery extends BasePaypalPlanifiedPaymentI18nQuery
{
} // PaypalPlanifiedPaymentI18nQuery

View File

@@ -0,0 +1,21 @@
<?php
namespace PayPal\Model;
use PayPal\Model\Base\PaypalPlanifiedPaymentQuery as BasePaypalPlanifiedPaymentQuery;
/**
* Skeleton subclass for performing query and update operations on the 'paypal_planified_payment' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
*/
class PaypalPlanifiedPaymentQuery extends BasePaypalPlanifiedPaymentQuery
{
} // PaypalPlanifiedPaymentQuery

View File

@@ -0,0 +1,373 @@
<?php
/*************************************************************************************/
/* This file is part of the Thelia package. */
/* */
/* Copyright (c) OpenStudio */
/* email : dev@thelia.net */
/* web : http://www.thelia.net */
/* */
/* For the full copyright and license information, please view the LICENSE.txt */
/* file that was distributed with this source code. */
/*************************************************************************************/
namespace PayPal;
use Monolog\Logger;
use PayPal\Exception\PayPalConnectionException;
use PayPal\Model\PaypalCartQuery;
use PayPal\Model\PaypalPlanifiedPaymentQuery;
use PayPal\Service\Base\PayPalBaseService;
use PayPal\Service\PayPalAgreementService;
use PayPal\Service\PayPalLoggerService;
use PayPal\Service\PayPalPaymentService;
use Propel\Runtime\Connection\ConnectionInterface;
use Propel\Runtime\Propel;
use Symfony\Component\Finder\Finder;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Thelia\Core\Event\Order\OrderEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Core\Translation\Translator;
use Thelia\Install\Database;
use Thelia\Model\Message;
use Thelia\Model\MessageQuery;
use Thelia\Model\ModuleImageQuery;
use Thelia\Model\Order;
use Thelia\Model\OrderStatusQuery;
use Thelia\Module\AbstractPaymentModule;
use Thelia\Tools\URL;
class PayPal extends AbstractPaymentModule
{
/** @var string */
const DOMAIN_NAME = 'paypal';
const ROUTER = 'router.paypal';
/**
* The confirmation message identifier
*/
const CONFIRMATION_MESSAGE_NAME = 'paypal_payment_confirmation';
const RECURSIVE_MESSAGE_NAME = 'paypal_recursive_payment_confirmation';
const CREDIT_CARD_TYPE_VISA = 'visa';
const CREDIT_CARD_TYPE_MASTERCARD = 'mastercard';
const CREDIT_CARD_TYPE_DISCOVER = 'discover';
const CREDIT_CARD_TYPE_AMEX = 'amex';
const PAYPAL_METHOD_PAYPAL = 'paypal';
const PAYPAL_METHOD_EXPRESS_CHECKOUT = 'express_checkout';
const PAYPAL_METHOD_CREDIT_CARD = 'credit_card';
const PAYPAL_METHOD_PLANIFIED_PAYMENT = 'planified_payment';
const PAYPAL_PAYMENT_SERVICE_ID = 'paypal_payment_service';
const PAYPAL_CUSTOMER_SERVICE_ID = 'paypal_customer_service';
const PAYPAL_AGREEMENT_SERVICE_ID = 'paypal_agreement_service';
const PAYMENT_STATE_APPROVED = 'approved';
const PAYMENT_STATE_CREATED = 'created';
const PAYMENT_STATE_REFUSED = 'refused';
/**
* Method used by payment gateway.
*
* If this method return a \Thelia\Core\HttpFoundation\Response instance, this response is send to the
* browser.
*
* In many cases, it's necessary to send a form to the payment gateway. On your response you can return this form already
* completed, ready to be sent
*
* @param Order $order
* @return RedirectResponse
* @throws \Exception
*/
public function pay(Order $order)
{
$con = Propel::getConnection();
$con->beginTransaction();
try {
/** @var PayPalPaymentService $payPalService */
$payPalService = $this->getContainer()->get(self::PAYPAL_PAYMENT_SERVICE_ID);
/** @var PayPalAgreementService $payPalAgreementService */
$payPalAgreementService = $this->getContainer()->get(self::PAYPAL_AGREEMENT_SERVICE_ID);
if (null !== $payPalCart = PaypalCartQuery::create()->findOneById($order->getCartId())) {
if (null !== $payPalCart->getCreditCardId()) {
$payment = $payPalService->makePayment($order, $payPalCart->getCreditCardId());
//This payment method does not have a callback URL... So we have to check the payment status
if ($payment->getState() === PayPal::PAYMENT_STATE_APPROVED) {
$event = new OrderEvent($order);
$event->setStatus(OrderStatusQuery::getPaidStatus()->getId());
$this->getDispatcher()->dispatch(TheliaEvents::ORDER_UPDATE_STATUS, $event);
$response = new RedirectResponse(URL::getInstance()->absoluteUrl('/order/placed/' . $order->getId()));
PayPalLoggerService::log(
Translator::getInstance()->trans(
'Order payed with success with method : %method',
[
'%method' => self::PAYPAL_METHOD_CREDIT_CARD
],
self::DOMAIN_NAME
),
[
'order_id' => $order->getId(),
'customer_id' => $order->getCustomerId()
],
Logger::INFO
);
} else {
$response = new RedirectResponse(URL::getInstance()->absoluteUrl('/module/paypal/cancel/' . $order->getId()));
PayPalLoggerService::log(
Translator::getInstance()->trans(
'Order failed with method : %method',
[
'%method' => self::PAYPAL_METHOD_CREDIT_CARD
],
self::DOMAIN_NAME
),
[
'order_id' => $order->getId(),
'customer_id' => $order->getCustomerId()
],
Logger::CRITICAL
);
}
} elseif (null !== $planifiedPayment = PaypalPlanifiedPaymentQuery::create()->findOneById($payPalCart->getPlanifiedPaymentId())) {
//Agreement Payment
$agreement = $payPalAgreementService->makeAgreement($order, $planifiedPayment);
$response = new RedirectResponse($agreement->getApprovalLink());
PayPalLoggerService::log(
Translator::getInstance()->trans(
'Order created with success in PayPal with method : %method',
[
'%method' => self::PAYPAL_METHOD_PLANIFIED_PAYMENT
],
self::DOMAIN_NAME
),
[
'order_id' => $order->getId(),
'customer_id' => $order->getCustomerId()
],
Logger::INFO
);
} else {
//Classic Payment
$payment = $payPalService->makePayment($order);
$response = new RedirectResponse($payment->getApprovalLink());
PayPalLoggerService::log(
Translator::getInstance()->trans(
'Order created with success in PayPal with method : %method',
[
'%method' => self::PAYPAL_METHOD_PAYPAL
],
self::DOMAIN_NAME
),
[
'order_id' => $order->getId(),
'customer_id' => $order->getCustomerId()
],
Logger::INFO
);
}
} else {
//Classic Payment
$payment = $payPalService->makePayment($order);
$response = new RedirectResponse($payment->getApprovalLink());
PayPalLoggerService::log(
Translator::getInstance()->trans(
'Order created with success in PayPal with method : %method',
[
'%method' => self::PAYPAL_METHOD_PAYPAL
],
self::DOMAIN_NAME
),
[
'order_id' => $order->getId(),
'customer_id' => $order->getCustomerId()
],
Logger::INFO
);
//Future Payment NOT OPERATIONNEL IN PAYPAL API REST YET !
//$payment = $payPalService->makePayment($order, null, null, true);
//$response = new RedirectResponse($payment->getApprovalLink());
}
$con->commit();
return $response;
} catch (PayPalConnectionException $e) {
$con->rollBack();
$message = sprintf('url : %s. data : %s. message : %s', $e->getUrl(), $e->getData(), $e->getMessage());
PayPalLoggerService::log(
$message,
[
'customer_id' => $order->getCustomerId(),
'order_id' => $order->getId()
],
Logger::CRITICAL
);
throw $e;
} catch(\Exception $e) {
$con->rollBack();
PayPalLoggerService::log(
$e->getMessage(),
[
'customer_id' => $order->getCustomerId(),
'order_id' => $order->getId()
],
Logger::CRITICAL
);
throw $e;
}
}
/**
*
* This method is call on Payment loop.
*
* If you return true, the payment method will de display
* If you return false, the payment method will not be display
*
* @return boolean
*/
public function isValidPayment()
{
$isValid = false;
// Check if total order amount is within the module's limits
$order_total = $this->getCurrentOrderTotalAmount();
$min_amount = Paypal::getConfigValue('minimum_amount', 0);
$max_amount = Paypal::getConfigValue('maximum_amount', 0);
if (
($order_total > 0)
&&
($min_amount <= 0 || $order_total >= $min_amount)
&&
($max_amount <= 0 || $order_total <= $max_amount)
) {
// Check cart item count
$cartItemCount = $this->getRequest()->getSession()->getSessionCart($this->getDispatcher())->countCartItems();
if ($cartItemCount <= Paypal::getConfigValue('cart_item_count', 9)) {
$isValid = true;
if (PayPalBaseService::isSandboxMode()) {
// In sandbox mode, check the current IP
$raw_ips = explode("\n", Paypal::getConfigValue('allowed_ip_list', ''));
$allowed_client_ips = array();
foreach ($raw_ips as $ip) {
$allowed_client_ips[] = trim($ip);
}
$client_ip = $this->getRequest()->getClientIp();
$isValid = in_array($client_ip, $allowed_client_ips);
}
}
}
return $isValid;
}
/**
* if you want, you can manage stock in your module instead of order process.
* Return false to decrease the stock when order status switch to pay
*
* @return bool
*/
public function manageStockOnCreation()
{
return false;
}
/**
* @param \Propel\Runtime\Connection\ConnectionInterface $con
*/
public function postActivation(ConnectionInterface $con = null)
{
$database = new Database($con);
$database->insertSql(null, array(__DIR__ . "/Config/create.sql"));
// Setup some default values at first install
if (null === self::getConfigValue('minimum_amount', null)) {
self::setConfigValue('minimum_amount', 0);
self::setConfigValue('maximum_amount', 0);
self::setConfigValue('send_payment_confirmation_message', 1);
self::setConfigValue('cart_item_count', 999);
}
if (null === MessageQuery::create()->findOneByName(self::CONFIRMATION_MESSAGE_NAME)) {
$message = new Message();
$message
->setName(self::CONFIRMATION_MESSAGE_NAME)
->setHtmlTemplateFileName('paypal-payment-confirmation.html')
->setTextTemplateFileName('paypal-payment-confirmation.txt')
->setLocale('en_US')
->setTitle('Paypal payment confirmation')
->setSubject('Payment of order {$order_ref}')
->setLocale('fr_FR')
->setTitle('Confirmation de paiement par Paypal')
->setSubject('Confirmation du paiement de votre commande {$order_ref}')
->save()
;
}
if (null === MessageQuery::create()->findOneByName(self::RECURSIVE_MESSAGE_NAME)) {
$message = new Message();
$message
->setName(self::RECURSIVE_MESSAGE_NAME)
->setHtmlTemplateFileName('paypal-recursive-payment-confirmation.html')
->setTextTemplateFileName('paypal-recursive-payment-confirmation.txt')
->setLocale('en_US')
->setTitle('Paypal payment confirmation')
->setSubject('Payment of order {$order_ref}')
->setLocale('fr_FR')
->setTitle('Confirmation de paiement par Paypal')
->setSubject('Confirmation du paiement de votre commande {$order_ref}')
->save()
;
}
/* Deploy the module's image */
$module = $this->getModuleModel();
if (ModuleImageQuery::create()->filterByModule($module)->count() == 0) {
$this->deployImageFolder($module, sprintf('%s/images', __DIR__), $con);
}
}
public function update($currentVersion, $newVersion, ConnectionInterface $con = null)
{
$finder = (new Finder())
->files()
->name('#.*?\.sql#')
->sortByName()
->in(__DIR__ . DS . 'Config' . DS . 'Update')
;
$database = new Database($con);
/** @var \Symfony\Component\Finder\SplFileInfo $updateSQLFile */
foreach ($finder as $updateSQLFile) {
if (version_compare($currentVersion, str_replace('.sql', '', $updateSQLFile->getFilename()), '<')) {
$database->insertSql(
null,
[
$updateSQLFile->getPathname()
]
);
}
}
}
}

View File

@@ -0,0 +1,56 @@
# PayPal
* I) Install notes
* II) Configure your PayPal account
* III) Module options payments
## I) Installation
### Composer
> **WARNING** : A console access is required to update dependencies. If you don't have a console access, please get the latest 2.x version of the module here : https://github.com/thelia-modules/Paypal/tree/2.x
To install the module with Composer, open a console, navigate to the Thelia diorectory and type the following command to add the dependency to Thelia composer.json file.
```
composer require thelia/paypal-module:~4.0.0
```
## II) Configure your PayPal account
- Log In on [developer.paypal.com] (https://developer.paypal.com "developer.paypal.com")
- Create REST API apps [here] (https://developer.paypal.com/developer/applications/ "here")
- Click on Create App
- Fill the fields : App Name & Sandbox developer account
- Click on Create App
- Note the Client ID to use it later in the module configuration
- Note the Client SECRET to use it later in the module configuration
#### In SANDBOX WEBHOOKS
- To fill this part, go to your module configuration page to see the urls to implement
#### In SANDBOX APP SETTINGS
- To fill this part, go to your module configuration page to see the urls to implement
## III) Module options payments
#### Classic PayPal payment
![alt classic paypal payment](https://github.com/thelia-modules/Paypal/blob/master/images/payment_classic.png?raw=true)
- This method will redirect to the PayPal platform to proceed payment
#### InContext Classic PayPal payment
![alt classic paypal payment](https://github.com/thelia-modules/Paypal/blob/master/images/payment_classic_incontext.png?raw=true)
- This method will allow the customer to pay from a PayPal inContext popup directly from your website (no redirection to the PayPal plateform)
#### Credit card
![alt classic paypal payment](https://github.com/thelia-modules/Paypal/blob/master/images/payment_credit_card.png?raw=true)
- This method allow the customer to pay directly by a credit card without a PayPal account. 'The merchant must have a Pro PayPal account UK and the website must be in HTTPS'
#### Recursive payment
![alt classic paypal payment](https://github.com/thelia-modules/Paypal/blob/master/images/payment_recursive.png?raw=true)
- This method use the 'PayPal AGRREMENTS' and allow you to use recursive payments on your website. If you want to log all PayPal actions, you need to configure the PayPal webhooks and to have a wabsite in HTTPS
#### Express checkout
![alt classic paypal payment](https://github.com/thelia-modules/Paypal/blob/master/images/payment_express_checkout.png?raw=true)
- This method allow the customer to proceed the payment directly from the cart from a PayPal inContext popup.

View File

@@ -0,0 +1,414 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace PayPal\Service\Base;
use Monolog\Logger;
use PayPal\Api\Amount;
use PayPal\Api\FuturePayment;
use PayPal\Api\Payer;
use PayPal\Api\PayerInfo;
use PayPal\Api\ShippingAddress;
use PayPal\Api\Transaction;
use PayPal\Auth\OAuthTokenCredential;
use PayPal\Event\PayPalEvents;
use PayPal\Event\PayPalOrderEvent;
use PayPal\Model\PaypalCart;
use PayPal\Model\PaypalCartQuery;
use PayPal\Model\PaypalOrder;
use PayPal\Model\PaypalPlanifiedPayment;
use PayPal\PayPal;
use PayPal\Rest\ApiContext;
use PayPal\Service\PayPalLoggerService;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Routing\RouterInterface;
use Thelia\Core\Event\Cart\CartRestoreEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Core\HttpFoundation\Session\Session;
use Thelia\Core\Translation\Translator;
use Thelia\Model\Cart;
use Thelia\Model\Country;
use Thelia\Model\Currency;
use Thelia\Model\Order;
use Thelia\Model\OrderAddressQuery;
class PayPalBaseService
{
/** @var EventDispatcherInterface */
protected $dispatcher;
/** @var RequestStack */
protected $requestStack;
/** @var RouterInterface */
protected $router;
/** @var OAuthTokenCredential */
protected $authTokenCredential;
/**
* PayPalBaseService constructor.
* @param EventDispatcherInterface $dispatcher
* @param RequestStack $requestStack
* @param RouterInterface $router
*/
public function __construct(EventDispatcherInterface $dispatcher, RequestStack $requestStack, RouterInterface $router)
{
$this->dispatcher = $dispatcher;
$this->requestStack = $requestStack;
$this->router = $router;
$this->authTokenCredential = new OAuthTokenCredential(self::getLogin(), self::getPassword());
}
/**
* @param Order $order
* @param string|null $creditCardId
* @param PaypalPlanifiedPayment $planifiedPayment
* @return PayPalOrderEvent
*/
public function generatePayPalOrder(Order $order, $creditCardId = null, PaypalPlanifiedPayment $planifiedPayment = null)
{
$payPalOrder = new PaypalOrder();
$payPalOrder
->setId($order->getId())
->setAmount($order->getTotalAmount())
;
if (null !== $creditCardId) {
$payPalOrder->setCreditCardId($creditCardId);
}
if (null !== $planifiedPayment) {
/** @var \Thelia\Model\Lang $lang */
$lang = $this->requestStack->getCurrentRequest()->getSession()->get('thelia.current.lang');
$planifiedPayment->getTranslation($lang->getLocale());
$payPalOrder
->setPlanifiedTitle($planifiedPayment->getTitle())
->setPlanifiedDescription($planifiedPayment->getDescription())
->setPlanifiedFrequency($planifiedPayment->getFrequency())
->setPlanifiedFrequencyInterval($planifiedPayment->getFrequencyInterval())
->setPlanifiedCycle($planifiedPayment->getCycle())
->setPlanifiedMinAmount($planifiedPayment->getMinAmount())
->setPlanifiedMaxAmount($planifiedPayment->getMaxAmount())
;
}
$payPalOrderEvent = new PayPalOrderEvent($payPalOrder);
$this->dispatcher->dispatch(PayPalEvents::PAYPAL_ORDER_CREATE, $payPalOrderEvent);
return $payPalOrderEvent;
}
/**
* @param PaypalOrder $payPalOrder
* @param $state
* @param string|null $paymentId
* @param string|null $agreementId
* @return PayPalOrderEvent
*/
public function updatePayPalOrder(PaypalOrder $payPalOrder, $state, $paymentId = null, $agreementId = null)
{
$payPalOrder->setState($state);
if (null !== $paymentId) {
$payPalOrder->setPaymentId($paymentId);
}
if (null !== $agreementId) {
$payPalOrder->setAgreementId($agreementId);
}
$payPalOrderEvent = new PayPalOrderEvent($payPalOrder);
$this->dispatcher->dispatch(PayPalEvents::PAYPAL_ORDER_UPDATE, $payPalOrderEvent);
return $payPalOrderEvent;
}
/**
* @return PaypalCart
*/
public function getCurrentPayPalCart()
{
/** @var Session $session */
$session = $this->requestStack->getCurrentRequest()->getSession();
$cart = $session->getSessionCart($this->dispatcher);
if (null === $cart) {
$cartEvent = new CartRestoreEvent();
$this->dispatcher->dispatch(TheliaEvents::CART_RESTORE_CURRENT, $cartEvent);
$cart = $cartEvent->getCart();
}
if (null === $payPalCart = PaypalCartQuery::create()->findOneById($cart->getId())) {
$payPalCart = new PaypalCart();
$payPalCart->setId($cart->getId());
}
return $payPalCart;
}
/**
* @param string $method
* @param array $fundingInstruments
* @param PayerInfo $payerInfo
* @return Payer
*/
public static function generatePayer($method = PayPal::PAYPAL_METHOD_PAYPAL, $fundingInstruments = [], PayerInfo $payerInfo = null)
{
$payer = new Payer();
$payer->setPaymentMethod($method);
// Never set empty instruments when communicating with PayPal
if (count($fundingInstruments) > 0) {
$payer->setFundingInstruments($fundingInstruments);
}
if (null !== $payerInfo) {
$payer->setPayerInfo($payerInfo);
}
return $payer;
}
public static function generatePayerInfo($data = [])
{
$payerInfo = new PayerInfo($data);
return $payerInfo;
}
public static function generateShippingAddress(Order $order)
{
if (null !== $orderAddress = OrderAddressQuery::create()->findOneById($order->getDeliveryOrderAddressId())) {
$shippingAddress = new ShippingAddress();
if (null !== $state = $orderAddress->getState()) {
$payPalState = $state->getIsocode();
} else {
$payPalState = 'CA';
}
$shippingAddress
->setLine1($orderAddress->getAddress1())
->setCity($orderAddress->getCity())
->setPostalCode($orderAddress->getZipcode())
->setCountryCode($orderAddress->getCountry()->getIsoalpha2())
->setState($payPalState)
;
if (null !== $orderAddress->getAddress2()) {
if (null !== $orderAddress->getAddress3()) {
$shippingAddress->setLine2($orderAddress->getAddress2() . ' ' . $orderAddress->getAddress3());
} else {
$shippingAddress->setLine2($orderAddress->getAddress2());
}
} elseif (null !== $orderAddress->getAddress3()) {
$shippingAddress->setLine2($orderAddress->getAddress3());
}
if (null !== $orderAddress->getStateId()) {
//$shippingAddress->setState($orderAddress->getState()->getIsocode());
}
return $shippingAddress;
} else {
$message = Translator::getInstance()->trans(
'Order address no found to generate PayPal shipping address',
[],
PayPal::DOMAIN_NAME
);
PayPalLoggerService::log(
$message,
[
'customer_id' => $order->getCustomerId(),
'order_id' => $order->getId()
],
Logger::ERROR
);
throw new \Exception($message);
}
}
/**
* @param Order $order
* @param Currency $currency
* @return Amount
*/
public function generateAmount(Order $order, Currency $currency)
{
// Specify the payment amount.
$amount = new Amount();
$amount->setCurrency($currency->getCode());
$amount->setTotal($order->getTotalAmount());
return $amount;
}
/**
* @param Cart $cart
* @param Currency $currency
* @return Amount
*/
public function generateAmountFromCart(Cart $cart, Currency $currency)
{
// Specify the payment amount.
$amount = new Amount();
$amount->setCurrency($currency->getCode());
$amount->setTotal($cart->getTaxedAmount(Country::getDefaultCountry()));
return $amount;
}
/**
* @param Amount $amount
* @param string $description
* @return Transaction
*/
public function generateTransaction(Amount $amount, $description = '')
{
// ###Transaction
// A transaction defines the contract of a
// payment - what is the payment for and who
// is fulfilling it. Transaction is created with
// a `Payee` and `Amount` types
$transaction = new Transaction();
$transaction->setAmount($amount);
$transaction->setDescription($description);
return $transaction;
}
public function getAccessToken()
{
$config = self::getApiContext()->getConfig();
$accessToken = $this->authTokenCredential->getAccessToken($config);
return $accessToken;
}
public function getRefreshToken()
{
$refreshToken = FuturePayment::getRefreshToken($this->getAccessToken(), self::getApiContext());
return $refreshToken;
}
/**
* SDK Configuration
*
*@return ApiContext
*/
public static function getApiContext()
{
$apiContext = new ApiContext();
// Alternatively pass in the configuration via a hashmap.
// The hashmap can contain any key that is allowed in
// sdk_config.ini
$apiContext->setConfig([
'acct1.ClientId' => self::getLogin(),
'acct1.ClientSecret' => self::getPassword(),
'http.ConnectionTimeOut' => 30,
'http.Retry' => 1,
'mode' => self::getMode(),
'log.LogEnabled' => true,
'log.FileName' => '../log/PayPal.log',
'log.LogLevel' => 'INFO',
'cache.enabled' => true,
'cache.FileName' => '../cache/prod/PayPal.cache',
'http.headers.PayPal-Partner-Attribution-Id' => 'Thelia_Cart',
]);
return $apiContext;
}
/**
* @return string
*/
public static function getLogin()
{
if (PayPal::getConfigValue('sandbox') == 1) {
$login = PayPal::getConfigValue('sandbox_login');
} else {
$login = PayPal::getConfigValue('login');
}
return $login;
}
/**
* @return string
*/
public static function getPassword()
{
if (PayPal::getConfigValue('sandbox') == 1) {
$password = PayPal::getConfigValue('sandbox_password');
} else {
$password = PayPal::getConfigValue('password');
}
return $password;
}
/**
* @return string
*/
public static function getMerchantId()
{
if (PayPal::getConfigValue('sandbox') == 1) {
$login = PayPal::getConfigValue('sandbox_merchant_id');
} else {
$login = PayPal::getConfigValue('merchant_id');
}
return $login;
}
/**
* @return string
*/
public static function getMode()
{
if (PayPal::getConfigValue('sandbox') == 1) {
$mode = 'sandbox';
} else {
$mode = 'live';
}
return $mode;
}
public static function isSandboxMode()
{
if (self::getMode() === 'live') {
return false;
} else {
return true;
}
}
}

View File

@@ -0,0 +1,940 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace PayPal\Service;
use Monolog\Logger;
use PayPal\Api\Agreement;
use PayPal\Api\AgreementStateDescriptor;
use PayPal\Api\ChargeModel;
use PayPal\Api\CreditCard;
use PayPal\Api\CreditCardToken;
use PayPal\Api\Currency;
use PayPal\Api\FundingInstrument;
use PayPal\Api\MerchantPreferences;
use PayPal\Api\Patch;
use PayPal\Api\PatchRequest;
use PayPal\Api\Payer;
use PayPal\Api\PaymentDefinition;
use PayPal\Api\Plan;
use PayPal\Common\PayPalModel;
use PayPal\Event\PayPalEvents;
use PayPal\Event\PayPalOrderEvent;
use PayPal\Event\PayPalPlanEvent;
use PayPal\Exception\PayPalConnectionException;
use PayPal\Model\PaypalOrder;
use PayPal\Model\PaypalOrderQuery;
use PayPal\Model\PaypalPlan;
use PayPal\Model\PaypalPlanifiedPayment;
use PayPal\Model\PaypalPlanQuery;
use PayPal\PayPal;
use PayPal\Service\Base\PayPalBaseService;
use Symfony\Component\Routing\Router;
use Thelia\Core\Translation\Translator;
use Thelia\Model\CurrencyQuery;
use Thelia\Model\Order;
use Thelia\Model\OrderProduct;
use Thelia\Model\OrderProductQuery;
use Thelia\Model\OrderProductTax;
use Thelia\Model\OrderProductTaxQuery;
use Thelia\Tools\URL;
class PayPalAgreementService extends PayPalBaseService
{
const PLAN_TYPE_FIXED = 'FIXED';
const PLAN_TYPE_INFINITE = 'INFINITE';
const PAYMENT_TYPE_REGULAR = 'REGULAR';
const PAYMENT_TYPE_TRIAL = 'TRIAL';
const CHARGE_TYPE_SHIPPING = 'SHIPPING';
const CHARGE_TYPE_TAX = 'TAX';
const PAYMENT_FREQUENCY_DAY = 'DAY';
const PAYMENT_FREQUENCY_WEEK = 'WEEK';
const PAYMENT_FREQUENCY_MONTH = 'MONTH';
const PAYMENT_FREQUENCY_YEAR = 'YEAR';
const FAIL_AMOUNT_ACTION_CONTINUE = 'CONTINUE';
const FAIL_AMOUNT_ACTION_CANCEL = 'CANCEL';
const MAX_API_LENGHT = 128;
/**
* @param Order $order
* @param PaypalPlanifiedPayment $planifiedPayment
* @param null $description
* @return Agreement
* @throws PayPalConnectionException
* @throws \Exception
*/
public function makeAgreement(Order $order, PaypalPlanifiedPayment $planifiedPayment, $description = null)
{
//Sadly, this description can NOT be null
if (null === $description) {
$description = 'Thelia order ' . $order->getId();
}
$payPalOrderEvent = $this->generatePayPalOrder($order, null, $planifiedPayment);
$merchantPreferences = $this->createMerchantPreferences($order);
$chargeModel = $this->createChargeModel($order);
$totalAmount = $order->getTotalAmount();
$cycleAmount = round($totalAmount / $planifiedPayment->getCycle(), 2);
$paymentDefinition = $this->createPaymentDefinition(
$order,
'payment definition for order ' . $order->getId(),
[$chargeModel],
$cycleAmount,
self::PAYMENT_TYPE_REGULAR,
$planifiedPayment->getFrequency(),
$planifiedPayment->getFrequencyInterval(),
$planifiedPayment->getCycle()
);
$plan = $this->generateBillingPlan($order, 'plan for order ' . $order->getId(), $merchantPreferences, [$paymentDefinition]);
$plan = $this->createBillingPlan($order, $plan);
$plan = $this->activateBillingPlan($order, $plan);
$newPlan = new Plan();
$newPlan->setId($plan->getId());
// There is no Billing agreement possible with credit card
$agreement = $this->createBillingAgreementWithPayPal($order, $newPlan, 'agreement ' . $order->getId(), $description);
//We must update concerned order_product price... order discount... order postage... PayPal will create one invoice each cycle
$this->updateTheliaOrderForCycle($order, $planifiedPayment->getCycle(), $cycleAmount);
$this->updatePayPalOrder($payPalOrderEvent->getPayPalOrder(), $agreement->getState(), null, $agreement->getId());
return $agreement;
}
public function updateTheliaOrderForCycle(Order $order, $cycle, $cycleAmount)
{
//Be sure that there is no rounding price lost with this method
$moneyLeft = $cycleAmount;
$newPostage = round($order->getPostage() / $cycle, 2);
$newPostageTax = round($order->getPostageTax() / $cycle, 2);
$newDiscount = round($order->getDiscount() / $cycle, 2);
$moneyLeft -= ($newPostage + $newPostageTax + $newDiscount);
$orderProducts = OrderProductQuery::create()->filterByOrderId($order->getId())->find();
/** @var \Thelia\Model\OrderProduct $orderProduct */
foreach ($orderProducts as $orderProduct) {
$newPrice = round($orderProduct->getPrice() / $cycle, 2);
$newPromoPrice = round($orderProduct->getPrice() / $cycle, 2);
if ($orderProduct->getWasInPromo()) {
$moneyLeft -= $newPromoPrice;
} else {
$moneyLeft -= $newPrice;
}
$orderProduct
->setPrice($newPrice)
->setPromoPrice($newPromoPrice)
->save()
;
$taxes = OrderProductTaxQuery::create()->filterByOrderProductId($orderProduct->getId())->find();
/** @var \Thelia\Model\OrderProductTax $tax */
foreach ($taxes as $tax) {
$newAmount = round($tax->getAmount() / $cycle, 2);
$newPromoAmount = round($tax->getPromoAmount() / $cycle, 2);
if ($orderProduct->getWasInPromo()) {
$moneyLeft -= $newPromoAmount;
} else {
$moneyLeft -= $newAmount;
}
$tax
->setAmount($newAmount)
->setPromoAmount($newPromoAmount)
->save()
;
}
}
//Normally, $moneyLeft == 0 here. But in case of rouding price, adjust the rounding in the postage column
$newPostage += $moneyLeft;
$order
->setPostage($newPostage)
->setPostageTax($newPostageTax)
->setDiscount($newDiscount)
->save()
;
return $order;
}
/**
* @param $billingPlanId
* @return Plan
*/
public function getBillingPlan($billingPlanId)
{
$plan = Plan::get($billingPlanId, self::getApiContext());
return $plan;
}
/**
* @param Order $order
* @param Plan $plan
* @return Plan
*/
public function activateBillingPlan(Order $order, Plan $plan)
{
$patch = new Patch();
$value = new PayPalModel('{
"state":"ACTIVE"
}');
$patch
->setOp('replace')
->setPath('/')
->setValue($value)
;
$patchRequest = new PatchRequest();
$patchRequest->addPatch($patch);
$plan->update($patchRequest, self::getApiContext());
$plan = $this->getBillingPlan($plan->getId());
if (null === $payPalPlan = PaypalPlanQuery::create()
->filterByPaypalOrderId($order->getId())
->filterByPlanId($plan->getId())
->findOne()) {
$payPalPlan = new PaypalPlan();
$payPalPlan
->setPaypalOrderId($order->getId())
->setPlanId($plan->getId())
;
}
$payPalPlan->setState($plan->getState());
$payPalPlanEvent = new PayPalPlanEvent($payPalPlan);
$this->dispatcher->dispatch(PayPalEvents::PAYPAL_PLAN_UPDATE, $payPalPlanEvent);
return $plan;
}
/**
* @param $token
* @param null $orderId
* @return Agreement
* @throws PayPalConnectionException
* @throws \Exception
*/
public function activateBillingAgreementByToken($token, $orderId = null)
{
$agreement = new Agreement();
try {
$agreement->execute($token, self::getApiContext());
return $this->getBillingAgreement($agreement->getId());
} catch (PayPalConnectionException $e) {
$message = sprintf('url : %s. data : %s. message : %s', $e->getUrl(), $e->getData(), $e->getMessage());
PayPalLoggerService::log(
$message,
[
'customer_id' => $orderId
],
Logger::CRITICAL
);
throw $e;
} catch (\Exception $e) {
PayPalLoggerService::log(
$e->getMessage(),
[
'customer_id' => $orderId
],
Logger::CRITICAL
);
throw $e;
}
}
/**
* @param Order $order
* @param $name
* @param $merchantPreferences
* @param array $paymentDefinitions
* @param string $description
* @param string $type
* @return Plan
* @throws \Exception
*/
public function generateBillingPlan(Order $order, $name, $merchantPreferences, $paymentDefinitions = [], $description = '', $type = self::PLAN_TYPE_FIXED)
{
if (!in_array($type, self::getAllowedPlanType())) {
$message = Translator::getInstance()->trans(
'Invalid type send to generate billing plan',
[],
PayPal::DOMAIN_NAME
);
PayPalLoggerService::log(
$message,
[
'customer_id' => $order->getCustomerId(),
'order_id' => $order->getId()
],
Logger::ERROR
);
throw new \Exception($message);
}
if (!is_array($paymentDefinitions) || count($paymentDefinitions) <= 0) {
$message = Translator::getInstance()->trans(
'Invalid number of payment definition send to generate billing plan',
[],
PayPal::DOMAIN_NAME
);
PayPalLoggerService::log(
$message,
[
'customer_id' => $order->getCustomerId(),
'order_id' => $order->getId()
],
Logger::ERROR
);
throw new \Exception($message);
}
$plan = new Plan();
$plan
->setName(substr($name, 0, self::MAX_API_LENGHT))
->setDescription(substr($description, 0, self::MAX_API_LENGHT))
->setType($type)
->setPaymentDefinitions($paymentDefinitions)
->setMerchantPreferences($merchantPreferences)
;
return $plan;
}
/**
* @param Plan $plan
* @return bool
*/
public function deleteBillingPlan(Plan $plan)
{
$isDeleted = $plan->delete(self::getApiContext());
return $isDeleted;
}
/**
* @param int $pageSize
* @return \PayPal\Api\PlanList
*/
public function listBillingPlans($pageSize = 2)
{
$planList = Plan::all(['page_size' => $pageSize], self::getApiContext());
return $planList;
}
/**
* @param Order $order
* @param Plan $plan
* @return Plan
* @throws PayPalConnectionException
* @throws \Exception
*/
public function createBillingPlan(Order $order, Plan $plan)
{
try {
$plan = $plan->create(self::getApiContext());
if (null === $payPalPlan = PaypalPlanQuery::create()
->filterByPaypalOrderId($order->getId())
->filterByPlanId($plan->getId())
->findOne()) {
$payPalPlan = new PaypalPlan();
$payPalPlan
->setPaypalOrderId($order->getId())
->setPlanId($plan->getId())
;
}
$payPalPlan->setState($plan->getState());
$payPalPlanEvent = new PayPalPlanEvent($payPalPlan);
$this->dispatcher->dispatch(PayPalEvents::PAYPAL_PLAN_CREATE, $payPalPlanEvent);
return $plan;
} catch (PayPalConnectionException $e) {
$message = sprintf('url : %s. data : %s. message : %s', $e->getUrl(), $e->getData(), $e->getMessage());
PayPalLoggerService::log(
$message,
[
'customer_id' => $order->getCustomerId(),
'order_id' => $order->getId()
],
Logger::CRITICAL
);
throw $e;
} catch (\Exception $e) {
PayPalLoggerService::log(
$e->getMessage(),
[
'customer_id' => $order->getCustomerId(),
'order_id' => $order->getId()
],
Logger::CRITICAL
);
throw $e;
}
}
/**
* @param Order $order
* @param Plan $plan
* @param $creditCardId
* @param $name
* @param $description
* @return Agreement
*/
public function createBillingAgreementWithCreditCard(Order $order, Plan $plan, $creditCardId, $name, $description)
{
$creditCardToken = new CreditCardToken();
$creditCardToken->setCreditCardId($creditCardId);
$fundingInstrument = new FundingInstrument();
//$fundingInstrument->setCreditCardToken($creditCardToken);
$card = new CreditCard();
$card
->setType('visa')
->setNumber('4491759698858890')
->setExpireMonth('12')
->setExpireYear('2017')
->setCvv2('128')
;
$fundingInstrument->setCreditCard($card);
$payer = self::generatePayer(
PayPal::PAYPAL_METHOD_CREDIT_CARD,
[$fundingInstrument],
self::generatePayerInfo(['email' => $order->getCustomer()->getEmail()])
);
$agreement = $this->generateAgreement($order, $plan, $payer, $name, $description);
$agreement = $agreement->create(self::getApiContext());
return $agreement;
}
/**
* @param Order $order
* @param Plan $plan
* @param $name
* @param $description
* @return Agreement
*/
public function createBillingAgreementWithPayPal(Order $order, Plan $plan, $name, $description)
{
$payer = self::generatePayer(PayPal::PAYPAL_METHOD_PAYPAL);
$agreement = $this->generateAgreement($order, $plan, $payer, $name, $description);
$agreement = $agreement->create(self::getApiContext());
return $agreement;
}
/**
* @param $agreementId
* @return Agreement
*/
public function getBillingAgreement($agreementId)
{
$agreement = Agreement::get($agreementId, self::getApiContext());
return $agreement;
}
/**
* @param $agreementId
* @param array $params
* @return \PayPal\Api\AgreementTransactions
*/
public function getBillingAgreementTransactions($agreementId, $params = [])
{
if (is_array($params) || count($params) == 0) {
$params = [
'start_date' => date('Y-m-d', strtotime('-15 years')),
'end_date' => date('Y-m-d', strtotime('+5 days'))
];
}
$agreementTransactions = Agreement::searchTransactions($agreementId, $params, self::getApiContext());
return $agreementTransactions;
}
/**
* @param Agreement $agreement
* @param string $note
* @return Agreement
*/
public function suspendBillingAgreement(Agreement $agreement, $note = 'Suspending the agreement')
{
//Create an Agreement State Descriptor, explaining the reason to suspend.
$agreementStateDescriptor = new AgreementStateDescriptor();
$agreementStateDescriptor->setNote($note);
$agreement->suspend($agreementStateDescriptor, self::getApiContext());
$agreement = $this->getBillingAgreement($agreement->getId());
return $agreement;
}
/**
* @param Agreement $agreement
* @param string $note
* @return Agreement
*/
public function reActivateBillingAgreement(Agreement $agreement, $note = 'Reactivating the agreement')
{
//Create an Agreement State Descriptor, explaining the reason to re activate.
$agreementStateDescriptor = new AgreementStateDescriptor();
$agreementStateDescriptor->setNote($note);
$agreement->reActivate($agreementStateDescriptor, self::getApiContext());
$agreement = $this->getBillingAgreement($agreement->getId());
return $agreement;
}
/**
* @param Order $order
* @param $name
* @param array $chargeModels
* @param null $cycleAmount
* @param string $type
* @param string $frequency
* @param int $frequencyInterval
* @param int $cycles
* @return PaymentDefinition
* @throws \Exception
*/
public function createPaymentDefinition(Order $order, $name, $chargeModels = [], $cycleAmount = null, $type = self::PAYMENT_TYPE_REGULAR, $frequency = self::PAYMENT_FREQUENCY_DAY, $frequencyInterval = 1, $cycles = 1)
{
if (!in_array($type, self::getAllowedPaymentType())) {
$message = Translator::getInstance()->trans(
'Invalid payment type send to create payment definition',
[],
PayPal::DOMAIN_NAME
);
PayPalLoggerService::log(
$message,
[
'customer_id' => $order->getCustomerId(),
'order_id' => $order->getId()
],
Logger::ERROR
);
throw new \Exception($message);
}
if (!in_array($frequency, self::getAllowedPaymentFrequency())) {
$message = Translator::getInstance()->trans(
'Invalid payment frequency send to create payment definition',
[],
PayPal::DOMAIN_NAME
);
PayPalLoggerService::log(
$message,
[
'customer_id' => $order->getCustomerId(),
'order_id' => $order->getId()
],
Logger::ERROR
);
throw new \Exception($message);
}
if (!is_array($chargeModels) || count($chargeModels) <= 0) {
$message = Translator::getInstance()->trans(
'Invalid number of charge models send to create payment definition',
[],
PayPal::DOMAIN_NAME
);
PayPalLoggerService::log(
$message,
[
'customer_id' => $order->getCustomerId(),
'order_id' => $order->getId()
],
Logger::ERROR
);
throw new \Exception($message);
}
$paymentDefinition = new PaymentDefinition();
if (null === $cycleAmount) {
$totalAmount = $order->getTotalAmount();
$cycleAmount = round($totalAmount / $cycles, 2);
}
$paymentDefinition
->setName(substr($name, 0, self::MAX_API_LENGHT))
->setType($type)
->setFrequency($frequency)
->setFrequencyInterval($frequencyInterval)
->setCycles($cycles)
->setAmount(new Currency(['value' => $cycleAmount, 'currency' => self::getOrderCurrencyCode($order)]))
->setChargeModels($chargeModels)
;
return $paymentDefinition;
}
/**
* @param Order $order
* @param int $chargeAmount
* @param string $type
* @return ChargeModel
* @throws \Exception
*/
public function createChargeModel(Order $order, $chargeAmount = 0, $type = self::CHARGE_TYPE_SHIPPING)
{
if (!in_array($type, self::getAllowedChargeType())) {
$message = Translator::getInstance()->trans(
'Invalid charge type send to create charge model',
[],
PayPal::DOMAIN_NAME
);
PayPalLoggerService::log(
$message,
[
'customer_id' => $order->getCustomerId(),
'order_id' => $order->getId()
],
Logger::ERROR
);
throw new \Exception($message);
}
$chargeModel = new ChargeModel();
$chargeModel
->setType($type)
->setAmount(new Currency(['value' => $chargeAmount, 'currency' => self::getOrderCurrencyCode($order)]))
;
return $chargeModel;
}
/**
* @param Order $order
* @param bool $autoBillAmount
* @param string $failAction
* @param int $maxFailAttempts
* @param int $feeAmount
* @return MerchantPreferences
* @throws \Exception
*/
public function createMerchantPreferences(Order $order, $autoBillAmount = false, $failAction = self::FAIL_AMOUNT_ACTION_CONTINUE, $maxFailAttempts = 0, $feeAmount = 0)
{
if (!in_array($failAction, self::getAllowedFailedAction())) {
$message = Translator::getInstance()->trans(
'Invalid fail action send to create merchant preference',
[],
PayPal::DOMAIN_NAME
);
PayPalLoggerService::log(
$message,
[
'customer_id' => $order->getCustomerId(),
'order_id' => $order->getId()
],
Logger::ERROR
);
throw new \Exception($message);
}
$merchantPreferences = new MerchantPreferences();
$urlOk = URL::getInstance()->absoluteUrl(
$this->router->generate(
"paypal.agreement.ok",
[
'orderId' => $order->getId()
],
Router::ABSOLUTE_URL
)
);
$urlKo = URL::getInstance()->absoluteUrl(
$this->router->generate(
"paypal.agreement.ko",
[
'orderId' => $order->getId()
],
Router::ABSOLUTE_URL
)
);
if ($autoBillAmount) {
$autoBillAmountStr = 'YES';
} else {
$autoBillAmountStr = 'NO';
}
$merchantPreferences
->setReturnUrl($urlOk)
->setCancelUrl($urlKo)
->setAutoBillAmount($autoBillAmountStr)
->setInitialFailAmountAction($failAction)
->setMaxFailAttempts($maxFailAttempts)
->setSetupFee(new Currency(['value' => $feeAmount, 'currency' => self::getOrderCurrencyCode($order)]))
;
return $merchantPreferences;
}
/**
* @param Order $order
* @return Order
* @throws \Exception
* @throws \Propel\Runtime\Exception\PropelException
*/
public function duplicateOrder(Order $order)
{
$today = new \Datetime;
$newOrder = new Order();
$newOrder
->setCustomerId($order->getCustomerId())
->setInvoiceOrderAddressId($order->getInvoiceOrderAddressId())
->setDeliveryOrderAddressId($order->getDeliveryOrderAddressId())
->setInvoiceDate($today->format('Y-m-d H:i:s'))
->setCurrencyId($order->getCurrencyId())
->setCurrencyRate($order->getCurrencyRate())
->setDeliveryRef($order->getDeliveryRef())
->setInvoiceRef($order->getInvoiceRef())
->setDiscount($order->getDiscount())
->setPostage($order->getPostage())
->setPostageTax($order->getPostageTax())
->setPostageTaxRuleTitle($order->getPostageTaxRuleTitle())
->setPaymentModuleId($order->getPaymentModuleId())
->setDeliveryModuleId($order->getDeliveryModuleId())
->setStatusId($order->getStatusId())
->setLangId($order->getLangId())
->setCartId($order->getCartId())
->save()
;
$orderProducts = OrderProductQuery::create()->filterByOrderId($order->getId())->find();
/** @var \Thelia\Model\OrderProduct $orderProduct */
foreach ($orderProducts as $orderProduct) {
$newOrderProduct = new OrderProduct();
$newOrderProduct
->setOrderId($newOrder->getId())
->setProductRef($orderProduct->getProductRef())
->setProductSaleElementsRef($orderProduct->getProductSaleElementsRef())
->setProductSaleElementsId($orderProduct->getProductSaleElementsId())
->setTitle($orderProduct->getTitle())
->setChapo($orderProduct->getChapo())
->setDescription($orderProduct->getDescription())
->setPostscriptum($orderProduct->getPostscriptum())
->setQuantity($orderProduct->getQuantity())
->setPrice($orderProduct->getPrice())
->setPromoPrice($orderProduct->getPromoPrice())
->setWasNew($orderProduct->getWasNew())
->setWasInPromo($orderProduct->getWasInPromo())
->setWeight($orderProduct->getWeight())
->setEanCode($orderProduct->getEanCode())
->setTaxRuleTitle($orderProduct->getTaxRuleTitle())
->setTaxRuleDescription($orderProduct->getTaxRuleDescription())
->setParent($orderProduct->getParent())
->setVirtual($orderProduct->getVirtual())
->setVirtualDocument($orderProduct->getVirtualDocument())
->save()
;
$orderProductTaxes = OrderProductTaxQuery::create()->filterByOrderProductId($orderProduct->getId())->find();
/** @var \Thelia\Model\OrderProductTax $orderProductTax */
foreach ($orderProductTaxes as $orderProductTax) {
$newOrderProductTax = new OrderProductTax();
$newOrderProductTax
->setOrderProductId($newOrderProduct->getId())
->setTitle($orderProductTax->getTitle())
->setDescription($orderProductTax->getDescription())
->setAmount($orderProductTax->getAmount())
->setPromoAmount($orderProductTax->getPromoAmount())
->save()
;
}
}
if (null !== $payPalOrder = PaypalOrderQuery::create()->findOneById($order->getId())) {
$newPayPalOrder = new PaypalOrder();
$newPayPalOrder
->setId($newOrder->getId())
->setPaymentId($payPalOrder->getPaymentId())
->setAgreementId($payPalOrder->getAgreementId())
->setCreditCardId($payPalOrder->getCreditCardId())
->setState($payPalOrder->getState())
->setAmount($payPalOrder->getAmount())
->setDescription($payPalOrder->getDescription())
->setPayerId($payPalOrder->getPayerId())
->setToken($payPalOrder->getToken())
;
$newPayPalOrderEvent = new PayPalOrderEvent($newPayPalOrder);
$this->dispatcher->dispatch(PayPalEvents::PAYPAL_ORDER_CREATE, $newPayPalOrderEvent);
$payPalPlans = PaypalPlanQuery::create()->filterByPaypalOrderId($payPalOrder->getId());
/** @var \PayPal\Model\PaypalPlan $payPalPlan */
foreach ($payPalPlans as $payPalPlan) {
$newPayPalPlan = new PaypalPlan();
$newPayPalPlan
->setPaypalOrderId($newPayPalOrderEvent->getPayPalOrder()->getId())
->setPlanId($payPalPlan->getPlanId())
->setState($payPalPlan->getState())
;
$newPayPalPlanEvent = new PayPalPlanEvent($newPayPalPlan);
$this->dispatcher->dispatch(PayPalEvents::PAYPAL_PLAN_CREATE, $newPayPalPlanEvent);
}
}
return $newOrder;
}
/**
* @param Order $order
* @param Plan $plan
* @param Payer $payer
* @param $name
* @param string $description
* @return Agreement
* @throws \Exception
*/
public function generateAgreement(Order $order, Plan $plan, Payer $payer, $name, $description = '')
{
$agreement = new Agreement();
$agreement
->setName($name)
->setDescription($description)
->setStartDate((new \Datetime)->format('Y-m-d\TG:i:s\Z'))
->setPlan($plan)
;
//Add Payer to Agreement
$agreement
->setPayer($payer)
->setShippingAddress(self::generateShippingAddress($order))
;
return $agreement;
}
/**
* @param Order $order
* @return string
*/
public static function getOrderCurrencyCode(Order $order)
{
if (null === $currency = CurrencyQuery::create()->findOneById($order->getCurrencyId())) {
$currency = \Thelia\Model\Currency::getDefaultCurrency();
}
return $currency->getCode();
}
/**
* @return array
*/
public static function getAllowedPlanType()
{
return [
self::PLAN_TYPE_FIXED,
self::PLAN_TYPE_INFINITE
];
}
/**
* @return array
*/
public static function getAllowedPaymentType()
{
return [
self::PAYMENT_TYPE_REGULAR,
self::PAYMENT_TYPE_TRIAL
];
}
/**
* @return array
*/
public static function getAllowedChargeType()
{
return [
self::CHARGE_TYPE_SHIPPING,
self::CHARGE_TYPE_TAX
];
}
/**
* @return array
*/
public static function getAllowedPaymentFrequency()
{
return [
self::PAYMENT_FREQUENCY_DAY => self::PAYMENT_FREQUENCY_DAY,
self::PAYMENT_FREQUENCY_WEEK => self::PAYMENT_FREQUENCY_WEEK,
self::PAYMENT_FREQUENCY_MONTH => self::PAYMENT_FREQUENCY_MONTH,
self::PAYMENT_FREQUENCY_YEAR => self::PAYMENT_FREQUENCY_YEAR
];
}
/**
* @return array
*/
public static function getAllowedFailedAction()
{
return [
self::FAIL_AMOUNT_ACTION_CANCEL,
self::FAIL_AMOUNT_ACTION_CONTINUE
];
}
}

View File

@@ -0,0 +1,164 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace PayPal\Service;
use Monolog\Logger;
use PayPal\Api\OpenIdSession;
use PayPal\Api\OpenIdTokeninfo;
use PayPal\Api\OpenIdUserinfo;
use PayPal\Model\PaypalCustomer;
use PayPal\Model\PaypalCustomerQuery;
use PayPal\Service\Base\PayPalBaseService;
use Thelia\Core\Security\SecurityContext;
/**
* Class PayPalCustomerService
* @package PayPal\Service
*/
class PayPalCustomerService
{
/** @var SecurityContext */
protected $securityContext;
/**
* PayPalService constructor.
* @param SecurityContext $securityContext
*/
public function __construct(SecurityContext $securityContext)
{
$this->securityContext = $securityContext;
}
/**
* @param $authorizationCode
* @return OpenIdUserinfo
* @throws \Exception
*/
public function getUserInfoWithAuthorizationCode($authorizationCode)
{
try {
$accessToken = OpenIdTokeninfo::createFromAuthorizationCode(
['code' => $authorizationCode],
null,
null,
PayPalBaseService::getApiContext()
);
return $this->getUserInfo($accessToken->getAccessToken());
} catch (\Exception $ex) {
PayPalLoggerService::log($ex->getMessage(), [], Logger::ERROR);
throw $ex;
}
}
/**
* @param $accessToken
* @return OpenIdUserinfo
*/
public function getUserInfo($accessToken)
{
$params = array('access_token' => $accessToken);
$userInfo = OpenIdUserinfo::getUserinfo($params, PayPalBaseService::getApiContext());
return $userInfo;
}
/**
* @return PaypalCustomer
*/
public function getCurrentPayPalCustomer()
{
$payPalCustomer = new PaypalCustomer();
if (null !== $customer = $this->securityContext->getCustomerUser()) {
$payPalCustomer = PaypalCustomerQuery::create()->findOneById($customer->getId());
}
return $payPalCustomer;
}
/**
* @param $refreshToken
* @return OpenIdTokeninfo
* @throws \Exception
*/
public function generateAccessTokenFromRefreshToken($refreshToken)
{
try {
$tokenInfo = new OpenIdTokeninfo();
$tokenInfo = $tokenInfo->createFromRefreshToken(['refresh_token' => $refreshToken], PayPalBaseService::getApiContext());
return $tokenInfo;
} catch (\Exception $ex) {
PayPalLoggerService::log($ex->getMessage(), [], Logger::ERROR);
throw $ex;
}
}
/**
* @param $refreshToken
* @return OpenIdUserinfo
* @throws \Exception
*/
public function getUserInfoWithRefreshToken($refreshToken)
{
try {
$tokenInfo = $this->generateAccessTokenFromRefreshToken($refreshToken);
return $this->getUserInfo($tokenInfo->getAccessToken());
} catch (\Exception $ex) {
PayPalLoggerService::log($ex->getMessage(), [], Logger::ERROR);
throw $ex;
}
}
/**
* @return string
*/
public function getUrlToRefreshToken()
{
//Get Authorization URL returns the redirect URL that could be used to get user's consent
$redirectUrl = OpenIdSession::getAuthorizationUrl(
'http://25b3ee89.ngrok.io/',
[
'openid',
'profile',
'address',
'email',
'phone',
'https://uri.paypal.com/services/paypalattributes',
'https://uri.paypal.com/services/expresscheckout',
'https://uri.paypal.com/services/invoicing'
],
null,
null,
null,
PayPalBaseService::getApiContext()
);
return $redirectUrl;
}
}

View File

@@ -0,0 +1,133 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace PayPal\Service;
use Monolog\Logger;
use MySQLHandler\MySQLHandler;
use PayPal\Model\Map\PaypalLogTableMap;
use PayPal\Model\PaypalLogQuery;
use PayPal\PayPal;
use Propel\Runtime\Propel;
use Thelia\Install\Database;
/**
* Class PayPalLoggerService
* @package PayPal\Service
*/
class PayPalLoggerService
{
/**
* @param $message
* @param array $params
* @param int $level
*/
public static function log($message, $params = [], $level = Logger::DEBUG)
{
$staticParams = self::getStaticParams();
$logger = new Logger(PayPal::getModuleCode());
//Create MysqlHandler
$database = new Database(Propel::getConnection());
$mySQLHandler = new MySQLHandler(
$database->getConnection(),
PaypalLogTableMap::TABLE_NAME,
array_keys($staticParams),
$level
);
$logger->pushHandler($mySQLHandler);
//Now you can use the logger, and further attach additional information
switch ($level) {
case Logger::DEBUG:
$logger->addDebug($message, array_merge($staticParams, $params));
break;
case Logger::INFO:
$logger->addInfo($message, array_merge($staticParams, $params));
break;
case Logger::NOTICE:
$logger->addNotice($message, array_merge($staticParams, $params));
break;
case Logger::WARNING:
$logger->addWarning($message, array_merge($staticParams, $params));
break;
case Logger::ERROR:
$logger->addError($message, array_merge($staticParams, $params));
break;
case Logger::CRITICAL:
$logger->addCritical($message, array_merge($staticParams, $params));
break;
case Logger::ALERT:
$logger->addAlert($message, array_merge($staticParams, $params));
break;
case Logger::EMERGENCY:
$logger->addEmergency($message, array_merge($staticParams, $params));
break;
default:
$logger->addDebug($message, array_merge($staticParams, $params));
break;
}
}
/**
* @return array
* @throws \Propel\Runtime\Exception\PropelException
*/
public static function getStaticParams()
{
$psr3Fields = ['channel', 'level', 'message', 'time'];
$payPalLogFields = PaypalLogTableMap::getFieldNames(PaypalLogTableMap::TYPE_FIELDNAME);
$readableDate = new \Datetime();
$staticParams = [];
foreach ($payPalLogFields as $fieldName) {
// Do not interpret psr3 fields
if (in_array($fieldName, $psr3Fields)) {
continue;
}
if (in_array($fieldName, ['created_at', 'updated_at'])) {
$staticParams[$fieldName] = $readableDate->format('Y-m-d H:i:s');
} elseif (in_array($fieldName, ['id'])) {
$lastId = PaypalLogQuery::create()->count();
$staticParams[$fieldName] = $lastId + 1;
} else {
$staticParams[$fieldName] = null;
}
}
return $staticParams;
}
}

View File

@@ -0,0 +1,411 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace PayPal\Service;
use Monolog\Logger;
use PayPal\Api\Amount;
use PayPal\Api\CreditCard;
use PayPal\Api\CreditCardToken;
use PayPal\Api\Details;
use PayPal\Api\FundingInstrument;
use PayPal\Api\FuturePayment;
use PayPal\Api\OpenIdTokeninfo;
use PayPal\Api\Payer;
use PayPal\Api\Payment;
use PayPal\Api\PaymentExecution;
use PayPal\Api\RedirectUrls;
use PayPal\Api\Transaction;
use PayPal\Exception\PayPalConnectionException;
use PayPal\PayPal;
use PayPal\Service\Base\PayPalBaseService;
use Thelia\Core\Translation\Translator;
use Thelia\Model\Cart;
use Thelia\Model\Currency;
use Thelia\Model\CurrencyQuery;
use Thelia\Model\Order;
use Thelia\Tools\URL;
/**
* Class PayPalPaymentService
* @package PayPal\Service
*/
class PayPalPaymentService extends PayPalBaseService
{
/**
* Create a payment using a previously obtained
* credit card id. The corresponding credit
* card is used as the funding instrument.
*
* @param Order $order
* @param bool $future
* @param string|null $creditCardId
* @param string|null $description
* @return Payment
*/
public function makePayment(Order $order, $creditCardId = null, $description = null, $future = false)
{
$payPalOrderEvent = $this->generatePayPalOrder($order);
if (null !== $creditCardId) {
$creditCardToken = new CreditCardToken();
$creditCardToken->setCreditCardId($creditCardId);
$fundingInstrument = new FundingInstrument();
$fundingInstrument->setCreditCardToken($creditCardToken);
$payer = self::generatePayer(PayPal::PAYPAL_METHOD_CREDIT_CARD, [$fundingInstrument]);
} else {
$payer = self::generatePayer();
}
// Specify the payment amount.
if (null === $currency = CurrencyQuery::create()->findOneById($order->getCurrencyId())) {
$currency = Currency::getDefaultCurrency();
}
$amount = $this->generateAmount($order, $currency);
$transaction = $this->generateTransaction($amount, $description);
$payment = $this->generatePayment($order, $payer, $transaction, $future);
$this->updatePayPalOrder($payPalOrderEvent->getPayPalOrder(), $payment->getState(), $payment->getId());
return $payment;
}
public function makePaymentFromCart(Cart $cart, $description = null, $future = false, $fromCartView = true)
{
$payer = self::generatePayer();
// Specify the payment amount.
if (null === $currency = CurrencyQuery::create()->findOneById($cart->getCurrencyId())) {
$currency = Currency::getDefaultCurrency();
}
$amount = $this->generateAmountFromCart($cart, $currency);
$transaction = $this->generateTransaction($amount, $description);
$payment = $this->generatePaymentFromCart($cart, $payer, $transaction, $future, $fromCartView);
//$this->updatePayPalOrder($payPalOrderEvent->getPayPalOrder(), $payment->getState(), $payment->getId());
return $payment;
}
/**
* Completes the payment once buyer approval has been
* obtained. Used only when the payment method is 'paypal'
*
* @param string $paymentId id of a previously created
* payment that has its payment method set to 'paypal'
* and has been approved by the buyer.
*
* @param string $payerId PayerId as returned by PayPal post
* buyer approval.
*
* @return Payment
*/
public function executePayment($paymentId, $payerId, Details $details = null)
{
$payment = $this->getPaymentDetails($paymentId);
$paymentExecution = new PaymentExecution();
$paymentExecution->setPayerId($payerId);
if (null !== $details) {
$amount = new Amount();
$totalDetails = (float)$details->getShipping() + (float)$details->getTax() + (float)$details->getSubtotal();
$amount
->setCurrency('EUR')
->setTotal($totalDetails)
->setDetails($details)
;
$transaction = new Transaction();
$transaction->setAmount($amount);
$paymentExecution->addTransaction($transaction);
}
$payment = $payment->execute($paymentExecution, self::getApiContext());
return $payment;
}
public function createDetails($shipping = 0, $shippingTax = 0, $subTotal = 0)
{
$details = new Details();
$details
->setShipping($shipping)
->setTax($shippingTax)
->setSubtotal($subTotal)
;
return $details;
}
/**
* Retrieves the payment information based on PaymentID from Paypal APIs
*
* @param $paymentId
*
* @return Payment
*/
public function getPaymentDetails($paymentId)
{
$payment = Payment::get($paymentId, self::getApiContext());
return $payment;
}
/**
* @param $authorizationCode
* @return OpenIdTokeninfo
* @throws PayPalConnectionException
*/
public function generateAccessToken($authorizationCode)
{
try {
// Obtain Authorization Code from Code, Client ID and Client Secret
$accessToken = OpenIdTokeninfo::createFromAuthorizationCode(
['code' => $authorizationCode],
null,
null,
self::getApiContext()
);
return $accessToken;
} catch (PayPalConnectionException $ex) {
PayPalLoggerService::log($ex->getMessage(), [], Logger::ERROR);
throw $ex;
}
}
/**
* @param $type
* @param $number
* @param $expireMonth
* @param $expireYear
* @param $cvv2
* @return string
* @throws \Exception
*/
public function getPayPalCreditCardId($type, $number, $expireMonth, $expireYear, $cvv2)
{
try {
$card = new CreditCard();
$card->setType($type);
$card->setNumber((int)$number);
$card->setExpireMonth((int)$expireMonth);
$card->setExpireYear((int)$expireYear);
$card->setCvv2($cvv2);
$card->create(self::getApiContext());
return $card->getId();
} catch (\Exception $e) {
PayPalLoggerService::log($e->getMessage(), [], Logger::ERROR);
throw new \Exception(Translator::getInstance()->trans('Credit card is invalid', [], PayPal::DOMAIN_NAME));
}
}
/**
* @param Order $order
* @param Payer $payer
* @param Transaction $transaction
* @param bool $future
* @return FuturePayment|Payment
* @throws PayPalConnectionException
* @throws \Exception
*/
public function generatePayment(Order $order, Payer $payer, Transaction $transaction, $future = false)
{
if ($future) {
$payment = new FuturePayment();
$payment->setIntent('authorize');
} else {
$payment = new Payment();
$payment->setIntent('sale');
}
$payment
->setRedirectUrls($this->getRedirectUrls($order))
->setPayer($payer)
->setTransactions([$transaction])
;
$clientMetadataId = '123123456';
try {
if ($future) {
//$authorizationCode = self::getAuthorizationCode();
$refreshToken = $this->getRefreshToken();
//$refreshToken = FuturePayment::getRefreshToken($this->getAuthorizationCode(), self::getApiContext());
$payment->updateAccessToken($refreshToken, self::getApiContext());
$payment->create(self::getApiContext(), $clientMetadataId);
} else {
$payment->create(self::getApiContext());
}
return $payment;
} catch (PayPalConnectionException $e) {
$message = sprintf('url : %s. data : %s. message : %s', $e->getUrl(), $e->getData(), $e->getMessage());
PayPalLoggerService::log(
$message,
[
'customer_id' => $order->getCustomerId(),
'order_id' => $order->getId()
],
Logger::CRITICAL
);
throw $e;
} catch (\Exception $e) {
PayPalLoggerService::log(
$e->getMessage(),
[
'customer_id' => $order->getCustomerId(),
'order_id' => $order->getId()
],
Logger::CRITICAL
);
throw $e;
}
}
/**
* @param Cart $cart
* @param Payer $payer
* @param Transaction $transaction
* @param bool $future
* @return FuturePayment|Payment
* @throws PayPalConnectionException
* @throws \Exception
*/
public function generatePaymentFromCart(Cart $cart, Payer $payer, Transaction $transaction, $future = false, $fromCartView = true)
{
if ($future) {
$payment = new FuturePayment();
$payment->setIntent('authorize');
} else {
$payment = new Payment();
$payment->setIntent('sale');
}
if ($fromCartView) {
$payment->setRedirectUrls($this->getRedirectCartUrls($cart));
} else {
$payment->setRedirectUrls($this->getRedirectInvoiceUrls($cart));
}
$payment
->setPayer($payer)
->setTransactions([$transaction])
;
$clientMetadataId = '123123456';
try {
if ($future) {
//$authorizationCode = self::getAuthorizationCode();
$refreshToken = $this->getRefreshToken();
//$refreshToken = FuturePayment::getRefreshToken($this->getAuthorizationCode(), self::getApiContext());
$payment->updateAccessToken($refreshToken, self::getApiContext());
$payment->create(self::getApiContext(), $clientMetadataId);
} else {
$payment->create(self::getApiContext());
}
return $payment;
} catch (PayPalConnectionException $e) {
$message = sprintf('url : %s. data : %s. message : %s', $e->getUrl(), $e->getData(), $e->getMessage());
PayPalLoggerService::log(
$message,
[],
Logger::CRITICAL
);
throw $e;
} catch (\Exception $e) {
PayPalLoggerService::log(
$e->getMessage(),
[],
Logger::CRITICAL
);
throw $e;
}
}
/**
* @param Order $order
* @return RedirectUrls
*/
public function getRedirectUrls(Order $order)
{
$redirectUrls = new RedirectUrls();
$urlOk = URL::getInstance()->absoluteUrl('/module/paypal/ok/' . $order->getId());
$urlCancel = URL::getInstance()->absoluteUrl('/module/paypal/cancel/' . $order->getId());
$redirectUrls->setReturnUrl($urlOk);
$redirectUrls->setCancelUrl($urlCancel);
return $redirectUrls;
}
/**
* @param Cart $cart
* @return RedirectUrls
*/
public function getRedirectCartUrls(Cart $cart)
{
$redirectUrls = new RedirectUrls();
$urlOk = URL::getInstance()->absoluteUrl('/module/paypal/express/checkout/ok/' . $cart->getId());
$urlCancel = URL::getInstance()->absoluteUrl('/module/paypal/express/checkout/ko/' . $cart->getId());
$redirectUrls->setReturnUrl($urlOk);
$redirectUrls->setCancelUrl($urlCancel);
return $redirectUrls;
}
/**
* @param Cart $cart
* @return RedirectUrls
*/
public function getRedirectInvoiceUrls(Cart $cart)
{
$redirectUrls = new RedirectUrls();
$urlOk = URL::getInstance()->absoluteUrl('/module/paypal/invoice/express/checkout/ok/' . $cart->getId());
$urlCancel = URL::getInstance()->absoluteUrl('/module/paypal/invoice/express/checkout/ko/' . $cart->getId());
$redirectUrls->setReturnUrl($urlOk);
$redirectUrls->setCancelUrl($urlCancel);
return $redirectUrls;
}
}

View File

@@ -0,0 +1,14 @@
{
"name": "thelia/paypal-module",
"description": "PayPal module for Thelia ecommerce solution ",
"license": "LGPL-3.0+",
"type": "thelia-module",
"require": {
"thelia/installer": "~1.1",
"paypal/rest-api-sdk-php": "1.7.1",
"wazaari/monolog-mysql": "1.0.3"
},
"extra": {
"installer-name": "PayPal"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -0,0 +1,38 @@
{render_form_field field="locale"}
<div class="panel panel-default">
<div class="panel-heading">
{intl l="Global informations of this planified payment" d="paypal.bo.default"}
</div>
<div class="panel-body">
<div class="row">
<div class="col-md-4">
{render_form_field field="title"}
</div>
</div>
<div class="row">
<div class="col-md-12">
{render_form_field field="description"}
</div>
</div>
<div class="row">
<div class="col-md-4">
{render_form_field field="frequency_interval"}
</div>
<div class="col-md-4">
{render_form_field field="frequency"}
</div>
<div class="col-md-4">
{render_form_field field="cycle"}
</div>
</div>
<div class="row">
<div class="col-md-4">
{render_form_field field="min_amount"}
</div>
<div class="col-md-4">
{render_form_field field="max_amount"}
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,11 @@
<script>
$('.paypal-log').on('click', function(){
var details = $($(this).data('details'));
if (details.hasClass('hidden')) {
details.removeClass('hidden');
} else {
details.addClass('hidden');
}
});
</script>

View File

@@ -0,0 +1,20 @@
<tr{if $log->getHook()} style="cursor: pointer;"{/if}>
<td>{format_date date=$CREATE_DATE}</td>
<td class="paypal-log" data-details="#details-{$log->getId()}">
{if $log->getHook()}
{$log->getHook()}&nbsp;({intl l="See webhook details" d="paypal.bo.default"})
<div id="details-{$log->getId()}" class="hidden">
{$log->getMessage() nofilter}
</div>
{else}
{$log->getMessage() nofilter}
{/if}
</td>
<td><a title="{intl l='Edit this customer'}" href="{url path='/admin/customer/update' customer_id=$log->getCustomerId()}">{$log->getCustomerId()}</a></td>
<td><a href="{url path="/admin/order/update/%id" id=$log->getOrderId()}">{$log->getOrderId()}</a></td>
<td>
<strong>{$log->getHook()}</strong>
</td>
<td>{intl l="critical_{$log->getLevel()}" d="paypal.bo.default"}</td>
</tr>

View File

@@ -0,0 +1,6 @@
<!-- Tab menu -->
<ul id="tabbed-menu" class="nav nav-tabs">
<li {if $selectedMenu eq 'general'}class="active"{/if}><a href="{if $selectedMenu eq 'general'}#{else}{url path='/admin/module/paypal'}{/if}">{intl l="General configuration" d='paypal.bo.default'}</a></li>
<li {if $selectedMenu eq 'planifiedPayment'}class="active"{/if}><a href="{if $selectedMenu eq 'planifiedPayment'}#{else}{url path='/admin/module/paypal/configure/planified'}{/if}">{intl l='Planified payment' d="paypal.bo.default"}</a></li>
<li {if $selectedMenu eq 'log'}class="active"{/if}><a href="{if $selectedMenu eq 'log'}#{else}{url path='/admin/module/paypal/configure/log'}{/if}">{intl l='Log' d="paypal.bo.default"}</a></li>
</ul>

View File

@@ -0,0 +1,236 @@
<div class="row">
<div class="col-md-12">
<div class="general-block-decorator">
{include file="paypal/menu/menu.html" selectedMenu="general"}
<div class="tab-content">
<!-- Countries managing tab -->
<div class="tab-pane active form-container">
{form name="paypal_form_configure"}
{if $form_error}
<div class="alert alert-danger">{$form_error_message}</div>
{elseif $general_error}
<div class="alert alert-danger">
{$general_error}
</div>
{/if}
<form action="{url path="/admin/module/paypal/configure"}" method="post">
{form_hidden_fields form=$form}
<div class="row">
<div class="col-md-12">
{include file = "includes/inner-form-toolbar.html"
hide_flags = true
page_url = "{url path='/admin/module/Paypal'}"
close_url = "{url path='/admin/modules'}"
}
</div>
</div>
<div class="row">
<div class="col-md-4">
<div class="col-md-8">
<h3>
<span class="label label-primary">1</span>
{intl l="SandBox configuration" d="paypal.bo.default"}
<span class="glyphicon glyphicon-info-sign"></span>
</h3>
</div>
<div class="col-md-4">
<div class="tips__img">
<img src="{image file='assets/paypal_conf1.png' source="PayPal"}" alt="Payment configuration" class="img-responsive" />
</div>
</div>
<div class="row">
<div class="col-md-12">
{custom_render_form_field form=$form field="sandbox"}
<input type="checkbox" {form_field_attributes form=$form field="sandbox"} {if $sandbox}checked{/if}>
{$label}
{/custom_render_form_field}
{render_form_field form=$form field="sandbox_login" value=$sandbox_login}
{render_form_field form=$form field="sandbox_password" value=$sandbox_password}
{render_form_field form=$form field="sandbox_merchant_id" value=$sandbox_merchant_id}
{render_form_field form=$form field="allowed_ip_list" value=$allowed_ip_list}
</div>
</div>
<div class="row">
<div class="col-md-12 alert alert-info">
<h4 class="text-uppercase">
<span class="glyphicon glyphicon-info-sign"></span>&nbsp;{intl l="Help" d="paypal.bo.default"}&nbsp;:&nbsp;{intl l="Configuration" d="paypal.bo.default"}
</h4>
- {intl l="Log In on <a target='_blank' href='https://developer.paypal.com'>developer.paypal.com</a>" d="paypal.bo.default"}<br />
- {intl l="Create REST API apps <a target='_blank' href='https://developer.paypal.com/developer/applications/'>here</a>" d="paypal.bo.default"}<br />
- {intl l="Click on Create App" d="paypal.bo.default"}<br />
- {intl l="Fill the fields : App Name & Sandbox developer account" d="paypal.bo.default"}<br />
- {intl l="Click on Create App" d="paypal.bo.default"}<br />
- {intl l="Copy & Paste the Client ID in the form below" d="paypal.bo.default"}<br />
- {intl l="Copy & Paste the Client SECRET in the form below" d="paypal.bo.default"}<br />
- <strong>{intl l="In SANDBOX WEBHOOKS" d="paypal.bo.default"}&nbsp;:</strong><br />
- &nbsp;&nbsp;&nbsp;&nbsp;{intl l="Add Webhook" d="paypal.bo.default"}<br />
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{url path="/module/paypal/webhook/all/events"}<br />
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{intl l="Check 'All events'" d="paypal.bo.default"}<br />
- <strong>{intl l="In SANDBOX APP SETTINGS" d="paypal.bo.default"}&nbsp;:</strong><br />
- &nbsp;&nbsp;&nbsp;&nbsp;{intl l="Return URL" d="paypal.bo.default"}<br />
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{navigate to="index"}<br />
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{url path="/module/paypal/login/ok"}<br />
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{url path="/module/paypal/agreement/ok"}<br />
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{url path="/module/paypal/agreement/ko"}<br />
- <label class="alert alert-danger">{intl l="This urls can take 3 hours to be taken in consideration" d="paypal.bo.default"}</label><br />
- {intl l="Check" d="paypal.bo.default"}&nbsp;<strong>{intl l="Accept payments" d="paypal.bo.default"}&nbsp;</strong><br />
- &nbsp;&nbsp;&nbsp;&nbsp;{intl l="Check" d="paypal.bo.default"}&nbsp;<strong>{intl l="Future Payments" d="paypal.bo.default"}</strong><br />
- &nbsp;&nbsp;&nbsp;&nbsp;{intl l="Check" d="paypal.bo.default"}&nbsp;<strong>{intl l="Billing agreements" d="paypal.bo.default"}</strong><br />
- {intl l="Check" d="paypal.bo.default"}&nbsp;<strong>{intl l="Invoicing" d="paypal.bo.default"}&nbsp;</strong><br />
- {intl l="Check" d="paypal.bo.default"}&nbsp;<strong>{intl l="Payouts" d="paypal.bo.default"}&nbsp;</strong><br />
- {intl l="Check" d="paypal.bo.default"}&nbsp;<strong>{intl l="PayPal Here" d="paypal.bo.default"}&nbsp;</strong><br />
- {intl l="Check" d="paypal.bo.default"}&nbsp;<strong>{intl l="Log In with PayPal" d="paypal.bo.default"}&nbsp;</strong><br />
- &nbsp;&nbsp;&nbsp;&nbsp;{intl l="Check" d="paypal.bo.default"}&nbsp;<strong>{intl l="Personal Information" d="paypal.bo.default"}</strong><br />
- &nbsp;&nbsp;&nbsp;&nbsp;{intl l="Check" d="paypal.bo.default"}&nbsp;<strong>{intl l="Address Information" d="paypal.bo.default"}</strong><br />
- &nbsp;&nbsp;&nbsp;&nbsp;{intl l="Check" d="paypal.bo.default"}&nbsp;<strong>{intl l="Account Information" d="paypal.bo.default"}</strong><br />
- &nbsp;&nbsp;&nbsp;&nbsp;{intl l="Check" d="paypal.bo.default"}&nbsp;<strong>{intl l="Use Seamless Checkout" d="paypal.bo.default"}</strong><br />
- &nbsp;&nbsp;&nbsp;&nbsp;{intl l="Check" d="paypal.bo.default"}&nbsp;<strong>{intl l="Allow the customers who haven't yet confirmed their email address with PayPal, to log in to your app" d="paypal.bo.default"}</strong><br />
- <strong>{intl l="That's it !" d="paypal.bo.default"}</strong><br />
</div>
</div>
</div>
<div class="col-md-4">
<div class="col-md-8">
<h3>
<span class="label label-primary">2</span>
{intl l="Production configuration" d="paypal.bo.default"}
</h3>
</div>
<div class="col-md-4">
<div class="tips__img">
<img src="{image file='assets/paypal_conf2.png' source="PayPal"}" alt="Payment configuration" class="img-responsive" />
</div>
</div>
<div class="row">
<div class="col-md-12">
{render_form_field form=$form field="login" value=$login}
{render_form_field form=$form field="password" value=$password}
{render_form_field form=$form field="merchant_id" value=$merchant_id}
</div>
</div>
<div class="row">
<div class="col-md-12 alert alert-info">
<h4 class="text-uppercase">
<span class="glyphicon glyphicon-info-sign"></span>&nbsp;{intl l="Help" d="paypal.bo.default"}&nbsp;:&nbsp;{intl l="Configuration" d="paypal.bo.default"}
</h4>
- {intl l="In your PayPal page API configuration" d="paypal.bo.default"}<br />
- {intl l="Click on the Live Button" d="paypal.bo.default"}<br />
<img src="{image file='assets/paypal_live_button.png' source="PayPal"}" alt="Payment configuration" class="img-responsive" /><br />
- {intl l="And configure it like the SandBox" d="paypal.bo.default"}<br />
</div>
</div>
</div>
<div class="col-md-4">
<h3>
<span class="label label-primary">3</span>
{intl l="Payment configuration" d="paypal.bo.default"}
</h3>
<div class="row">
<div class="tips__img">
<img src="{image file='assets/paypal_conf3.png' source="PayPal"}" alt="Payment configuration" class="img-responsive" />
</div>
<div class="col-md-12">
{custom_render_form_field form=$form field="method_paypal"}
<input type="checkbox" {form_field_attributes form=$form field="method_paypal"} {if $method_paypal}checked{/if}>
{$label}
{/custom_render_form_field}
{custom_render_form_field form=$form field="method_paypal_with_in_context"}
<input type="checkbox" {form_field_attributes form=$form field="method_paypal_with_in_context"} {if $method_paypal_with_in_context}checked{/if}>
{$label}
{/custom_render_form_field}
{custom_render_form_field form=$form field="method_express_checkout"}
<input type="checkbox" {form_field_attributes form=$form field="method_express_checkout"} {if $method_express_checkout}checked{/if}>
{$label}
{/custom_render_form_field}
{custom_render_form_field form=$form field="method_credit_card"}
<input type="checkbox" {form_field_attributes form=$form field="method_credit_card"} {if $method_credit_card}checked{/if}>
{$label}
{/custom_render_form_field}
<div class="well well-sm alert-danger">
<span class="glyphicon glyphicon-info-sign"></span>
{intl d='paypal.bo.default' l='This method works only with PayPal PRO UK account. Please contact PayPal to upgrade your account if you need this service. For more informations, go <a target="_blank" href="https://developer.paypal.com/docs/integration/direct/payments/accept-credit-cards/">here</a>'}
</div>
{custom_render_form_field form=$form field="method_planified_payment"}
<input type="checkbox" {form_field_attributes form=$form field="method_planified_payment"} {if $method_planified_payment}checked{/if}>
{$label}
{/custom_render_form_field}
<div class="well well-sm alert-danger">
<span class="glyphicon glyphicon-info-sign"></span>
<strong>{intl d='paypal.bo.default' l='This method use PayPal webhooks and works only in HTTPS !'}</strong>
</div>
<div class="well well-sm">
<span class="glyphicon glyphicon-info-sign"></span>
{intl d='paypal.bo.default' l='You can add some planified payment <a href="%url">here</a>.' url={url path="/admin/module/paypal/configure/planified"}}
</div>
{custom_render_form_field form=$form field="send_confirmation_message_only_if_paid"}
<input type="checkbox" {form_field_attributes form=$form field="send_confirmation_message_only_if_paid"} {if $send_confirmation_message_only_if_paid}checked{/if}>
{$label}
{/custom_render_form_field}
{custom_render_form_field form=$form field="send_payment_confirmation_message"}
<input type="checkbox" {form_field_attributes form=$form field="send_payment_confirmation_message"} {if $send_payment_confirmation_message}checked{/if}>
{$label}
{/custom_render_form_field}
{custom_render_form_field form=$form field="send_recursive_message"}
<input type="checkbox" {form_field_attributes form=$form field="send_recursive_message"} {if $send_recursive_message}checked{/if}>
{$label}
{/custom_render_form_field}
<div class="well well-sm">
<span class="glyphicon glyphicon-info-sign"></span>
{intl d='paypal.bo.default' l='You can <a href="%url">edit the payment confirmation email</a> sent to the customer after a successful payment.' url={url path="/admin/configuration/messages"}}
</div>
{custom_render_form_field form=$form field="minimum_amount"}
<div class="input-group">
<input type="text" {form_field_attributes form=$form field="minimum_amount" value=$minimum_amount}>
<span class="input-group-addon">{currency attr='symbol'}</span>
</div>
{/custom_render_form_field}
{custom_render_form_field form=$form field="maximum_amount"}
<div class="input-group">
<input type="text" {form_field_attributes form=$form field="maximum_amount" value=$maximum_amount}>
<span class="input-group-addon">{currency attr='symbol'}</span>
</div>
{/custom_render_form_field}
{render_form_field form=$form field="cart_item_count" value=$cart_item_count}
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
{include file = "includes/inner-form-toolbar.html"
hide_flags = true
page_url = "{url path='/admin/module/Paypal'}"
close_url = "{url path='/admin/modules'}"
}
</div>
</div>
</form>
{/form}
</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1 @@
{include file = "paypal/includes/paypal-log-row-js.html"}

View File

@@ -0,0 +1,18 @@
<table class="table table-striped table-condensed">
<thead>
<tr>
<th>{intl l='Date' d="paypal.bo.default"}</th>
<th>{intl l='Details' d="paypal.bo.default"}</th>
<th>{intl l="Customer ID" d="paypal.bo.default"}</th>
<th>{intl l="Order ID" d="paypal.bo.default"}</th>
<th>{intl l="Webhook" d="paypal.bo.default"}</th>
<th>{intl l="Level" d="paypal.bo.default"}</th>
</tr>
</thead>
<tbody>
{loop name="paypal_log" type="paypal_log" backend_context=true order_id=$order_id order="date-reverse"}
{include file = "paypal/includes/paypal-log-row.html"}
{/loop}
</tbody>
</table>

View File

@@ -0,0 +1,105 @@
{extends file="admin-layout.tpl"}
{block name="main-content"}
<div class="clearfix">
<ul class="breadcrumb pull-left">
<li>
<a href="{url path='/admin/home'}">{intl l="Home"}</a>
</li>
<li>
<a href="{url path='/admin/modules'}">{intl l="Modules"}</a>
</li>
<li>
<a href="{url path='/admin/module/PayPal'}">{intl l="PayPal"}</a>
</li>
<li>
<a href="{url path='/admin/module/paypal/configure/log'}">{intl l="Automatic PayPal logs" d="paypal.bo.default"}</a>
</li>
</ul>
</div>
<div class="row">
<div class="col-md-12">
<div class="general-block-decorator">
{include file="paypal/menu/menu.html" selectedMenu="log"}
<div class="tab-content">
<!-- Countries managing tab -->
<div class="tab-pane active form-container">
<div class="row">
<div class="col-md-12 general-block-decorator">
<h3>
<span class="label label-primary">1</span>
{intl l="Automatic PayPal logs" d="paypal.bo.default"}
</h3>
<div class="col-md-12 alert alert-info">
<div class="col-md-8">
<h4 class="text-uppercase">
<span class="glyphicon glyphicon-info-sign"></span>&nbsp;{intl l="Help" d="paypal.bo.default"}&nbsp;:
</h4>
<div class="tips">
{intl l="This is where we log all the transactions made with PayPal. PayPal webhooks also automatically feed these logs." d="paypal.bo.default"}
<br />{intl l="This informations can be found directly in concerned order details." d="paypal.bo.default"}
</div>
</div>
<div class="col-md-4">
<div class="tips__img">
<img src="{image file='assets/paypal_webhook.png' source="PayPal"}" alt="Payment configuration" class="img-responsive" />
</div>
</div>
</div>
{$page = $smarty.get.page|default:1}
{$limit = $smarty.get.limit|default:100}
<div class="form-container">
<div class="row">
<div class="col-md-12">
<table class="table table-striped table-condensed">
<thead>
<tr>
<th>{intl l='Date' d="paypal.bo.default"}</th>
<th>{intl l='Details' d="paypal.bo.default"}</th>
<th>{intl l="Customer ID" d="paypal.bo.default"}</th>
<th>{intl l="Order ID" d="paypal.bo.default"}</th>
<th>{intl l="Webhook" d="paypal.bo.default"}</th>
<th>{intl l="Level" d="paypal.bo.default"}</th>
</tr>
</thead>
<tbody>
{loop name="paypal_log" type="paypal_log" backend_context=true order="date-reverse" page=$page limit=$limit}
{include file = "paypal/includes/paypal-log-row.html"}
{/loop}
</tbody>
<tfoot>
<tr>
<td colspan="100">
{include
file = "includes/pagination.html"
loop_ref = "paypal_log"
max_page_count = $limit
page_url = {url path="/admin/module/paypal/configure/log"}
}
</td>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{/block}
{block name="javascript-initialization"}
{include file = "paypal/includes/paypal-log-row-js.html"}
{/block}

View File

@@ -0,0 +1,86 @@
{extends file="admin-layout.tpl"}
{block name="no-return-functions"}
{$admin_current_location = 'module'}
{/block}
{block name="page-title"}{intl l='Edit planified payment' d="paypal.bo.default"}{/block}
{block name="main-content"}
<div class="planified-payment edit-planified-payment">
<div id="wrapper" class="container">
{loop name="paypal_planified_payment" type="paypal_planified_payment" id=$planifiedPaymentId backend_context=true}
<nav>
<ul class="breadcrumb">
<li><a href="{url path='admin/home'}">{intl l='Home'}</a></li>
<li><a href="{url path='/admin/module/paypal/configure/planified'}">{intl l='Planified payments' d='paypal.bo.default'}</a></li>
<li>{intl l='Editing planified payment "%title"' d="paypal.bo.default" title=$planifiedPayment->getTitle()}</li>
</ul>
</nav>
<div class="row">
<div class="col-md-12 general-block-decorator">
<div class="row">
<div class="col-md-7 title">
{intl l='Edit planified payment %title' d="paypal.bo.default" title=$planifiedPayment->getTitle()}
</div>
</div>
<ul class="nav nav-tabs" id="tabbed-menu">
<li class="active">
<a href="#general" data-toggle="tab">{intl l="General description" d="paypal.bo.default"}</a>
</li>
</ul>
<div class="tab-content">
<div class="tab-pane fade active in" id="general">
<div class="form-container">
{form name="paypal_planified_payment_update_form"}
<form method="POST" action="{url path="/admin/module/paypal/configure/planified/%id" id=$planifiedPayment->getId()}" {form_enctype} class="clearfix">
{include file="includes/inner-form-toolbar.html" hide_flags=true close_url={url path="/admin/module/paypal/configure/planified"}}
<input type="hidden" name="current_tab" value="general"/>
{* Be sure to get the planified payment ID, even if the form could not be validated *}
<input type="hidden" name="planifiedPaymentId" value="{$planifiedPayment->getId()}" />
{form_hidden_fields}
{render_form_field field="id"}
{render_form_field field="success_url" value={url path="/admin/module/paypal/configure/planified"}}
{if $form_error}
<div class="alert alert-danger">{$form_error_message}</div>
{/if}
<div class="row">
{include file = "paypal/form/create-or-update-planified-payment-form.html"}
</div>
{include
file="includes/inner-form-toolbar.html"
hide_submit_buttons = false
hide_flags = true
close_url={url path="/admin/module/paypal/configure/planified"}
}
<small>{intl l='Planified payment created on %date_create. Last modification: %date_change' d="paypal.bo.default" date_create={format_date date=$CREATE_DATE} date_change={format_date date=$UPDATE_DATE} }</small>
</form>
{/form}
</div>
</div>
</div>
</div>
</div>
{/loop}
</div>
</div>
{/block}

View File

@@ -0,0 +1,185 @@
{extends file="admin-layout.tpl"}
{block name="main-content"}
<div class="clearfix">
<ul class="breadcrumb pull-left">
<li>
<a href="{url path='/admin/home'}">{intl l="Home"}</a>
</li>
<li>
<a href="{url path='/admin/modules'}">{intl l="Modules"}</a>
</li>
<li>
<a href="{url path='/admin/module/PayPal'}">{intl l="PayPal"}</a>
</li>
<li>
<a href="{url path='/admin/module/paypal/configure/planified'}">{intl l="Planified payment" d="paypal.bo.default"}</a>
</li>
</ul>
</div>
<div class="row">
<div class="col-md-12">
<div class="general-block-decorator">
{include file="paypal/menu/menu.html" selectedMenu="planifiedPayment"}
<div class="tab-content">
<!-- Countries managing tab -->
<div class="tab-pane active form-container">
<div class="row">
<div class="col-md-12 general-block-decorator">
<h3>
<span class="label label-primary">1</span>
{intl l="Planified payment configuration" d="paypal.bo.default"}
</h3>
<div class="col-md-12 alert alert-info">
<div class="col-md-8">
<h4 class="text-uppercase">
<span class="glyphicon glyphicon-info-sign"></span>&nbsp;{intl l="Help" d="paypal.bo.default"}&nbsp;:
</h4>
<div class="tips">
{intl l="This feature uses PayPal's Billing Plan and Agreement. It allows debiting a client recursively directly from PayPal." d="paypal.bo.default"}
<br />{intl l="These planned payments will appear in step 4 of the purchase tunnel when selecting the payment method." d="paypal.bo.default"}
</div>
</div>
<div class="col-md-4">
<div class="tips__img">
<img src="{image file='assets/paypal_agreement.jpeg' source="PayPal"}" alt="Payment configuration" class="img-responsive" />
</div>
</div>
</div>
<div class="form-container">
<div class="row">
<div class="col-md-12">
<table class="table table-striped table-condensed">
<caption class="clearfix">
{intl l="List of planified payments" d="paypal.bo.default"}
<span class="pull-right">
<button class="btn btn-primary" title="{intl l='Add a planified payment' d='paypal.bo.default'}" href="#creation_dialog" data-toggle="modal">
<span class="glyphicon glyphicon-plus-sign"></span> {intl l='Add a planified payment' d='paypal.bo.default'}
</button>
</span>
</caption>
<thead>
<tr>
<th>
{intl l='Title' d="paypal.bo.default"}
</th>
<th>
{intl l='Details' d="paypal.bo.default"}
</th>
<th class="actions"></th>
</tr>
</thead>
<tbody>
{loop name="paypal_planified_payment" type="paypal_planified_payment" backend_context=true order=$order}
<tr>
<td>
<strong>{$planifiedPayment->getTitle()}&nbsp;;</strong><br />
{$planifiedPayment->getDescription()}
</td>
<td>
<strong>{intl l='Frequency interval' d="paypal.bo.default"}&nbsp;:&nbsp;</strong>{$planifiedPayment->getFrequencyInterval()}<br />
<strong>{intl l='Frequency' d="paypal.bo.default"}&nbsp;:&nbsp;</strong>{$planifiedPayment->getFrequency()}<br />
<strong>{intl l='Cycle' d="paypal.bo.default"}&nbsp;:&nbsp;</strong>{$planifiedPayment->getCycle()}<br />
<strong>{intl l='Min amount' d="paypal.bo.default"}&nbsp;:&nbsp;</strong>{if $planifiedPayment->getMinAmount() > 0}{format_money number=$planifiedPayment->getMinAmount()}{else}{intl l='None' d="paypal.bo.default"}{/if}<br />
<strong>{intl l='Max amount' d="paypal.bo.default"}&nbsp;:&nbsp;</strong>{if $planifiedPayment->getMaxAmount() > 0}{format_money number=$planifiedPayment->getMaxAmount()}{else}{intl l='None' d="paypal.bo.default"}{/if}<br />
</td>
<td class="actions">
<div class="btn-group btn-group-sm" >
<a class="btn btn-primary" title="{intl l='Edit this planified payment' d='paypal.bo.default'}" href="{url path="/admin/module/paypal/configure/planified/%id" id=$planifiedPayment->getId()}">
<span class="glyphicon glyphicon-edit"></span>
</a>
<a class="btn btn-danger planified-payment-delete" title="{intl l='Delete this planified payment' d='paypal.bo.default'}" href="#delete_dialog" data-id="{$planifiedPayment->getId()}" data-toggle="modal">
<span class="glyphicon glyphicon-trash"></span>
</a>
</div>
</td>
</tr>
{/loop}
{elseloop rel="paypal_planified_payment"}
<tr>
<td colspan="100">
<div class="alert alert-info">
{intl l="No planified payment has been created yet. Click the + button to create one." d="paypal.bo.default"}
</div>
</td>
</tr>
{/elseloop}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{* Adding a new planified payment *}
{form name="paypal_planified_payment_create_form"}
{* Capture the dialog body, to pass it to the generic dialog *}
{capture "creation_dialog"}
{form_hidden_fields}
{include file = "paypal/form/create-or-update-planified-payment-form.html"}
{render_form_field field="success_url" value={url path='/admin/module/paypal/configure/planified'}}
{/capture}
{include
file = "includes/generic-create-dialog.html"
dialog_id = "creation_dialog"
dialog_title = {intl l="Create a new planified payment" d="paypal.bo.default"}
dialog_body = {$smarty.capture.creation_dialog nofilter}
dialog_ok_label = {intl l="Create this planified payment" d="paypal.bo.default"}
form_action = {url path='/admin/module/paypal/configure/planified/create'}
form_enctype = {form_enctype}
form_error_message = $form_error_message
}
{/form}
{* Delete confirmation dialog *}
{capture "delete_dialog"}
<input type="hidden" name="planifiedPaymentId" id="planifiedPaymentId" value="" />
{/capture}
{include
file = "includes/generic-confirm-dialog.html"
dialog_id = "delete_dialog"
dialog_title = {intl l="Delete planified payment" d="paypal.bo.default"}
dialog_message = {intl l="Do you really want to delete this planified payment ?" d="paypal.bo.default"}
form_action = {token_url path='/admin/module/paypal/configure/planified/create/delete'}
form_content = {$smarty.capture.delete_dialog nofilter}
}
{/block}
{block name="javascript-initialization"}
<script>
$(function() {
// Set proper planified ID in delete from
$('a.planified-payment-delete').click(function(ev) {
$('#planifiedPaymentId').val($(this).data('id'));
});
});
</script>
{/block}

View File

@@ -0,0 +1,23 @@
{extends file="email-layout.tpl"}
{* Do not provide a "Open in browser" link *}
{block name="browser"}{/block}
{* No pre-header *}
{block name="pre-header"}{/block}
{* Subject *}
{block name="email-subject"}{intl d='paypal.mail.default' l="Payment of your order %ref" ref={$order_ref}}{/block}
{* Title *}
{block name="email-title"}{intl d='paypal.mail.default' l="The payment of your order %ref is confirmed" ref={$order_ref}}{/block}
{* Content *}
{block name="email-content"}
<p>
<a href="{url path="/account"}">
{intl l="View this order in your account at %shop_name" shop_name={config key="store_name"}}
</a>
</p>
<p>{intl d='paypal.email.default' l='Thank you again for your purchase.'}</p>
<p>{intl d='paypal.email.default' l='The %store_name team.' store_name={config key="store_name"}}</p>
{/block}

View File

@@ -0,0 +1,9 @@
{intl d='paypal.email.default' l='Dear customer'},
{intl d='paypal.email.default' l='This is a confirmation of the payment of your order %ref via Paypal on our shop.' ref=$order_ref}
{intl d='paypal.email.default' l='Your invoice is now available in your customer account at %url.'} url={config key="url_site"}}
{intl d='paypal.email.default' l='Thank you again for your purchase.'}
{intl d='paypal.email.default' l='The %store_name team.' store_name={config key="store_name"}}

View File

@@ -0,0 +1,23 @@
{extends file="email-layout.tpl"}
{* Do not provide a "Open in browser" link *}
{block name="browser"}{/block}
{* No pre-header *}
{block name="pre-header"}{/block}
{* Subject *}
{block name="email-subject"}{intl d='paypal.mail.default' l="Payment of your order %ref" ref={$order_ref}}{/block}
{* Title *}
{block name="email-title"}{intl d='paypal.mail.default' l="The payment of your order %ref is confirmed" ref={$order_ref}}{/block}
{* Content *}
{block name="email-content"}
<p>
<a href="{url path="/account"}">
{intl l="View this order in your account at %shop_name" shop_name={config key="store_name"}}
</a>
</p>
<p>{intl d='paypal.email.default' l='Thank you again for your purchase.'}</p>
<p>{intl d='paypal.email.default' l='The %store_name team.' store_name={config key="store_name"}}</p>
{/block}

View File

@@ -0,0 +1,9 @@
{intl d='paypal.email.default' l='Dear customer'},
{intl d='paypal.email.default' l='This is a confirmation of the payment of your order %ref via Paypal on our shop.' ref=$order_ref}
{intl d='paypal.email.default' l='Your invoice is now available in your customer account at %url.'} url={config key="url_site"}}
{intl d='paypal.email.default' l='Thank you again for your purchase.'}
{intl d='paypal.email.default' l='The %store_name team.' store_name={config key="store_name"}}

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -0,0 +1,11 @@
<form id="paypal-express-checkout" method="post" action="{url path='/module/paypal/express/checkout'}" class="pull-right"></form>
<script>
window.paypalCheckoutReady = function() {
paypal.checkout.setup('{$paypal_merchantid}', {
environment: '{$paypal_mode}',
container: 'paypal-express-checkout',
locale: '{lang attr="locale"}'
});
};
</script>
<script src="//www.paypalobjects.com/api/checkout.js" async></script>

View File

@@ -0,0 +1,85 @@
<fieldset class="col-xs-11 col-xs-offset-1">
<input type="radio" id="{$label_attr.for}{$choice->label}" class="paypal-method" name="{$name}" data-content="#content-paypal-credit-card" value="{$choice->label}" {if $value == $choice->label}checked{/if}/>
<label class="control-label" for="{$label_attr.for}{$choice->label}"><strong>{intl l=$choice->label d="paypal.fo.default"}</strong>&nbsp;:<br />{if $required} <span class="required">*</span>{/if}</label>
<img src="{image file='assets/cards-logo.jpg' source="PayPal"}" border="0" alt="CB / VISA / Mastercard" />
<div id="content-paypal-credit-card" class="hidden">
{form_field field='paypal_credit_card_type.card_type'}
<div class="form-group row{if $error} has-error{/if}">
<label class="control-label col-sm-3" for="{$label_attr.for}">{$label}{if $required} <span class="required">*</span>{/if}</label>
<div class="control-input col-sm-5">
<select name="{$name}" id="{$label_attr.for}">
{foreach from=$choices item=type}
<option value="{$type->value}">{$type->label}</option>
{/foreach}
</select>
{if $error }
<span class="help-block">{$message}</span>
{assign var="error_focus" value="true"}
{/if}
</div>
</div>
{/form_field}
{form_field field='paypal_credit_card_type.card_number'}
<div class="form-group row{if $error} has-error{/if}">
<label class="control-label col-sm-3" for="{$label_attr.for}">{$label}{if $required} <span class="required">*</span>{/if}</label>
<div class="control-input col-sm-5">
<input type="text" name="{$name}" id="{$label_attr.for}" value="" />
</div>
{if $error }
<span class="help-block">{$message}</span>
{assign var="error_focus" value="true"}
{/if}
</div>
{/form_field}
{form_field field='paypal_credit_card_type.card_expire_month'}
<div class="form-group row{if $error} has-error{/if}">
<label class="control-label col-sm-3" for="{$label_attr.for}">{$label}{if $required} <span class="required">*</span>{/if}</label>
<div class="control-input col-sm-5">
<select name="{$name}" id="{$label_attr.for}">
{foreach from=$choices item=type}
<option value="{$type->value}">{$type->label}</option>
{/foreach}
</select>
{if $error }
<span class="help-block">{$message}</span>
{assign var="error_focus" value="true"}
{/if}
</div>
</div>
{/form_field}
{form_field field='paypal_credit_card_type.card_expire_year'}
<div class="form-group row{if $error} has-error{/if}">
<label class="control-label col-sm-3" for="{$label_attr.for}">{$label}{if $required} <span class="required">*</span>{/if}</label>
<div class="control-input col-sm-5">
<select name="{$name}" id="{$label_attr.for}">
{foreach from=$choices item=type}
<option value="{$type->value}">{$type->label}</option>
{/foreach}
</select>
{if $error }
<span class="help-block">{$message}</span>
{assign var="error_focus" value="true"}
{/if}
</div>
</div>
{/form_field}
{form_field field='paypal_credit_card_type.card_cvv'}
<div class="form-group row{if $error} has-error{/if}">
<label class="control-label col-sm-3" for="{$label_attr.for}">{$label}{if $required} <span class="required">*</span>{/if}</label>
<div class="control-input col-sm-5">
<input type="text" name="{$name}" id="{$label_attr.for}" value="" />
{if $error }
<span class="help-block">{$message}</span>
{assign var="error_focus" value="true"}
{/if}
</div>
</div>
{/form_field}
</div>
</fieldset>

View File

@@ -0,0 +1,17 @@
<fieldset class="col-xs-11 col-xs-offset-1">
{if $method_paypal_with_in_context}
<input type="radio" id="{$label_attr.for}{$choice->label}-express" class="paypal-method paypal-express-method" name="{$name}" value="{$choice->label}" {if $value == $choice->label}checked{/if}/>
<label class="control-label" for="{$label_attr.for}{$choice->label}-express">
<strong>{intl l=$choice->label d="paypal.fo.default"}</strong>&nbsp;:
<img src="{image file='assets/paypal-logo.png' source="PayPal"}" border="0" alt="PayPal account" />
</label>
{else}
<input type="radio" id="{$label_attr.for}{$choice->label}" class="paypal-method" name="{$name}" value="{$choice->label}" {if $value == $choice->label}checked{/if}/>
<label class="control-label" for="{$label_attr.for}{$choice->label}">
<strong>{intl l=$choice->label d="paypal.fo.default"}</strong>&nbsp;:
<img src="{image file='assets/paypal-logo.png' source="PayPal"}" border="0" alt="PayPal account" />
</label>
{/if}
</fieldset>

View File

@@ -0,0 +1,26 @@
{assign var="methodName" value=$name}
{form_field field='paypal_planified_payment'}
{if count($choices) > 0}
<fieldset class="col-xs-11 col-xs-offset-1">
<input type="radio" id="{$label_attr.for}{$choice->label}" class="paypal-method" name="{$methodName}" data-content="#content-paypal-planified-payment" value="{$choice->label}" {if $value == $choice->label}checked{/if}/>
<label class="control-label" for="{$label_attr.for}{$choice->label}"><strong>{intl l=$choice->label d="paypal.fo.default"}</strong>&nbsp;:<br />{if $required} <span class="required">*</span>{/if}</label>
<div id="content-paypal-planified-payment" class="hidden">
{foreach $choices as $choice}
{assign var="planifiedPayment" value=$choice->data}
<div class="form-group row{if $error} has-error{/if}">
<div class="control-input col-sm-5">
<input type="radio" id="{$label_attr.for}{$planifiedPayment->getId()}" name="{$name}" value="{$planifiedPayment->getId()}" {if $value == $planifiedPayment->getId()}checked{/if}/>
<label class="control-label" for="{$label_attr.for}{$planifiedPayment->getId()}"><strong>{$planifiedPayment->getTitle()}</strong>&nbsp;:<br />{if $required} <span class="required">*</span>{/if}</label>
<div class="row">
<div class="col-md-12">
{$planifiedPayment->getDescription()}
</div>
</div>
</div>
</div>
{/foreach}
</div>
</fieldset>
{/if}
{/form_field}

View File

@@ -0,0 +1,16 @@
<article>
<span id='lippButton'></span>
<script src='https://www.paypalobjects.com/js/external/api.js'></script>
<script>
paypal.use( ['login'], function (login) {
login.render ({
"appid":'{$paypal_appid}',
"authend":'{$paypal_authend}',
"scopes":"profile email address phone https://uri.paypal.com/services/paypalattributes",
"containerid":"lippButton",
"locale":"fr-fr",
"returnurl":'{url path="/module/paypal/login/ok"}'
});
});
</script>
</article>

View File

@@ -0,0 +1,7 @@
<script>
$('#form-cart-delivery button:submit').each(function() {
if (!$(this).hasClass('paypal')) {
$(this).addClass('hidden');
}
});
</script>

View File

@@ -0,0 +1,4 @@
<button class="btn btn-primary pull-right paypal" type="submit">
<i class="fa fa-chevron-right"></i>
{intl l='Finish payment with PayPal' d='paypal.fo.default'}
</button>

View File

@@ -0,0 +1,11 @@
<form id="paypal-express-checkout" method="post" action="{url path='/module/paypal/invoice/express/checkout'}" class="hidden"></form>
<script>
window.paypalCheckoutReady = function() {
paypal.checkout.setup('{$paypal_merchantid}', {
environment: '{$paypal_mode}',
container: 'paypal-express-checkout',
locale: '{lang attr="locale"}'
});
};
</script>
<script src="//www.paypalobjects.com/api/checkout.js" async></script>

Some files were not shown because too many files have changed in this diff Show More