+
+
+
diff --git a/afterpay/AfterpaySDK/code/SampleCode/Cancel.php b/afterpay/AfterpaySDK/code/SampleCode/Cancel.php
new file mode 100644
index 0000000..3574186
--- /dev/null
+++ b/afterpay/AfterpaySDK/code/SampleCode/Cancel.php
@@ -0,0 +1,6 @@
+
+
diff --git a/afterpay/AfterpaySDK/code/SampleCode/Confirm.php b/afterpay/AfterpaySDK/code/SampleCode/Confirm.php
new file mode 100644
index 0000000..7525667
--- /dev/null
+++ b/afterpay/AfterpaySDK/code/SampleCode/Confirm.php
@@ -0,0 +1,15 @@
+Capture Payment';
diff --git a/afterpay/AfterpaySDK/code/SampleCode/SampleCapturePayment.php b/afterpay/AfterpaySDK/code/SampleCode/SampleCapturePayment.php
new file mode 100644
index 0000000..f80c99c
--- /dev/null
+++ b/afterpay/AfterpaySDK/code/SampleCode/SampleCapturePayment.php
@@ -0,0 +1,69 @@
+callGetOrderApi($apiResponse['orderToken']);
+}
+//Set this Amount with Current Cart Amount.
+$cartAmount = '10.00';
+
+//Compare Afterpay Order Amount with current Cart Amount.
+//Need to pass this value from current cart. Need to validate if cart amount has been changed by the user
+
+$priceValidator = new PriceValidator();
+$priceValidatorResponse = $priceValidator->validateCartTotal($getOrderResponse,$cartAmount);
+
+//Merchant Reference Id or Order Id. Please pass this value from your system.
+$merchantReferenceId = 'merchantOrder-123433333';
+
+//If Order Status is confirmed and cart amount has not been changed, called capturePayment API
+if($apiResponse['status'] == "SUCCESS")
+{
+ $capturePaymentObj = new CapturePayment();
+ $capturePaymentResponse = $capturePaymentObj->processCapturePayment($apiResponse,$merchantReferenceId);
+}
+
+if($capturePaymentResponse->status == "APPROVED")
+{
+ echo('
Order Id '.$capturePaymentResponse->id.' is successfully placed with Afterpay');
+}
+else
+{
+ //Display the error response
+ var_dump($capturePaymentResponse);
+ exit;
+}
+//Store Payment Id in database for future reference
+
+$paymentId = $capturePaymentResponse->id;
+
+//Process Refund if required
+echo ' Process Refund';
+
+?>
\ No newline at end of file
diff --git a/afterpay/AfterpaySDK/code/SampleCode/SampleCreateOrder.php b/afterpay/AfterpaySDK/code/SampleCode/SampleCreateOrder.php
new file mode 100644
index 0000000..8b3d749
--- /dev/null
+++ b/afterpay/AfterpaySDK/code/SampleCode/SampleCreateOrder.php
@@ -0,0 +1,150 @@
+validateConsumer();
+
+/** End Of Consumer Property Settings */
+
+
+/* If Consumer validation is successful, proceed to create Billing and Shipping Address
+* Setup Properties for Billing Address
+*/
+
+$billingAddress = [];
+$billingAddress['name'] = 'Joe Consumer';
+$billingAddress['line1'] = 'Unit 1 16 Floor';
+$billingAddress['line2'] = '380 LaTrobe Street';
+$billingAddress['suburb'] = 'Melbourne';
+$billingAddress['state'] = 'VIC';
+$billingAddress['postcode'] = '3000';
+$billingAddress['countryCode'] = 'AU';
+$billingAddress['phoneNumber'] = '0400892011';
+
+//Create a Billing Address Object. Pass billing address array into constructor.
+$billingAddressObj = new BillingAddress($billingAddress);
+//Validate Billing Address Object
+//$isBillingAddressValid = $billingAddressObj->validateBillingAddress();
+
+/** End Of Billing Address Property settings */
+
+
+/* If Billing validation is correct, proceed to create Shipping Address
+* Setup Shipping Address
+* Shipping Amount and Shipping Courier
+*/
+
+$shippingAddress = [];
+$shippingAddress['name'] = 'Joe Consumer';
+$shippingAddress['line1'] = 'Unit 1 16 Floor';
+$shippingAddress['line2'] = '380 LaTrobe Street';
+$shippingAddress['suburb'] = 'Melbourne';
+$shippingAddress['state'] = 'VIC';
+$shippingAddress['postcode'] = '3000';
+$shippingAddress['countryCode'] = 'AU';
+$shippingAddress['phoneNumber'] = '0400892011';
+
+//Create a Shipping Address Object. Pass shipping address array into constructor.
+$shippingAddressObj = new ShippingAddress($shippingAddress);
+//Validate Shipping Address Object
+////Setup Shipping Amount if applicable (optional). No need to include for free shipping
+$shippingAmount = new Amount('10.00','AUD');
+//Shipping Courier Details. Name and Priority
+$shippingCourier = new ShippingCourier('FedEx','Standard');
+
+/** End Of Shipping Address Property settings */
+
+
+
+/* If Shipping validation is correct, proceed to create Item Object
+* Setup Item Details
+*
+*/
+//Pass Price and Currency in Amount Constructor
+$item1Price = new Amount('10.00','AUD');
+//Setup properties for purchased items. Pass name, SKU, Quantity and Price Object in Constructor
+//Pass Multiple items if required.
+$item1 = new Item('widget', '123412234', 1, $item1Price);
+$item2 = new Item('widget1', '123412234', 1, $item1Price);
+$item3 = new Item('widget2', '123412234', 1, $item1Price);
+//Setup Tax Amount if applicable (optional)
+$taxAmount = new Amount('10.00','AUD');
+//Setup Total Order Amount
+$totalAmount = new Amount('10.00','AUD');
+
+/*End of Item Setup */
+
+//Setup Confirm and Cancel URLs for order success and failure. Params are confirm URL and Cancel URL.
+$redirectUrl = new RedirectUrls('http://php-docker.local:8080/SampleCode/Confirm.php','http://php-docker.local:8080/SampleCode/Cancel.php');
+
+//Setup Discount Amount, if applicable. It's optional to set. Pass Discount name and Amount
+$discountAmount1 = new Amount('10.00','AUD');
+$discount1 = new Discount('Returning Customer Coupon',$discountAmount1);
+$discount2 = new Discount('Returning Customer Coupon1',$discountAmount1);
+$discount3 = new Discount('Returning Customer Coupon2',$discountAmount1);
+
+
+
+
+//Build a complete transaction
+$transaction = new Transaction();
+$transaction->setTotalAmount($totalAmount)
+ ->setConsumer($consumer)
+ ->setBilling($billingAddress)
+ ->setShipping($shippingAddress)
+ ->setCourier($shippingCourier)
+ ->setItems(array($item1,$item2,$item3))
+ ->setDiscounts(array($discount1,$discount2,$discount3))
+ ->setMerchantUrl($redirectUrl)
+ ->setMerchantReference('merchantOrder-123433333')
+ ->setTaxAmount($taxAmount)
+ ->setShippingAmount($shippingAmount);
+
+
+//Create Object of CreateOrder.
+$createOrderObj = new CreateOrder();
+
+//Call Process order Function.
+$createOrderObj->processOrder($transaction);
+
+?>
diff --git a/afterpay/AfterpaySDK/code/SampleCode/SampleGetOrder.php b/afterpay/AfterpaySDK/code/SampleCode/SampleGetOrder.php
new file mode 100644
index 0000000..7c4ec0e
--- /dev/null
+++ b/afterpay/AfterpaySDK/code/SampleCode/SampleGetOrder.php
@@ -0,0 +1,14 @@
+callGetOrderApi($orderToken);
+
+var_dump($getOrderResponse);
diff --git a/afterpay/AfterpaySDK/code/SampleCode/SamplePreAuth.php b/afterpay/AfterpaySDK/code/SampleCode/SamplePreAuth.php
new file mode 100644
index 0000000..bfad127
--- /dev/null
+++ b/afterpay/AfterpaySDK/code/SampleCode/SamplePreAuth.php
@@ -0,0 +1,22 @@
+checkPreAuth();
+
+var_dump($apiResponse);
+
+
+//You can store minimum, maximum values into the database
+//Later on amount validations can be added for minimum and maximum order limits
+
+?>
diff --git a/afterpay/AfterpaySDK/code/SampleCode/SampleProcessRefund.php b/afterpay/AfterpaySDK/code/SampleCode/SampleProcessRefund.php
new file mode 100644
index 0000000..872416a
--- /dev/null
+++ b/afterpay/AfterpaySDK/code/SampleCode/SampleProcessRefund.php
@@ -0,0 +1,38 @@
+setAmount($refundAmount);
+ //Call processOrderRefund function from Process Refund class to call Refund API
+ $processRefundObj = $processRefundObj->processOrderRefund($paymentId,$refundAmount);
+ // If
+ if(isset($processRefundObj->refundId))
+ {
+ echo "Refund Transaction is successfull.";
+ }
+ else
+ {
+ var_dump($processRefundObj);
+ }
+
+}
+
+?>
\ No newline at end of file
diff --git a/afterpay/AfterpaySDK/code/config.ini b/afterpay/AfterpaySDK/code/config.ini
new file mode 100644
index 0000000..d814999
--- /dev/null
+++ b/afterpay/AfterpaySDK/code/config.ini
@@ -0,0 +1,10 @@
+;Account credentials from developer portal
+[Account]
+MerchantId = 10
+MerchantSecret = f4b17f6318f90d7e63c0442875512a4eefdb0007c2f26da14cc0902f52e23b80118bc476757af7a9a3666ddccd6d87254538da6d3f6dee1d947a71e96a43046b
+CallbackUrl = 'SampleCode/SampleCapturePayment.php'
+
+;Service Configuration (Set to either sandbox or production)
+[Service]
+; can be set to sandbox / live
+mode = sandbox
\ No newline at end of file
diff --git a/afterpay/AfterpaySDK/docker-compose.yml b/afterpay/AfterpaySDK/docker-compose.yml
new file mode 100644
index 0000000..e918872
--- /dev/null
+++ b/afterpay/AfterpaySDK/docker-compose.yml
@@ -0,0 +1,13 @@
+web:
+ image: nginx:latest
+ ports:
+ - "8080:80"
+ volumes:
+ - ./code:/code
+ - ./site.conf:/etc/nginx/conf.d/site.conf
+ links:
+ - php
+php:
+ image: php:7-fpm
+ volumes:
+ - ./code:/code
\ No newline at end of file
diff --git a/afterpay/afterpay.php b/afterpay/afterpay.php
new file mode 100644
index 0000000..2f78976
--- /dev/null
+++ b/afterpay/afterpay.php
@@ -0,0 +1,795 @@
+
+* @copyright 2017 Afterpay Touch Group
+* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
+* International Registered Trademark & Property of PrestaShop SA
+*/
+
+require_once( _PS_MODULE_DIR_ . 'afterpay/classes/AfterpayConfig.php');
+require_once( _PS_MODULE_DIR_ . 'afterpay/classes/AfterpayRefund.php');
+
+// use PrestaShop\PrestaShop\Core\Payment\PaymentOption;
+
+if (!defined('_PS_VERSION_')) {
+ exit;
+}
+
+
+/**
+ * Class Afterpay
+ *
+ * Base Class for the entire Afterpay PrestaShop Module
+ * Utilise Afterpay API V1
+ */
+class Afterpay extends PaymentModule
+{
+ protected $_html = '';
+ protected $_postErrors = array();
+
+ public $afterpay_merchant_id;
+ public $afterpay_merchant_key;
+ public $afterpay_api_environment;
+ public $afterpay_enabled;
+ public $afterpay_payment_min;
+ public $afterpay_payment_max;
+
+ /**
+ * Constructor function
+ * Set up the Module details and initial configurations
+ * since 1.0.0
+ */
+ public function __construct()
+ {
+ $this->name = 'afterpay';
+ $this->tab = 'payments_gateways';
+ $this->version = '1.0.0';
+ $this->ps_versions_compliancy = array('min' => '1.6', 'max' => _PS_VERSION_);
+ $this->author = 'Afterpay Touch Group';
+ $this->controllers = array('validation', 'return', 'payment');
+ $this->is_eu_compatible = 0;
+
+ $this->currencies = true;
+ $this->currencies_mode = 'checkbox';
+
+ $this->_init_configurations();
+
+ $this->bootstrap = true;
+ parent::__construct();
+
+ $this->displayName = $this->l('Afterpay Payment Gateway');
+ $this->description = $this->l('This is a payment gateway module for Afterpay');
+
+ if (!count(Currency::checkPaymentCurrencies($this->id))) {
+ $this->warning = $this->l('No currency has been set for this module.');
+ }
+ }
+
+ /**
+ * Install function
+ * Set up the Module Hooks
+ * since 1.0.0
+ */
+ public function install() {
+
+ if (!parent::install() || !$this->registerHook('payment') || !$this->registerHook('displayPaymentEU') || !$this->registerHook('paymentReturn')
+ || !$this->registerHook('actionOrderStatusUpdate')
+ || !$this->registerHook('actionProductCancel')
+ || !$this->registerHook('actionOrderSlipAdd')
+ || !$this->registerHook('displayProductPriceBlock')
+ || !$this->registerHook('displayFooterProduct')
+ || !$this->registerHook('displayHeader')
+ || !$this->registerHook('displayAdminOrder')
+ ) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Main Hook for Payment Module
+ * Set up the Module Hooks
+ * @param array $params
+ * @return array
+ * since 1.0.0
+ */
+ public function hookPaymentOptions($params) {
+ if (!$this->afterpay_enabled) {
+ return;
+ }
+
+ if (!$this->checkCurrency($params['cart'])) {
+ return;
+ }
+
+ $total = $this->context->cart->getOrderTotal();
+ $payment_limits = $this->_getFrontEndLimits();
+
+ if( $payment_limits["afterpay_payment_min"] > $total ||
+ $payment_limits["afterpay_payment_max"] < $total) {
+
+ return;
+ }
+
+ $payment_options = [
+ // $this->getOfflinePaymentOption(),
+ $this->getExternalPaymentOption(),
+ // $this->getEmbeddedPaymentOption(),
+ // $this->getIframePaymentOption(),
+ ];
+
+ return $payment_options;
+ }
+
+ /**
+ * Main Function to output Afterpay in the checkout
+ * Set up the Module Hooks
+ * @return PaymentOption
+ * since 1.0.0
+ */
+ public function hookPayment($params) {
+ if (!$this->afterpay_enabled) {
+ return;
+ }
+
+ if (!$this->checkCurrency($params['cart'])) {
+ return;
+ }
+
+ $total = $this->context->cart->getOrderTotal();
+ $payment_limits = $this->_getFrontEndLimits();
+
+ if( $payment_limits["afterpay_payment_min"] > $total ||
+ $payment_limits["afterpay_payment_max"] < $total) {
+
+ return;
+ }
+
+ // $externalOption = new PaymentOption();
+
+ return $this->context->smarty->fetch( __DIR__ . "/views/templates/front/payment.tpl");
+ }
+
+ public function hookDisplayPaymentEU($params) {
+ if (!$this->afterpay_enabled) {
+ return;
+ }
+
+ if (!$this->checkCurrency($params['cart'])) {
+ return;
+ }
+
+ $total = $this->context->cart->getOrderTotal();
+ $payment_limits = $this->_getFrontEndLimits();
+
+ if( $payment_limits["afterpay_payment_min"] > $total ||
+ $payment_limits["afterpay_payment_max"] < $total) {
+
+ return;
+ }
+
+ $payment_options = array(
+ 'cta_text' => $this->l('Pay with Afterpay'),
+ 'logo' => Media::getMediaPath(_PS_MODULE_DIR_.$this->name.'/images/payment_checkout.png'),
+ 'action' => $this->context->link->getModuleLink($this->name, 'validation', array(), true)
+ );
+
+ return $payment_options;
+ }
+
+
+ /**
+ * Form generation function
+ *
+ * @return bool
+ * since 1.0.0
+ */
+ protected function generateForm()
+ {
+ $months = [];
+ for ($i = 1; $i <= 12; $i++) {
+ $months[] = sprintf("%02d", $i);
+ }
+
+ $years = [];
+ for ($i = 0; $i <= 10; $i++) {
+ $years[] = date('Y', strtotime('+'.$i.' years'));
+ }
+
+ $this->context->smarty->assign([
+ 'action' => $this->context->link->getModuleLink($this->name, 'validation', array(), true),
+ 'months' => $months,
+ 'years' => $years,
+ ]);
+
+ return false;
+ }
+
+
+ /*-----------------------------------------------------------------------------------------------------------------------
+ Afterpay Configurations
+ -----------------------------------------------------------------------------------------------------------------------*/
+
+ /**
+ * Initialise the configuration values
+ * since 1.0.0
+ */
+ private function _init_configurations() {
+
+ $config = Configuration::getMultiple(array('AFTERPAY_ENABLED', 'AFTERPAY_MERCHANT_ID', 'AFTERPAY_MERCHANT_KEY', 'AFTERPAY_API_ENVIRONMENT', 'AFTERPAY_USER_AGENT'));
+ if (!empty($config['AFTERPAY_ENABLED'])) {
+ $this->afterpay_enabled = $config['AFTERPAY_ENABLED'];
+ }
+ if (!empty($config['AFTERPAY_MERCHANT_ID'])) {
+ $this->afterpay_merchant_id = $config['AFTERPAY_MERCHANT_ID'];
+ }
+ if (!empty($config['AFTERPAY_MERCHANT_KEY'])) {
+ $this->afterpay_merchant_key = $config['AFTERPAY_MERCHANT_KEY'];
+ }
+ if (!empty($config['AFTERPAY_API_ENVIRONMENT'])) {
+ $this->afterpay_api_environment = $config['AFTERPAY_API_ENVIRONMENT'];
+ }
+ if (!empty($config['AFTERPAY_PAYMENT_MIN'])) {
+ $this->afterpay_payment_min = $config['AFTERPAY_PAYMENT_MIN'];
+ }
+ if (!empty($config['AFTERPAY_PAYMENT_MAX'])) {
+ $this->afterpay_payment_max = $config['AFTERPAY_PAYMENT_MAX'];
+ }
+ if (!empty($config['AFTERPAY_USER_AGENT'])) {
+ $this->afterpay_user_agent = $config['AFTERPAY_USER_AGENT'];
+ }
+ }
+
+ /**
+ * getContent() is required to show the "Configuration Page" option on Module Page
+ * @return string
+ * since 1.0.0
+ */
+ public function getContent() {
+ $output = null;
+
+ if (Tools::isSubmit('submit'.$this->name)) {
+ $output = $this->_validate_configuration();
+ }
+
+ return $output . $this->displayForm();
+ }
+
+
+ /**
+ * Validating the Configuration Form and append the output
+ * @return string
+ * since 1.0.0
+ */
+ private function _validate_configuration() {
+
+ $afterpay_merchant_id = strval(Tools::getValue('AFTERPAY_MERCHANT_ID'));
+ $afterpay_merchant_key = strval(Tools::getValue('AFTERPAY_MERCHANT_KEY'));
+ $afterpay_api_environment = strval(Tools::getValue('AFTERPAY_API_ENVIRONMENT'));
+ $afterpay_enabled = strval(Tools::getValue('AFTERPAY_ENABLED'));
+
+ $error = false;
+
+ $output = "";
+
+ //validate Afterpay Enabled
+ if (empty($afterpay_enabled) ) {
+
+ $output .= $this->displayWarning($this->l('Afterpay is Disabled'));
+ }
+
+ Configuration::updateValue('AFTERPAY_ENABLED', $afterpay_enabled);
+
+ //validate Merchant ID
+ if (!$afterpay_merchant_id
+ || empty($afterpay_merchant_id)
+ || !Validate::isGenericName($afterpay_merchant_id)) {
+
+ $output .= $this->displayError($this->l('Invalid Merchant ID value'));
+ $error = true;
+ }
+ else {
+ Configuration::updateValue('AFTERPAY_MERCHANT_ID', $afterpay_merchant_id);
+ }
+
+ //validate Merchant Key
+ if (!$afterpay_merchant_key
+ || empty($afterpay_merchant_key)
+ || !Validate::isGenericName($afterpay_merchant_key)) {
+
+ $output .= $this->displayError($this->l('Invalid Merchant Key value'));
+ $error = true;
+ }
+ else {
+ Configuration::updateValue('AFTERPAY_MERCHANT_KEY', $afterpay_merchant_key);
+ }
+
+ //validate API Environment
+ if (empty($afterpay_api_environment)) {
+
+ $output .= $this->displayError($this->l('Invalid Api Environment value'));
+ $error = true;
+ }
+ else {
+ Configuration::updateValue('AFTERPAY_API_ENVIRONMENT', $afterpay_api_environment);
+ }
+
+ if( !empty($afterpay_merchant_id) && !empty($afterpay_merchant_key) && !empty($afterpay_api_environment) ) {
+
+ $user_agent = "AfterpayPrestaShop1.6Module " . $this->version . " - Merchant ID: " . $afterpay_merchant_id . " - PrestaShop " . _PS_VERSION_ . " - URL: " . Tools::getHttpHost(true) . __PS_BASE_URI__;
+
+ Configuration::updateValue('AFTERPAY_USER_AGENT', $user_agent);
+
+ $afterpay_admin = new AfterpayConfig(
+ $afterpay_merchant_id,
+ $afterpay_merchant_key,
+ $afterpay_api_environment,
+ $afterpay_enabled,
+ $user_agent
+ );
+ $payment_limits_check = $afterpay_admin->_update_payment_limits();
+ }
+
+ if( $payment_limits_check["error"] ) {
+ $output .= $this->displayError($this->l( $payment_limits_check["message"] ));
+ }
+ else if( !$error ) {
+ $output .= $this->displayConfirmation($this->l('Settings updated'));
+ }
+
+ return $output;
+ }
+
+ /**
+ * DisplayFrom() is required to show the "Configuration Form Page"
+ * @return string
+ * since 1.0.0
+ */
+ public function displayForm() {
+
+ // Get default language
+ $afterpay_merchant_id = (int)Configuration::get('AFTERPAY_MERCHANT_ID');
+ $afterpay_merchant_key = Configuration::get('AFTERPAY_MERCHANT_KEY');
+ $afterpay_api_environment = (int)Configuration::get('AFTERPAY_API_ENVIRONMENT');
+ $afterpay_enabled = (int)Configuration::get('AFTERPAY_ENABLED');
+ $afterpay_payment_min = (int)Configuration::get('AFTERPAY_PAYMENT_MIN');
+ $afterpay_payment_max = (int)Configuration::get('AFTERPAY_PAYMENT_MAX');
+
+ // Init Fields form array
+ $fields_form[0]['form'] = array(
+ 'legend' => array(
+ 'title' => $this->l('Settings'),
+ ),
+ 'input' => array(
+ array(
+ 'type' => 'select',
+ 'label' => $this->l('Enabled'),
+ 'name' => 'AFTERPAY_ENABLED',
+ 'options' => array(
+ 'query' => array(
+ array(
+ 'enabled' => false,
+ 'enabled_name' => 'No'
+ ),
+ array(
+ 'enabled' => true,
+ 'enabled_name' => 'Yes'
+ )
+ ),
+ 'id' => 'enabled',
+ 'name' => 'enabled_name'
+ ),
+ 'required' => true
+ ),
+ array(
+ 'type' => 'text',
+ 'label' => $this->l('Merchant ID'),
+ 'name' => 'AFTERPAY_MERCHANT_ID',
+ 'size' => 5,
+ 'required' => true
+ ),
+ array(
+ 'type' => 'text',
+ 'label' => $this->l('Merchant Key'),
+ 'name' => 'AFTERPAY_MERCHANT_KEY',
+ 'size' => 128,
+ 'required' => true
+ ),
+ array(
+ 'type' => 'select',
+ 'label' => $this->l('API Environment'),
+ 'name' => 'AFTERPAY_API_ENVIRONMENT',
+ 'options' => array(
+ 'query' => array(
+ array(
+ 'api_mode' => 'sandbox',
+ 'api_name' => 'Sandbox'
+ ),
+ array(
+ 'api_mode' => 'production',
+ 'api_name' => 'Production'
+ )
+ ),
+ 'id' => 'api_mode',
+ 'name' => 'api_name'
+ ),
+ 'required' => true
+ ),
+ array(
+ 'type' => 'text',
+ 'label' => $this->l('Min Payment Limit'),
+ 'name' => 'AFTERPAY_PAYMENT_MIN',
+ 'size' => 128,
+ 'readonly' => 'readonly'
+ ),
+ array(
+ 'type' => 'text',
+ 'label' => $this->l('Max Payment Limit'),
+ 'name' => 'AFTERPAY_PAYMENT_MAX',
+ 'size' => 128,
+ 'readonly' => 'readonly'
+ )
+ ),
+ 'submit' => array(
+ 'title' => $this->l('Save'),
+ 'class' => 'btn btn-default pull-right'
+ )
+ );
+
+ $helper = new HelperForm();
+
+ // Module, token and currentIndex
+ $helper->module = $this;
+ $helper->name_controller = $this->name;
+ $helper->token = Tools::getAdminTokenLite('AdminModules');
+ $helper->currentIndex = AdminController::$currentIndex.'&configure='.$this->name;
+
+
+ // Title and toolbar
+ $helper->title = $this->displayName;
+ $helper->show_toolbar = true; // false -> remove toolbar
+ $helper->toolbar_scroll = true; // yes - > Toolbar is always visible on the top of the screen.
+ $helper->submit_action = 'submit'.$this->name;
+ $helper->toolbar_btn = array(
+ 'save' =>
+ array(
+ 'desc' => $this->l('Save'),
+ 'href' => AdminController::$currentIndex.'&configure='.$this->name.'&save'.$this->name.
+ '&token='.Tools::getAdminTokenLite('AdminModules'),
+ ),
+ 'back' => array(
+ 'href' => AdminController::$currentIndex.'&token='.Tools::getAdminTokenLite('AdminModules'),
+ 'desc' => $this->l('Back to list')
+ )
+ );
+
+ // Load current value
+ $helper->fields_value['AFTERPAY_ENABLED'] = Configuration::get('AFTERPAY_ENABLED');
+ $helper->fields_value['AFTERPAY_MERCHANT_ID'] = Configuration::get('AFTERPAY_MERCHANT_ID');
+ $helper->fields_value['AFTERPAY_MERCHANT_KEY'] = Configuration::get('AFTERPAY_MERCHANT_KEY');
+ $helper->fields_value['AFTERPAY_API_ENVIRONMENT'] = Configuration::get('AFTERPAY_API_ENVIRONMENT');
+ $helper->fields_value['AFTERPAY_PAYMENT_MIN'] = Configuration::get('AFTERPAY_PAYMENT_MIN');
+ $helper->fields_value['AFTERPAY_PAYMENT_MAX'] = Configuration::get('AFTERPAY_PAYMENT_MAX');
+
+ return $helper->generateForm($fields_form);
+ }
+ /*-----------------------------------------------------------------------------------------------------------------------
+ End of Afterpay Configurations
+ -----------------------------------------------------------------------------------------------------------------------*/
+
+
+
+
+ /*-----------------------------------------------------------------------------------------------------------------------
+ Start of Refund Codes
+ -----------------------------------------------------------------------------------------------------------------------*/
+
+ /**
+ * Hook Action for Order Status Update (handles Refunds)
+ * @param array $params
+ * @return bool
+ * since 1.0.0
+ */
+ public function hookActionOrderStatusUpdate($params) {
+
+ if( !empty($params) && !empty($params['id_order']) ) {
+ $order = new Order((int)$params['id_order']);
+ }
+
+ if( !empty($params) && !empty($params['newOrderStatus']) ) {
+ $new_order_status = $params['newOrderStatus'];
+ }
+
+ if( $new_order_status->id == _PS_OS_REFUND_ ) {
+
+ $afterpay_refund = $this->_constructRefundObject($order);
+
+ //get the cart total since this would be Full Refund
+ $cart = new Cart($order->id_cart);
+ $order_total = round($cart->getOrderTotal(), 2);
+
+ $payments = $order->getOrderPayments();
+ $afterpay_transaction_id = $payments[0]->transaction_id;
+
+ $currency = new CurrencyCore($order->id_currency);
+ $currency_code = $currency->iso_code;
+
+ $results = $afterpay_refund->doRefund($afterpay_transaction_id, $order_total, $currency_code);
+ $this->_verifyRefund( $results );
+
+ }
+ return false;
+ }
+
+ /**
+ * Hook Action for Partial Refunds
+ * @param array $params
+ * since 1.0.0
+ */
+ public function hookActionOrderSlipAdd($params) {
+
+ if( !empty($params) && !empty($params["order"]->id) ) {
+ $order = new Order((int)$params["order"]->id);
+
+ $payments = $order->getOrderPayments();
+ $afterpay_transaction_id = $payments[0]->transaction_id;
+
+ $currency = new CurrencyCore($order->id_currency);
+ $currency_code = $currency->iso_code;
+ }
+
+
+ $afterpay_refund = $this->_constructRefundObject($order);
+
+ $refund_products_list = $params["productList"];
+ $refund_total_amount = 0;
+
+ foreach( $refund_products_list as $key => $item ) {
+ $refund_total_amount += $item["amount"];
+ }
+
+ $refund_total_amount = round($refund_total_amount, 2);
+
+ $results = $afterpay_refund->doRefund($afterpay_transaction_id, round($refund_total_amount, 2), $currency_code);
+
+ if( !empty($results->errorCode) ) {
+
+ $message = "Afterpay Partial Refund Error: " . $results->errorCode . " (" . $results->errorId . ") " . $results->message;
+ PrestaShopLogger::addLog($message, 2, NULL, "Afterpay", 1);
+ }
+ }
+
+ /**
+ * Construct the Refunds Object based on the configuration and Refunds type
+ * @param int $order
+ * @return AfterpayRefund
+ * since 1.0.0
+ */
+ private function _constructRefundObject($order) {
+ $config = Configuration::getMultiple(array('AFTERPAY_MERCHANT_ID', 'AFTERPAY_MERCHANT_KEY', 'AFTERPAY_API_ENVIRONMENT'));
+
+ $afterpay_merchant_id = (int)Configuration::get('AFTERPAY_MERCHANT_ID');
+ $afterpay_merchant_key = Configuration::get('AFTERPAY_MERCHANT_KEY');
+ $afterpay_api_environment = Configuration::get('AFTERPAY_API_ENVIRONMENT');
+ $afterpay_user_agent = Configuration::get('AFTERPAY_USER_AGENT');
+
+ $afterpay_refund = new AfterpayRefund(
+ $afterpay_merchant_id,
+ $afterpay_merchant_key,
+ $afterpay_api_environment,
+ $afterpay_user_agent
+ );
+
+ return $afterpay_refund;
+ }
+
+ /**
+ * Verify the Refunds results
+ * @param string $results
+ * since 1.0.0
+ */
+ private function _verifyRefund( $results ) {
+ $refund_error = false;
+ if( empty($results) ) {
+ $refund_error = true;
+ $error_message = "Missing refund response.";
+ }
+ if( !empty($results->errorCode) ) {
+ $refund_error = true;
+ $error_message = $results->message;
+ }
+
+ if( $refund_error ) {
+ /*the order update doesn't work, hence the die()*/
+ // $new_history = new OrderHistory();
+ // $new_history->id_order = (int)$order->id;
+ // $new_history->changeIdOrderState(1, $order, true);
+
+ $return_url = $_SERVER['HTTP_REFERER'];
+
+ echo $results->message . " " . $results->errorId;
+ echo " Return to Order Details";
+
+ $message = "Afterpay Full Refund Error: " . $results->errorCode . " (" . $results->errorId . ") " . $results->message;
+ PrestaShopLogger::addLog($message, 2, NULL, "Afterpay", 1);
+
+ die();
+ }
+ }
+
+ /*-----------------------------------------------------------------------------------------------------------------------
+ End of Refund Codes
+ -----------------------------------------------------------------------------------------------------------------------*/
+
+
+ /*-----------------------------------------------------------------------------------------------------------------------
+ Afterpay Product Display
+ -----------------------------------------------------------------------------------------------------------------------*/
+
+ /**
+ * Function to display the Afterpay Product Price Payment Breakdown
+ * @param array $params
+ * @return TPL
+ * since 1.0.0
+ */
+ public function hookDisplayProductPriceBlock($params) {
+
+ $current_controller = Tools::getValue('controller');
+ $payment_limits = $this->_getFrontEndLimits();
+
+ //note the different params between PrestaShop 1.7 and 1.6 (price and price_amount)
+ if( $current_controller == "product" &&
+ $params["type"] == "after_price" &&
+ $payment_limits["afterpay_payment_min"] <= $params["product"]->price &&
+ $payment_limits["afterpay_payment_max"] >= $params["product"]->price &&
+ $payment_limits["afterpay_enabled"] ) {
+
+ $tax_rate = $params["product"]->tax_rate;
+ $base_price = $params["product"]->base_price;
+ $product_price = round($base_price + ( $base_price * $tax_rate / 100), 2, PHP_ROUND_HALF_UP);
+
+ // foreach( $params["product"] as $key => $item ) {
+ // echo( "
" . $key . "
");
+ // var_dump($item);
+ // }
+
+ $this->context->smarty->assign( "afterpay_instalment_breakdown", $this->_getCurrentInstalmentsDisplay( $product_price ) );
+
+ return $this->context->smarty->fetch( __DIR__ . "/views/templates/front/product_page.tpl");
+ }
+ }
+
+ /**
+ * Function to display the Afterpay Product Price Modal Window
+ * @param array $params
+ * @return TPL
+ * since 1.0.0
+ */
+ public function hookDisplayFooterProduct($params) {
+
+ $current_controller = Tools::getValue('controller');
+ $payment_limits = $this->_getFrontEndLimits();
+
+ if( $current_controller == "product" &&
+ $payment_limits["afterpay_payment_min"] <= $params["product"]->price &&
+ $payment_limits["afterpay_payment_max"] >= $params["product"]->price &&
+ $payment_limits["afterpay_enabled"] ) {
+
+ return $this->context->smarty->fetch( __DIR__ . "/views/templates/front/product_modal.tpl");
+ }
+ }
+
+
+ /**
+ * Function to append Afterpay JS, CSS and Variables to Site Header
+ * @param array $params
+ * since 1.0.0
+ */
+ public function hookDisplayHeader($params) {
+ $this->context->controller->addCSS($this->_path."css/afterpay.css", "all");
+ $this->context->controller->addJS($this->_path."js/afterpay.js");
+
+ $this->context->smarty->assign( "afterpay_base_url", Context::getContext()->shop->getBaseURL(true) );
+ }
+
+ /*-----------------------------------------------------------------------------------------------------------------------
+ End of Afterpay Product Display
+ -----------------------------------------------------------------------------------------------------------------------*/
+
+ /*-----------------------------------------------------------------------------------------------------------------------
+ Miscellaneous
+ -----------------------------------------------------------------------------------------------------------------------*/
+
+ /**
+ * Function to get the Afterpay Front-End criteria
+ * @return array
+ * since 1.0.0
+ */
+ private function _getFrontEndLimits() {
+
+ $return["afterpay_enabled"] = (int)Configuration::get('AFTERPAY_ENABLED');
+ $return["afterpay_payment_min"] = (int)Configuration::get('AFTERPAY_PAYMENT_MIN');
+ $return["afterpay_payment_max"] = (int)Configuration::get('AFTERPAY_PAYMENT_MAX');
+
+ return $return;
+ }
+
+ /**
+ * Function to check the Supported Currency
+ * @param Cart $cart
+ * @return bool
+ * since 1.0.0
+ */
+ public function checkCurrency($cart)
+ {
+ $currency_order = new Currency($cart->id_currency);
+ $currencies_module = $this->getCurrency($cart->id_currency);
+
+ if (is_array($currencies_module)) {
+ foreach ($currencies_module as $currency_module) {
+ if ($currency_order->id == $currency_module['id_currency']) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public function hookDisplayAdminOrder($params) {
+ $order_id = $params["id_order"];
+ $order = new Order( $order_id );
+
+ if( $order->payment == $this->name ) {
+ $this->context->controller->addCSS($this->_path."css/afterpay-admin.css", "all");
+ }
+ }
+
+ /**
+ * Display function for Total Payment
+ *
+ * @return string
+ * since 1.0.0
+ */
+ private function _getCurrentCartTotalDisplay() {
+ $cart = $this->context->cart;
+ $order_total = round($cart->getOrderTotal(), 2);
+
+ return $this->context->currency->iso_code . " " . $this->context->currency->sign . $order_total;
+ }
+
+ /**
+ * Display function for Payment Breakdowns
+ *
+ * @return string
+ * since 1.0.0
+ */
+ private function _getCurrentInstalmentsDisplay( $amount = NULL ) {
+
+ if( empty($amount) ) {
+ $cart = $this->context->cart;
+ $amount = $cart->getOrderTotal();
+ }
+ $instalment = round($amount / 4, 2, PHP_ROUND_HALF_UP);
+
+ return $this->context->currency->iso_code . " " . $this->context->currency->sign .
+ "" . $instalment . "";
+ }
+}
\ No newline at end of file
diff --git a/afterpay/classes/AfterpayCapture.php b/afterpay/classes/AfterpayCapture.php
new file mode 100644
index 0000000..1ffca7d
--- /dev/null
+++ b/afterpay/classes/AfterpayCapture.php
@@ -0,0 +1,165 @@
+
+* @copyright 2017 Afterpay Touch Group
+* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
+* International Registered Trademark & Property of PrestaShop SA
+*/
+
+
+require_once( _PS_MODULE_DIR_ . 'afterpay/AfterpaySDK/code/Afterpay/Api/CapturePayment.php' );
+require_once( _PS_MODULE_DIR_ . 'afterpay/AfterpaySDK/code/Afterpay/Core/Call.php');
+
+// use PrestaShop\PrestaShop\Core\Payment\PaymentOption;
+
+use Afterpay\Api\CapturePayment as AfterpayCapturePayment;
+use Afterpay\Core\Call as AfterpayCall;
+
+
+if (!defined('_PS_VERSION_')) {
+ exit;
+}
+
+
+/**
+ * Class AfterpayCapture
+ *
+ * Afterpay PrestaShop Module API Capture class
+ * Utilise Afterpay API V1
+ */
+class AfterpayCapture
+{
+ private $afterpay_capture_payment;
+ private $afterpay_call;
+ private $params;
+ private $merchant_reference;
+
+ /**
+ * Constructor Function
+ *
+ * @param string $merchant_id
+ * @param string $merchant_secret
+ * @param string $mode
+ * @param array $params
+ * @param string $merchant_reference
+ * @return bool
+ * since 1.0.0
+ */
+ public function __construct($merchant_id, $merchant_secret, $mode, $params, $merchant_reference = NULL, $user_agent) {
+ $config = array(
+ 'merchantId' => $merchant_id,
+ 'merchantSecret' => $merchant_secret,
+ 'mode' => $mode,
+ 'sdkName' => $user_agent
+ );
+
+ $this->afterpay_capture_payment = new AfterpayCapturePayment($config);
+ $this->afterpay_call = new AfterpayCall($config);
+
+ $this->params = $params;
+ $this->merchant_reference = $merchant_reference;
+ }
+
+ /**
+ * Transaction Integrity Checking function
+ * Perform the API Call to check whether a transaction has been tampered with or not
+ * @return array
+ * since 1.0.0
+ */
+ public function doTransactionIntegrityChecking() {
+
+ $results = $this->afterpay_call->callGetOrderApi( $this->params["orderToken"] );
+
+ if( empty($results) ) {
+ $return['message'] = "No response received for the following token: " . $this->params["orderToken"] ;
+ $return['info'] = "";
+ $return['error'] = true;
+ }
+ else if( !empty( $results->errorCode ) ) {
+ $return['message'] = $results->message;
+ $return['info'] = "Code: " . $results->errorCode . " (" . $results->errorId . ") ";
+ $return['error'] = true;
+ }
+ else {
+ //create the order on PrestaShop Admin
+ $return['error'] = false;
+ $return['results'] = $results;
+ }
+
+ return $return;
+ }
+
+ /**
+ * Afterpay Capture function
+ * Perform the API Call to capture a transaction
+ * @return array
+ * since 1.0.0
+ */
+ public function createCapturePayment() {
+ $results = $this->afterpay_capture_payment->processCapturePayment($this->params);
+
+ if( !empty( $results->status ) && $results->status == "APPROVED" && !empty($results->id) ) {
+ //create the order on PrestaShop Admin
+ $this->_createOrder($results->id);
+ $return['error'] = false;
+ }
+ else if( !empty( $results->errorCode ) ) {
+ $return['message'] = $results->message;
+ $return['info'] = "Code: " . $results->errorCode . " (" . $results->errorId . ") ";
+ $return['error'] = true;
+ }
+ else {
+ $return['message'] = "No response received for the following token: " . $this->params["orderToken"] ;
+ $return['info'] = "";
+ $return['error'] = true;
+ }
+
+ return $return;
+ }
+
+ /**
+ * Create Order function
+ * Create the PrestaShop Order after a successful Capture
+ * @param string $afterpay_order_id
+ * since 1.0.0
+ */
+ private function _createOrder($afterpay_order_id) {
+
+ $cart = Context::getContext()->cart;
+
+ $order_status = (int)Configuration::get("PS_OS_PAYMENT");
+
+ $order_total = $cart->getOrderTotal(true, Cart::BOTH);
+
+
+ $module = Module::getInstanceByName("afterpay");
+
+ $extra_vars = array(
+ "transaction_id" => $afterpay_order_id
+ );
+
+ $module->validateOrder($cart->id, $order_status, $order_total, "afterpay", null, $extra_vars, null, false, $cart->secure_key);
+
+ $message = "Afterpay Order Captured Successfully - Order ID: " . $afterpay_order_id . "; PrestaShop Cart ID: " . $cart->id;
+ PrestaShopLogger::addLog($message, 1, NULL, "Afterpay", 1);
+
+ }
+}
\ No newline at end of file
diff --git a/afterpay/classes/AfterpayCheckout.php b/afterpay/classes/AfterpayCheckout.php
new file mode 100644
index 0000000..50f21a0
--- /dev/null
+++ b/afterpay/classes/AfterpayCheckout.php
@@ -0,0 +1,315 @@
+
+* @copyright 2017 Afterpay Touch Group
+* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
+* International Registered Trademark & Property of PrestaShop SA
+*/
+
+
+require_once( _PS_MODULE_DIR_ . 'afterpay/AfterpaySDK/code/Afterpay/Api/CreateOrder.php' );
+
+require_once( _PS_MODULE_DIR_ . 'afterpay/AfterpaySDK/code/Afterpay/Api/Amount.php' );
+require_once( _PS_MODULE_DIR_ . 'afterpay/AfterpaySDK/code/Afterpay/Api/Transaction.php' );
+require_once( _PS_MODULE_DIR_ . 'afterpay/AfterpaySDK/code/Afterpay/Api/RedirectUrls.php' );
+require_once( _PS_MODULE_DIR_ . 'afterpay/AfterpaySDK/code/Afterpay/Api/Consumer.php' );
+
+require_once( _PS_MODULE_DIR_ . 'afterpay/AfterpaySDK/code/Afterpay/Api/Address.php' );
+require_once( _PS_MODULE_DIR_ . 'afterpay/AfterpaySDK/code/Afterpay/Api/BillingAddress.php' );
+require_once( _PS_MODULE_DIR_ . 'afterpay/AfterpaySDK/code/Afterpay/Api/ShippingAddress.php' );
+require_once( _PS_MODULE_DIR_ . 'afterpay/AfterpaySDK/code/Afterpay/Api/Item.php' );
+
+require_once( _PS_MODULE_DIR_ . 'afterpay/AfterpaySDK/code/Afterpay/Api/Discount.php' );
+
+use PrestaShop\PrestaShop\Core\Payment\PaymentOption;
+
+use Afterpay\Api\CreateOrder as AfterpayCreateOrder;
+use Afterpay\Api\Amount as AfterpayAmount;
+use Afterpay\Api\Transaction as AfterpayTransaction;
+use Afterpay\Api\RedirectUrls as AfterpayRedirectUrls;
+use Afterpay\Api\Consumer as AfterpayCustomer;
+
+use Afterpay\Api\Address as AfterpayAddress;
+use Afterpay\Api\BillingAddress as AfterpayBillingAddress;
+use Afterpay\Api\ShippingAddress as AfterpayShippingAddress;
+use Afterpay\Api\Item as AfterpayItem;
+use Afterpay\Api\Discount as AfterpayDiscount;
+
+if (!defined('_PS_VERSION_')) {
+ exit;
+}
+
+/**
+ * Class AfterpayCheckout
+ *
+ * Afterpay PrestaShop Module API Order Token Generation Class
+ * Utilise Afterpay API V1
+ */
+class AfterpayCheckout
+{
+ private $afterpay_create_order;
+ private $enabled;
+ private $cart_object;
+ private $currency_code;
+ private $transaction;
+
+ /**
+ * Constructor Function
+ *
+ * @param string $merchant_id
+ * @param string $merchant_secret
+ * @param string $mode
+ * @param Cart $cart_object
+ * @param string $currency_code
+ * since 1.0.0
+ */
+ public function __construct($merchant_id, $merchant_secret, $mode, $cart_object, $currency_code = 'AUD') {
+
+ $user_agent = Configuration::get('AFTERPAY_USER_AGENT');
+
+ $config = array(
+ 'merchantId' => $merchant_id,
+ 'merchantSecret' => $merchant_secret,
+ 'mode' => $mode,
+ 'sdkName' => $user_agent
+ );
+ $this->afterpay_create_order = new AfterpayCreateOrder($config);
+
+ $this->cart_object = $cart_object;
+ $this->currency_code = $currency_code;
+
+ $this->transaction = new AfterpayTransaction();
+ }
+
+ /**
+ * Create Order Token function
+ *
+ * since 1.0.0
+ */
+ public function createOrderToken() {
+
+ $this->_constructPayload();
+
+ $result = $this->afterpay_create_order->processOrder($this->transaction);
+ }
+
+ /**
+ * Construct API Order Token Payload function
+ *
+ * since 1.0.0
+ */
+ private function _constructPayload() {
+
+ $this->transaction->setTotalAmount( $this->_processTotal( $this->currency_code ) );
+
+ $this->transaction->setMerchantUrl( $this->_processRedirect() );
+
+ $this->transaction->setConsumer( $this->_processCustomer() );
+
+ // $this->transaction->setMerchantReference( $this->cart_object->id );
+
+ $this->transaction->setBilling( $this->_processBillingAddress() );
+
+ $this->transaction->setShipping( $this->_processShippingAddress() );
+
+ $this->transaction->setItems( $this->_processItems() );
+
+ //check for discounts
+ $total_discounts = $this->cart_object->getOrderTotal(true, Cart::ONLY_DISCOUNTS);
+ if( !empty($total_discounts) ) {
+ $this->transaction->setDiscounts( $this->_processDiscount( $total_discounts ) );
+ }
+ }
+
+
+ /**
+ * Extracting API Order Token Payload function for logging purposes
+ *
+ * since 1.0.0
+ */
+ public function _extractPayload() {
+ $return = array();
+
+ $return["billing"] = $this->transaction->getBilling();
+ $return["item"] = $this->transaction->getItems();
+ $return["total"] = $this->transaction->getTotalAmount();
+ $return["consumer"] = $this->transaction->getConsumer();
+ $return["discount"] = $this->transaction->getDiscounts();
+
+ return $return;
+ }
+
+ /*----------------------------------------------------------------------------------------------------
+ Item Processing Classes
+ ----------------------------------------------------------------------------------------------------*/
+ /**
+ * Process the Order Items
+ *
+ * @return array
+ * since 1.0.0
+ */
+ private function _processItems() {
+
+ $products = $this->cart_object->getProducts(true);
+ $items = array();
+
+ foreach( $products as $key => $item ) {
+
+
+ $product_price = round($item["price_wt"], 2);
+
+ $item_amount = new AfterpayAmount( round( $product_price, 2), $this->currency_code );
+
+ $product_item = new AfterpayItem( $item["name"], $item["reference"], $item["quantity"], $item_amount);
+ $items[] = $product_item;
+ }
+
+ return $items;
+ }
+
+ /**
+ * Process the Order Shipping Address
+ *
+ * @return array
+ * since 1.0.0
+ */
+ private function _processShippingAddress() {
+ $shipping_address = new Address($this->cart_object->id_address_delivery);
+
+ $country_object = new Country( $shipping_address->id_country );
+ $state_object = new State( $shipping_address->id_state );
+
+ $address['name'] = $shipping_address->firstname . " " . $shipping_address->lastname;
+ $address['line1'] = $shipping_address->address1;
+ $address['line2'] = $shipping_address->address2;
+ $address['postcode'] = $shipping_address->postcode;
+ $address['suburb'] = $shipping_address->city;
+ $address['phoneNumber'] = $shipping_address->phone;
+
+ $address['countryCode'] = $country_object->iso_code;
+
+ if( !empty($shipping_address->id_state) && !empty($state_object) ) {
+ $address['state'] = $state_object->iso_code;
+ }
+ else {
+ $address['state'] = $shipping_address->city;
+ }
+
+ return $address;
+ }
+
+ /**
+ * Process the Order Billing Address
+ *
+ * @return array
+ * since 1.0.0
+ */
+ private function _processBillingAddress() {
+ $billing_address = new Address($this->cart_object->id_address_invoice);
+
+ $country_object = new Country( $billing_address->id_country );
+ $state_object = new State( $billing_address->id_state );
+
+
+ $address['name'] = $billing_address->firstname . " " . $billing_address->lastname;
+ $address['line1'] = $billing_address->address1;
+ $address['line2'] = $billing_address->address2;
+ $address['postcode'] = $billing_address->postcode;
+ $address['suburb'] = $billing_address->city;
+ $address['phoneNumber'] = $billing_address->phone;
+
+ $address['countryCode'] = $country_object->iso_code;
+
+ if( !empty($billing_address->id_state) && !empty($state_object) ) {
+ $address['state'] = $state_object->iso_code;
+ }
+ else {
+ $address['state'] = $billing_address->city;
+ }
+
+ return $address;
+ }
+
+ /**
+ * Process the Order Total Amount
+ *
+ * @return AfterpayAmount
+ * since 1.0.0
+ */
+ private function _processTotal() {
+ $total_amount = new AfterpayAmount( round( $this->cart_object->getOrderTotal(), 2), $this->currency_code );
+ return $total_amount;
+ }
+
+ /**
+ * Process the Order Redirection Targets
+ *
+ * @return AfterpayRedirectUrls
+ * since 1.0.0
+ */
+ private function _processRedirect() {
+
+ $site_url = Tools::getHttpHost(true).__PS_BASE_URI__;
+ $success_url = $site_url . "module/afterpay/return";
+ $cancel_url = $site_url . "order?step=1&?=";
+
+ $redirect_url = new AfterpayRedirectUrls($success_url, $cancel_url);
+ return $redirect_url;
+ }
+
+ /**
+ * Process the Order Customer Details
+ *
+ * @return AfterpayCustomer
+ * since 1.0.0
+ */
+ private function _processCustomer() {
+ //get Customer Data
+ $customer_id = $this->cart_object->id_customer;
+ $customer = new Customer( (int) $customer_id );
+
+ //get the Billing Phone
+ $billing_address = new Address($this->cart_object->id_address_invoice);
+
+ $consumer_data["phoneNumber"] = $billing_address->phone;
+ $consumer_data["givenName"] = $customer->firstname;
+ $consumer_data["surName"] = $customer->lastname;
+ $consumer_data["email"] = $customer->email;
+
+ $afterpay_customer = new AfterpayCustomer($consumer_data);
+
+ return $afterpay_customer;
+ }
+
+ /**
+ * Process the Order Discount Details
+ *
+ * @return AfterpayDiscount
+ * since 1.0.0
+ */
+ private function _processDiscount( $total_discounts ) {
+ //get Customer Data
+ $discount_amount = new AfterpayAmount( $total_discounts, $this->currency_code );
+ $discount = new AfterpayDiscount('Discount Coupon', $discount_amount);
+
+ return array( $discount );
+ }
+}
\ No newline at end of file
diff --git a/afterpay/classes/AfterpayConfig.php b/afterpay/classes/AfterpayConfig.php
new file mode 100644
index 0000000..cf8a706
--- /dev/null
+++ b/afterpay/classes/AfterpayConfig.php
@@ -0,0 +1,109 @@
+
+* @copyright 2017 Afterpay Touch Group
+* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
+* International Registered Trademark & Property of PrestaShop SA
+*/
+
+
+require_once( _PS_MODULE_DIR_ . 'afterpay/AfterpaySDK/code/Afterpay/Core/Call.php');
+
+// use PrestaShop\PrestaShop\Core\Payment\PaymentOption;
+use Afterpay\Core\Call as AfterpayCall;
+
+if (!defined('_PS_VERSION_')) {
+ exit;
+}
+
+class AfterpayConfig
+{
+ private $afterpay_call;
+ private $enabled;
+ private $merchant_id;
+ private $merchant_secret;
+ private $mode;
+
+ public function __construct($merchant_id, $merchant_secret, $mode, $enabled = false, $user_agent) {
+ $config = array(
+ 'merchantId' => $merchant_id,
+ 'merchantSecret' => $merchant_secret,
+ 'mode' => $mode,
+ 'sdkName' => $user_agent
+ );
+
+ $this->merchant_id = $merchant_id;
+ $this->merchant_secret = $merchant_secret;
+ $this->mode = $mode;
+
+ $this->afterpay_call = new AfterpayCall($config);
+
+ $this->enabled = $enabled;
+ }
+
+ public function _update_payment_limits(){
+
+ $return = array( "error" => false );
+
+ if($this->enabled) {
+
+ $results = $this->afterpay_call->callAuthorizationApi();
+
+ if( empty($results) || !empty($results->errorCode) ) {
+ $return["error"] = true;
+ $return["message"] = $results->message;
+
+ $masked_merchant_secret = substr($this->merchant_secret, 0, 4) . '****' . substr($this->merchant_secret, -4);
+
+ //log the error
+ $log_message = "Afterpay Credentials Error: " . $results->errorCode .
+ " (" . $results->errorId . ") " .
+ " " . $results->message .
+ " ID: " . $this->merchant_id .
+ " Key: " . $masked_merchant_secret;
+
+ PrestaShopLogger::addLog($log_message, 2, NULL, "Afterpay", 1);
+
+ //nullify the payment limits values
+ Configuration::updateValue('AFTERPAY_PAYMENT_MAX', 0);
+ Configuration::updateValue('AFTERPAY_PAYMENT_MIN', 0);
+
+ return $return;
+ }
+
+ if( !empty($results[0]->maximumAmount->amount) ) {
+ Configuration::updateValue('AFTERPAY_PAYMENT_MAX', $results[0]->maximumAmount->amount);
+ }
+ else {
+ Configuration::updateValue('AFTERPAY_PAYMENT_MAX', 0);
+ }
+
+ if( !empty($results[0]->minimumAmount->amount) ) {
+ Configuration::updateValue('AFTERPAY_PAYMENT_MIN', $results[0]->minimumAmount->amount);
+ }
+ else {
+ Configuration::updateValue('AFTERPAY_PAYMENT_MIN', 0);
+ }
+ }
+
+ return $return;
+ }
+}
\ No newline at end of file
diff --git a/afterpay/classes/AfterpayRefund.php b/afterpay/classes/AfterpayRefund.php
new file mode 100644
index 0000000..4f8a4d0
--- /dev/null
+++ b/afterpay/classes/AfterpayRefund.php
@@ -0,0 +1,67 @@
+
+* @copyright 2017 Afterpay Touch Group
+* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
+* International Registered Trademark & Property of PrestaShop SA
+*/
+
+
+require_once( _PS_MODULE_DIR_ . 'afterpay/AfterpaySDK/code/Afterpay/Api/ProcessRefund.php' );
+require_once( _PS_MODULE_DIR_ . 'afterpay/AfterpaySDK/code/Afterpay/Api/Amount.php' );
+
+use PrestaShop\PrestaShop\Core\Payment\PaymentOption;
+
+use Afterpay\Api\ProcessRefund as AfterpayProcessRefund;
+use Afterpay\Api\Amount as AfterpayAmount;
+
+
+if (!defined('_PS_VERSION_')) {
+ exit;
+}
+
+class AfterpayRefund
+{
+ private $afterpay_process_refund;
+
+ public function __construct($merchant_id, $merchant_secret, $mode, $user_agent = '', $currency_code = 'AUD') {
+
+ $config = array(
+ 'merchantId' => $merchant_id,
+ 'merchantSecret' => $merchant_secret,
+ 'mode' => $mode,
+ 'sdkName' => $user_agent
+ );
+
+ $this->afterpay_process_refund = new AfterpayProcessRefund($config);
+ }
+
+ /*----------------------------------------------------------------------------------------------------
+
+ ----------------------------------------------------------------------------------------------------*/
+
+ public function doRefund( $afterpay_transaction_id, $amount, $currency_code ) {
+ $amount = new AfterpayAmount( $amount, $currency_code );
+ $results = $this->afterpay_process_refund->processOrderRefund( $afterpay_transaction_id, $amount );
+
+ return $results;
+ }
+}
\ No newline at end of file
diff --git a/afterpay/config.xml b/afterpay/config.xml
new file mode 100644
index 0000000..555bb4d
--- /dev/null
+++ b/afterpay/config.xml
@@ -0,0 +1,12 @@
+
+
+ afterpay
+
+
+
+
+
+ 1
+ 1
+
+
\ No newline at end of file
diff --git a/afterpay/controllers/front/index.php b/afterpay/controllers/front/index.php
new file mode 100644
index 0000000..0f370e2
--- /dev/null
+++ b/afterpay/controllers/front/index.php
@@ -0,0 +1,35 @@
+
+* @copyright 2007-2015 PrestaShop SA
+* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
+* International Registered Trademark & Property of PrestaShop SA
+*/
+
+header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
+header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
+
+header('Cache-Control: no-store, no-cache, must-revalidate');
+header('Cache-Control: post-check=0, pre-check=0', false);
+header('Pragma: no-cache');
+
+header('Location: ../../../../');
+exit;
\ No newline at end of file
diff --git a/afterpay/controllers/front/payment.php b/afterpay/controllers/front/payment.php
new file mode 100644
index 0000000..1233f57
--- /dev/null
+++ b/afterpay/controllers/front/payment.php
@@ -0,0 +1,140 @@
+
+* @copyright 2007-2016 PrestaShop SA
+* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
+* International Registered Trademark & Property of PrestaShop SA
+*/
+
+/**
+ * @since 1.5.0
+ */
+
+require_once(_PS_TOOL_DIR_.'mobile_Detect/Mobile_Detect.php');
+
+class AfterpayPaymentModuleFrontController extends ModuleFrontController
+{
+ public $ssl = true;
+ public $display_column_left = false;
+
+ /**
+ * @see FrontController::initContent()
+ */
+ public function initContent()
+ {
+ parent::initContent();
+
+ $cart = $this->context->cart;
+ if (!$this->module->checkCurrency($cart))
+ Tools::redirect('index.php?controller=order');
+
+ $this->context->smarty->assign( "afterpay_order_total", $this->_getCurrentCartTotalDisplay() );
+ $this->context->smarty->assign( "afterpay_instalment_breakdown", $this->_getCurrentInstalmentsDisplay() );
+ $this->context->smarty->assign( "afterpay_instalment_breakdown_last", $this->_getCurrentInstalmentsDisplayLast() );
+
+ $this->context->smarty->assign(array(
+ 'nbProducts' => $cart->nbProducts(),
+ 'cust_currency' => $cart->id_currency,
+ 'currencies' => $this->module->getCurrency((int)$cart->id_currency),
+ 'total' => $cart->getOrderTotal(true, Cart::BOTH),
+ 'isoCode' => $this->context->language->iso_code,
+ 'this_path' => $this->module->getPathUri(),
+ 'this_path_ssl' => Tools::getShopDomainSsl(true, true).__PS_BASE_URI__.'modules/'.$this->module->name.'/'
+ ));
+
+ $afterpay_error = Tools::getValue('afterpay_error');
+ $this->context->smarty->assign('afterpay_error', $afterpay_error);
+
+ if( $this->_getDeviceType() == "mobile" ) {
+ $this->setTemplate("payment_infos_mobile.tpl");
+ }
+ else {
+ $this->setTemplate("payment_infos.tpl");
+ }
+
+ }
+
+ /**
+ * Display function for Total Payment
+ *
+ * @return string
+ * since 1.0.0
+ */
+ private function _getCurrentCartTotalDisplay() {
+ $cart = $this->context->cart;
+ $order_total = round($cart->getOrderTotal(), 2);
+
+ return $this->context->currency->iso_code . " " . $this->context->currency->sign . $order_total;
+ }
+
+ /**
+ * Display function for Payment Breakdowns
+ *
+ * @return string
+ * since 1.0.0
+ */
+ private function _getCurrentInstalmentsDisplay( $amount = NULL ) {
+
+ if( empty($amount) ) {
+ $cart = $this->context->cart;
+ $amount = $cart->getOrderTotal();
+ }
+ $instalment = round($amount / 4, 2, PHP_ROUND_HALF_UP);
+
+ return $this->context->currency->iso_code . " " . $this->context->currency->sign . $instalment;
+ }
+
+ /**
+ * Display function for Last Payment Breakdown
+ *
+ * @return string
+ * since 1.0.0
+ */
+ private function _getCurrentInstalmentsDisplayLast( $amount = NULL ) {
+
+ if( empty($amount) ) {
+ $cart = $this->context->cart;
+ $amount = $cart->getOrderTotal();
+ }
+
+ $prev_instalments = round($amount / 4, 2, PHP_ROUND_HALF_UP);
+ $instalment = $amount - 3 * $prev_instalments;
+
+ return $this->context->currency->iso_code . " " . $this->context->currency->sign . $instalment;
+ }
+
+ /**
+ * Display function for Last Payment Breakdown
+ *
+ * @return string
+ * since 1.0.0
+ */
+ private function _getDeviceType() {
+
+ $this->mobile_detect = new Mobile_Detect();
+ $mobile_class = 'desktop';
+ if ($this->mobile_detect->isMobile()){
+ $mobile_class = 'mobile';
+ }
+
+ return $mobile_class;
+ }
+}
diff --git a/afterpay/controllers/front/return.php b/afterpay/controllers/front/return.php
new file mode 100644
index 0000000..8127832
--- /dev/null
+++ b/afterpay/controllers/front/return.php
@@ -0,0 +1,181 @@
+
+* @copyright 2007-2015 PrestaShop SA
+* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
+* International Registered Trademark & Property of PrestaShop SA
+*/
+
+/**
+ * @since 1.5.0
+ */
+require_once( _PS_MODULE_DIR_ . 'afterpay/classes/AfterpayCapture.php' );
+
+use PrestaShop\PrestaShop\Core\Payment\PaymentOption;
+
+class AfterpayReturnModuleFrontController extends ModuleFrontController
+{
+
+ private $afterpay_merchant_id;
+ private $afterpay_merchant_key;
+ private $afterpay_api_environment;
+ private $afterpay_user_agent;
+ private $params;
+
+ /**
+ * @see FrontController::postProcess()
+ */
+ public function postProcess()
+ {
+ $this->params = $_REQUEST;
+ $this->context->smarty->assign([
+ "params" => $this->params,
+ ]);
+
+ $params = $_REQUEST;
+
+ $validate_error = $this->_validateCredentials($params);
+
+ if( count($validate_error) ) {
+ $error["message"] = "Invalid Response: Missing Afterpay transaction " . implode($validate_error, ", ");
+ $this->_checkoutErrorRedirect($error);
+ }
+
+ $this->_retrieveAfterpayConfiguration();
+
+ $transaction_integrity = $this->_checkTransactionIntegrity();
+
+ $results = $this->_doCapture();
+
+ $this->setTemplate("module:afterpay/views/templates/front/payment_return.tpl");
+
+ }
+
+ private function _retrieveAfterpayConfiguration() {
+ $this->afterpay_merchant_id = Configuration::get('AFTERPAY_MERCHANT_ID');
+ $this->afterpay_merchant_key = Configuration::get('AFTERPAY_MERCHANT_KEY');
+ $this->afterpay_api_environment = Configuration::get('AFTERPAY_API_ENVIRONMENT');
+ $this->afterpay_user_agent = Configuration::get('AFTERPAY_USER_AGENT');
+ }
+
+ private function _checkTransactionIntegrity() {
+
+ $error = array(
+ "error" => false
+ );
+
+ $afterpay_capture = new AfterpayCapture($this->afterpay_merchant_id, $this->afterpay_merchant_key, $this->afterpay_api_environment, $this->params, NULL, $this->afterpay_user_agent);
+ $results = $afterpay_capture->doTransactionIntegrityChecking();
+
+
+
+ if( empty($results) ) {
+ $error["error"] = true;
+ $error["message"] = "Afterpay Transaction Capture Failed - Incorrect Order Token Detected";
+
+ $message = "Afterpay Transaction Integrity Check Error: " . $error['message'];
+ PrestaShopLogger::addLog($message, 2, NULL, "Afterpay", 1);
+
+ }
+ else if( $results["error"] && !empty($results["message"]) ) {
+ $error["error"] = true;
+ $error["message"] = $results["message"];
+
+
+ $log_message = "Afterpay Transaction Capture Failed; " .
+ $results["message"] . " " . $results["info"];
+
+ $message = "Afterpay Transaction Integrity Check Error: " . $log_message;
+ PrestaShopLogger::addLog($message, 2, NULL, "Afterpay", 1);
+ }
+ else if( $results["results"]->totalAmount->amount != round($this->context->cart->getOrderTotal(), 2) ) {
+ $error["error"] = true;
+ $error["message"] = "Afterpay Transaction Capture Failed - Incorrect Amount Detected";
+
+
+ $log_message = "Afterpay Transaction Capture Failed - Incorrect Amount Detected;" .
+ " API: " . $results["results"]->totalAmount->amount .
+ " Session: " . round($this->context->cart->getOrderTotal(), 2);
+
+
+ $message = "Afterpay Transaction Integrity Check Error: " . $log_message;
+ PrestaShopLogger::addLog($message, 2, NULL, "Afterpay", 1);
+ }
+ // else if( $results["results"]->merchantReference != $this->context->cart->id ) {
+ // $error["error"] = true;
+ // $error["message"] = "Afterpay Transaction Capture Failed - Incorrect Merchant Reference Detected";
+
+
+ // $log_message = "Afterpay Transaction Capture Failed - Incorrect Merchant Reference Detected;" .
+ // " Token: " . $this->params["orderToken"] .
+ // " API: " . $results["results"]->merchantReference .
+ // " Session: " . $this->context->cart->id;
+ // }
+
+ if( !empty($error) && !empty($error["error"]) && $error["error"] ) {
+ $this->_checkoutErrorRedirect($error);
+ }
+ }
+
+ private function _doCapture() {
+ $afterpay_capture = new AfterpayCapture($this->afterpay_merchant_id, $this->afterpay_merchant_key, $this->afterpay_api_environment, $this->params, NULL, $this->afterpay_user_agent);
+ $results = $afterpay_capture->createCapturePayment();
+
+ if( !empty($results) && !empty($results["error"]) && $results["error"] ) {
+
+ $message = "Afterpay Transaction Capture Failed: " . $results["message"];
+
+
+ $log_message = "Afterpay Transaction Capture Failed: " . $results["message"] . " " . $results["info"];
+
+ PrestaShopLogger::addLog($log_message, 2, NULL, "Afterpay", 1);
+
+ $this->_checkoutErrorRedirect($results);
+ }
+ else {
+ $customer = new Customer($this->context->cart->id_customer);
+ Tools::redirect('index.php?controller=order-confirmation&id_cart='.$this->context->cart->id.'&id_module='.$this->module->id.'&id_order='.$this->module->currentOrder.'&key='.$customer->secure_key);
+ }
+
+ return $results;
+ }
+
+
+ private function _validateCredentials($params) {
+ $error = array();
+
+ if( empty($params["orderToken"]) ) {
+ $error[] = "token";
+ }
+
+ if( empty($params["status"]) ) {
+ $error[] = "status";
+ }
+
+ return $error;
+ }
+
+
+ private function _checkoutErrorRedirect($results) {
+ $link = $this->context->link->getModuleLink('afterpay','payment', array("afterpay_error" => $results["message"]) );
+ Tools::redirect($link);
+ }
+}
diff --git a/afterpay/controllers/front/validation.php b/afterpay/controllers/front/validation.php
new file mode 100644
index 0000000..a4ea110
--- /dev/null
+++ b/afterpay/controllers/front/validation.php
@@ -0,0 +1,101 @@
+
+* @copyright 2007-2015 PrestaShop SA
+* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
+* International Registered Trademark & Property of PrestaShop SA
+*/
+
+/**
+ * @since 1.5.0
+ */
+require_once( _PS_MODULE_DIR_ . 'afterpay/classes/AfterpayCheckout.php' );
+
+class AfterpayValidationModuleFrontController extends ModuleFrontController
+{
+ /**
+ * @see FrontController::postProcess()
+ */
+ public function postProcess() {
+
+ $afterpay_merchant_id = strval(Configuration::get('AFTERPAY_MERCHANT_ID'));
+ $afterpay_merchant_key = strval(Configuration::get('AFTERPAY_MERCHANT_KEY'));
+ $afterpay_api_environment = strval(Configuration::get('AFTERPAY_API_ENVIRONMENT'));
+
+ $cart = $this->context->cart;
+ $currency_code = $this->context->currency->iso_code;
+
+ if ($cart->id_customer == 0 || $cart->id_address_delivery == 0 || $cart->id_address_invoice == 0 || !$this->module->active) {
+ Tools::redirect('index.php?controller=order&step=1');
+ }
+
+ // Check that this payment option is still available in case the customer changed his address just before the end of the checkout process
+ $authorized = false;
+ foreach (Module::getPaymentModules() as $module) {
+ if ($module['name'] == 'afterpay') {
+ $authorized = true;
+ break;
+ }
+ }
+
+ if (!$authorized) {
+ $this->_checkoutErrorRedirect('This payment method is not available. Please contact website administrator.');
+ }
+
+ // $params = $_REQUEST;
+
+ // $this->context->smarty->assign([
+ // 'params' => $params,
+ // ]);
+
+
+ $afterpay_checkout = new AfterpayCheckout($afterpay_merchant_id,
+ $afterpay_merchant_key,
+ $afterpay_api_environment,
+ $cart,
+ $currency_code
+ // $_REQUEST["user_agent"]
+ );
+
+ try{
+ $afterpay_checkout->createOrderToken();
+ }
+ catch( Exception $e ) {
+
+ $log_message = json_encode($e->getMessage());
+ $log_message = "Afterpay Token Generation Failure: " . $log_message . " Payload: " . preg_replace( "/\r|\n/", "", print_r($afterpay_checkout->_extractPayload(), true) );
+ PrestaShopLogger::addLog($log_message, 3, NULL, "Afterpay", 1);
+
+ $this->_checkoutErrorRedirect( "Afterpay Token Generation Failure. Please contact Website Administrator" );
+ }
+
+ $this->setTemplate('module:afterpay/views/templates/front/payment_return.tpl');
+ }
+
+ private function _checkoutErrorRedirect($message) {
+
+ if( !empty($message) ) {
+ $this->errors[] = $message;
+ }
+ $link = $this->context->link->getModuleLink('afterpay','payment', array("afterpay_error" => $message) );
+ Tools::redirect($link);
+ }
+}
\ No newline at end of file
diff --git a/afterpay/controllers/index.php b/afterpay/controllers/index.php
new file mode 100644
index 0000000..72b7262
--- /dev/null
+++ b/afterpay/controllers/index.php
@@ -0,0 +1,35 @@
+
+* @copyright 2007-2015 PrestaShop SA
+* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
+* International Registered Trademark & Property of PrestaShop SA
+*/
+
+header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
+header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
+
+header('Cache-Control: no-store, no-cache, must-revalidate');
+header('Cache-Control: post-check=0, pre-check=0', false);
+header('Pragma: no-cache');
+
+header('Location: ../../../');
+exit;
\ No newline at end of file
diff --git a/afterpay/css/afterpay-admin.css b/afterpay/css/afterpay-admin.css
new file mode 100644
index 0000000..1dcab93
--- /dev/null
+++ b/afterpay/css/afterpay-admin.css
@@ -0,0 +1,19 @@
+/** afterpay-admin.css */
+
+
+/* ------------------------------------------------------------------------------------
+ Order Page
+------------------------------------------------------------------------------------*/
+.product_action,
+#add_product,
+#add_voucher,
+.current-edit,
+button[name="submitChangeCurrency"],
+#desc-order-partial_refund
+{
+ display:none !important;
+}
+
+select[name="new_currency"] {
+ opacity: 0.6;
+}
\ No newline at end of file
diff --git a/afterpay/css/afterpay.css b/afterpay/css/afterpay.css
new file mode 100644
index 0000000..861edf6
--- /dev/null
+++ b/afterpay/css/afterpay.css
@@ -0,0 +1,139 @@
+/** afterpay.css */
+
+/* ------------------------------------------------------------------------------------
+ Product Page
+------------------------------------------------------------------------------------*/
+
+.afterpay-modal-image {
+ display: none;
+}
+
+@media only screen and (min-width : 992px) {
+ .afterpay-modal-image {
+ display: block;
+ }
+}
+
+.afterpay-modal-image-mobile {
+ display: block;
+}
+
+@media only screen and (min-width : 992px) {
+ .afterpay-modal-image-mobile {
+ display: none;
+}
+
+/*------------------------------------------------------------------------------------
+ Checkout Page
+------------------------------------------------------------------------------------*/
+#afterpaypayovertime-method {
+ text-align: center;
+}
+
+#afterpaypayovertime-method #afterpaypayovertime {
+ width: 80%;
+ margin: 0 auto;
+}
+
+#afterpaypayovertime-method .payment-method-note {
+ /*font-size: 1.2rem;*/
+ color: #a0a0a0;
+ text-align: center;
+}
+
+#afterpaypayovertime-method .payment-method-note .afterpay_instalments_amount {
+ font-size: 1.75rem;
+}
+
+#afterpaypayovertime-method .payment-method-note h3 {
+ color: #00a4e4;
+ text-align: left;
+}
+
+#afterpaypayovertime-method .payment-method-note ul {
+ padding-left: 1rem;
+ padding-right: 1rem;
+}
+
+#afterpaypayovertime-method .payment-method-note ul li {
+ width: 24%;
+ display: inline-block;
+}
+
+#afterpaypayovertime-method .payment-method-note ul.cost li {
+ font-size: 1.1rem;
+ color: #153F72;
+}
+
+#afterpaypayovertime-method .afterpay-checkout-redirect {
+ margin-top: 1rem;
+ text-align: left;
+ background-color: #f6f7f9;
+ display: inline-block;
+ padding: 15px;
+}
+
+#afterpaypayovertime-method .afterpay-checkout-redirect {
+ width: 100%;
+ text-align:center;
+}
+#afterpaypayovertime-method .afterpay-checkout-redirect a {
+ color: blue;
+}
+
+#afterpaypayovertime-method .actions-toolbar {
+ float: right;
+ margin-top: 1.5rem;
+ line-height: 1.1;
+ width: 100%;
+ text-align: center;
+}
+
+@media only screen and (min-width : 992px) {
+ #afterpaypayovertime-method .actions-toolbar {
+ width: auto;
+ margin-top: 0px;
+ }
+}
+
+@media only screen and (min-width : 768px) {
+ #afterpaypayovertime-method .actions-toolbar .primary {
+ width: 100%;
+ }
+}
+.afterpay_checkout_steps {
+ background-size: 12px 12px;
+ vertical-align: middle;
+ display: inline-block;
+ height: 12px;
+ width: 12px;
+}
+
+.checkout-methods-items button.btn-afterpay-checkout {
+ padding: 13px 15px 10px 10px;
+ width: 100%;
+}
+
+#afterpaypayovertime-method .afterpay-form {
+ margin-top: 10px;
+}
+
+#center_column #afterpaypayovertime-method .cart_navigation input,
+#center_column #afterpaypayovertime-method .cart_navigation a {
+ background-image: none;
+ background: #1979c3 !important;
+ border: 1px solid #1979c3;
+ color: #fff;
+ cursor: pointer;
+ display: inline-block;
+ font-family: 'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif;
+ font-weight: 600;
+ padding: 7px 15px;
+ font-size: 1.75rem;
+ box-sizing: border-box;
+ vertical-align: middle;
+ margin-left: 30px;
+ margin-right: 30px;
+ width: 250px;
+ text-align: center;
+}
\ No newline at end of file
diff --git a/afterpay/images/afterpay_logo_white.png b/afterpay/images/afterpay_logo_white.png
new file mode 100644
index 0000000..df6cc06
Binary files /dev/null and b/afterpay/images/afterpay_logo_white.png differ
diff --git a/afterpay/images/circle_1@2x.png b/afterpay/images/circle_1@2x.png
new file mode 100644
index 0000000..fe5acaf
Binary files /dev/null and b/afterpay/images/circle_1@2x.png differ
diff --git a/afterpay/images/circle_2@2x.png b/afterpay/images/circle_2@2x.png
new file mode 100644
index 0000000..d95bbcd
Binary files /dev/null and b/afterpay/images/circle_2@2x.png differ
diff --git a/afterpay/images/circle_3@2x.png b/afterpay/images/circle_3@2x.png
new file mode 100644
index 0000000..0ce47d1
Binary files /dev/null and b/afterpay/images/circle_3@2x.png differ
diff --git a/afterpay/images/circle_4@2x.png b/afterpay/images/circle_4@2x.png
new file mode 100644
index 0000000..0549362
Binary files /dev/null and b/afterpay/images/circle_4@2x.png differ
diff --git a/afterpay/images/logo.png b/afterpay/images/logo.png
new file mode 100644
index 0000000..8e2d262
Binary files /dev/null and b/afterpay/images/logo.png differ
diff --git a/afterpay/images/payment_checkout.png b/afterpay/images/payment_checkout.png
new file mode 100644
index 0000000..cb7ed10
Binary files /dev/null and b/afterpay/images/payment_checkout.png differ
diff --git a/afterpay/index.php b/afterpay/index.php
new file mode 100644
index 0000000..7673569
--- /dev/null
+++ b/afterpay/index.php
@@ -0,0 +1,36 @@
+
+* @copyright 2017 Afterpay Touch Group
+* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
+* International Registered Trademark & Property of PrestaShop SA
+*/
+
+
+header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
+header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
+
+header("Cache-Control: no-store, no-cache, must-revalidate");
+header("Cache-Control: post-check=0, pre-check=0", false);
+header("Pragma: no-cache");
+
+header("Location: ../");
+exit;
\ No newline at end of file
diff --git a/afterpay/js/afterpay.js b/afterpay/js/afterpay.js
new file mode 100644
index 0000000..ccf156c
--- /dev/null
+++ b/afterpay/js/afterpay.js
@@ -0,0 +1,37 @@
+$(document).ready(() => {
+
+ changeAfterpayInstalments();
+
+ $(".afterpay-modal-popup-trigger").fancybox({
+
+ afterShow: function() {
+ $('#afterpay-modal-popup').find(".close-afterpay-button").on("click", function(event) {
+ event.preventDefault();
+ $.fancybox.close();
+ })
+ }
+ });
+
+ $(document).on("change", ".attribute_select", function(e){
+ changeAfterpayInstalments();
+ });
+
+ $(document).on("click", ".attribute_radio", function(e){
+ changeAfterpayInstalments();
+ });
+
+ $(document).on("click", ".color_pick", function(e){
+ changeAfterpayInstalments();
+ });
+
+ function changeAfterpayInstalments() {
+ setTimeout( function(e) {
+ current_price = $("#our_price_display").text().replace(/[^\d\.]/g, '');
+
+ current_price = Math.round( current_price / 4 * 100) / 100;
+
+ $(".afterpay-installments-value").text(current_price);
+
+ }, 200);
+ }
+});
\ No newline at end of file
diff --git a/afterpay/logo.png b/afterpay/logo.png
new file mode 100644
index 0000000..8e2d262
Binary files /dev/null and b/afterpay/logo.png differ
diff --git a/afterpay/views/hook/payment.tpl b/afterpay/views/hook/payment.tpl
new file mode 100644
index 0000000..1d73c84
--- /dev/null
+++ b/afterpay/views/hook/payment.tpl
@@ -0,0 +1,31 @@
+{*
+* 2007-2016 PrestaShop
+*
+* NOTICE OF LICENSE
+*
+* This source file is subject to the Academic Free License (AFL 3.0)
+* that is bundled with this package in the file LICENSE.txt.
+* It is also available through the world-wide-web at this URL:
+* http://opensource.org/licenses/afl-3.0.php
+* If you did not receive a copy of the license and are unable to
+* obtain it through the world-wide-web, please send an email
+* to license@prestashop.com so we can send you a copy immediately.
+*
+* DISCLAIMER
+*
+* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
+* versions in the future. If you wish to customize PrestaShop for your
+* needs please refer to http://www.prestashop.com for more information.
+*
+* @author PrestaShop SA
+* @copyright 2007-2016 PrestaShop SA
+* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
+* International Registered Trademark & Property of PrestaShop SA
+*}
+
+
\ No newline at end of file
diff --git a/afterpay/views/templates/front/payment_infos.tpl b/afterpay/views/templates/front/payment_infos.tpl
new file mode 100644
index 0000000..1bcb285
--- /dev/null
+++ b/afterpay/views/templates/front/payment_infos.tpl
@@ -0,0 +1,94 @@
+{*
+* 2007-2015 PrestaShop
+*
+* NOTICE OF LICENSE
+*
+* This source file is subject to the Academic Free License (AFL 3.0)
+* that is bundled with this package in the file LICENSE.txt.
+* It is also available through the world-wide-web at this URL:
+* http://opensource.org/licenses/afl-3.0.php
+* If you did not receive a copy of the license and are unable to
+* obtain it through the world-wide-web, please send an email
+* to license@prestashop.com so we can send you a copy immediately.
+*
+* DISCLAIMER
+*
+* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
+* versions in the future. If you wish to customize PrestaShop for your
+* needs please refer to http://www.prestashop.com for more information.
+*
+* @author PrestaShop SA
+* @copyright 2007-2015 PrestaShop SA
+* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
+* International Registered Trademark & Property of PrestaShop SA
+*}
+
+
+ {if isset($afterpay_error) && $afterpay_error != "" }
+
+ {$afterpay_error}
+
+ {/if}
+
+
+
+
+
+ Four interest-free payments totalling
+ {$afterpay_order_total}
+
+
+
{$afterpay_instalment_breakdown}
+
{$afterpay_instalment_breakdown}
+
{$afterpay_instalment_breakdown}
+
{$afterpay_instalment_breakdown_last}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
First instalment
+
2 weeks later
+
4 weeks later
+
6 weeks later
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/afterpay/views/templates/front/payment_infos_mobile.tpl b/afterpay/views/templates/front/payment_infos_mobile.tpl
new file mode 100644
index 0000000..5fea9f6
--- /dev/null
+++ b/afterpay/views/templates/front/payment_infos_mobile.tpl
@@ -0,0 +1,70 @@
+{*
+* 2007-2015 PrestaShop
+*
+* NOTICE OF LICENSE
+*
+* This source file is subject to the Academic Free License (AFL 3.0)
+* that is bundled with this package in the file LICENSE.txt.
+* It is also available through the world-wide-web at this URL:
+* http://opensource.org/licenses/afl-3.0.php
+* If you did not receive a copy of the license and are unable to
+* obtain it through the world-wide-web, please send an email
+* to license@prestashop.com so we can send you a copy immediately.
+*
+* DISCLAIMER
+*
+* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
+* versions in the future. If you wish to customize PrestaShop for your
+* needs please refer to http://www.prestashop.com for more information.
+*
+* @author PrestaShop SA
+* @copyright 2007-2015 PrestaShop SA
+* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
+* International Registered Trademark & Property of PrestaShop SA
+*}
+
+
+ {if isset($afterpay_error) && $afterpay_error != "" }
+
+ {$afterpay_error}
+
+ {/if}
+
+
+
+
+
+
+ Four interest-free payments totalling:
+ {$afterpay_order_total}
+
+
+
First instalment - {$afterpay_instalment_breakdown}
+
2 weeks later - {$afterpay_instalment_breakdown}
+
4 weeks later - {$afterpay_instalment_breakdown}
+
6 weeks later - {$afterpay_instalment_breakdown_last}
\ No newline at end of file
diff --git a/afterpay/views/templates/front/product_page.tpl b/afterpay/views/templates/front/product_page.tpl
new file mode 100644
index 0000000..a710ad2
--- /dev/null
+++ b/afterpay/views/templates/front/product_page.tpl
@@ -0,0 +1,11 @@
+
+ or 4 interest-free payments of {$afterpay_instalment_breakdown} with
+
+
+
+
+
+
+ Learn more
+
+
\ No newline at end of file
diff --git a/afterpay/views/templates/index.php b/afterpay/views/templates/index.php
new file mode 100644
index 0000000..0f370e2
--- /dev/null
+++ b/afterpay/views/templates/index.php
@@ -0,0 +1,35 @@
+
+* @copyright 2007-2015 PrestaShop SA
+* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
+* International Registered Trademark & Property of PrestaShop SA
+*/
+
+header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
+header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
+
+header('Cache-Control: no-store, no-cache, must-revalidate');
+header('Cache-Control: post-check=0, pre-check=0', false);
+header('Pragma: no-cache');
+
+header('Location: ../../../../');
+exit;
\ No newline at end of file