<?xml version="1.0" encoding="utf-8"?>
<modification>
    <name>So OnePage Checkout</name>
    <code>so-onepage-checkout</code>
    <version>1.1.5</version>
    <author>OpenCartWorks</author>
    <link>http://www.opencartworks.com/</link>

    <file path="catalog/controller/checkout/checkout.php">
        <operation error="log">
            <search ><![CDATA[class ControllerCheckoutCheckout extends Controller {]]></search>
            <add position="after"><![CDATA[
                public function __construct($registry) {
                    parent::__construct($registry);
                    $this->load->language('checkout/cart');
                    $this->load->language('checkout/checkout');
            
                    $this->load->language('checkout/coupon');
                    $this->load->language('checkout/voucher');
                    $this->load->language('extension/module/so_onepagecheckout');
            
                    $this->load->model('account/activity');
                    $this->load->model('account/custom_field');
                    $this->load->model('tool/upload');
            
                    $this->load->model('account/address');
                    $this->load->model('account/customer');
                    $this->load->model('account/customer_group');
                    $this->load->model('localisation/country');
                    $this->load->model('localisation/zone');
                    $this->load->model('extension/module/so_onepagecheckout');
                }
                
                public function getProperty($array, $property, $default_value = null) {
                    $properties = explode('.', $property);
                    foreach ($properties as $prop) {
                        if (!is_array($array) || !isset($array[$prop])) {
                            return $default_value;
                        }
                        $array = $array[$prop];
                    }
                    if (is_array($array)) {
                        return $array;
                    }
                    $array = trim($array);
                    return $array !== '' ? $array : $default_value;
                }
                
                private function isShippingRequired() {
                    return $this->cart->hasShipping();
                }
            
                private function isLoggedIn() {
                    return $this->customer->isLogged();
                }
            
                private function allowGuestCheckout() {
                    return $this->config->get('config_checkout_guest') && !$this->config->get('config_customer_price') && !$this->cart->hasDownload();
                }

                private function renderRegisterForm() {
                    $this->load->model('setting/setting');
                    $setting_so_onepagecheckout                 = $this->model_setting_setting->getSetting('so_onepagecheckout');
                    $setting_so_onepagecheckout_general         = $setting_so_onepagecheckout['so_onepagecheckout_general'];
                    $setting_so_onepagecheckout_layout_setting  = $setting_so_onepagecheckout['so_onepagecheckout_layout_setting'];
                    $data['setting_so_onepagecheckout']                     = $setting_so_onepagecheckout;
                    $data['setting_so_onepagecheckout_general']             = $setting_so_onepagecheckout_general;
                    $data['setting_so_onepagecheckout_layout_setting']      = $setting_so_onepagecheckout_layout_setting;

                    $data['text_register'] = $this->language->get('text_register');
                    $data['text_guest'] = $this->language->get('text_guest');
                    $data['entry_email'] = $this->language->get('entry_email');
                    $data['entry_password'] = $this->language->get('entry_password');
                    $data['text_forgotten'] = $this->language->get('text_forgotten');
                    $data['text_loading'] = $this->language->get('text_loading');
                    $data['button_login'] = $this->language->get('button_login');
                    $data['text_i_am_returning_customer'] = $this->language->get('text_i_am_returning_customer');
                    $data['text_returning_customer'] = $this->language->get('text_returning_customer');

                    $data['text_your_details'] = $this->language->get('text_your_details');
                    $data['entry_customer_group'] = $this->language->get('entry_customer_group');
                    $data['entry_firstname'] = $this->language->get('entry_firstname');
                    $data['entry_lastname'] = $this->language->get('entry_lastname');
                    $data['entry_telephone'] = $this->language->get('entry_telephone');
                    $data['entry_fax'] = $this->language->get('entry_fax');
                    $data['text_your_password'] = $this->language->get('text_your_password');
                    $data['entry_confirm'] = $this->language->get('entry_confirm');
                    $data['text_your_address'] = $this->language->get('text_your_address');
                    $data['entry_shipping'] = $this->language->get('entry_shipping');
                    $data['text_shipping_address'] = $this->language->get('text_shipping_address');

                    $data['customer_groups'] = array();
                    $data['customer_group_id'] = $this->model_extension_module_so_onepagecheckout->getCustomerGroupId();
                    if (is_array($this->config->get('config_customer_group_display'))) {
                        $this->load->model('account/customer_group');

                        $customer_groups = $this->model_account_customer_group->getCustomerGroups();

                        foreach ($customer_groups  as $customer_group) {
                            if (in_array($customer_group['customer_group_id'], $this->config->get('config_customer_group_display'))) {
                                $data['customer_groups'][] = $customer_group;
                            }
                        }
                    }

                    $data['payment_address_form'] = $this->renderAddressForm('payment', false);
                    $data['shipping_address_form'] = $this->renderAddressForm('shipping');
                    $data['shipping_address'] = $this->getProperty($this->session->data, 'so_checkout_shipping_address', '1');
                    $data['is_shipping_required'] = $this->isShippingRequired();

                    $data['forgotten'] = $this->url->link('account/forgotten', '', true);

                    $data['custom_fields'] = $this->model_extension_module_so_onepagecheckout->getCustomFields();
                    $data['order_data'] = $this->model_extension_module_so_onepagecheckout->getOrder();

                    return $this->load->view('extension/module/so_onepagecheckout/checkout/register', $data);
                }

                private function renderAddressForm($type, $name = true) {
                    $this->load->model('setting/setting');
                    $setting_so_onepagecheckout                 = $this->model_setting_setting->getSetting('so_onepagecheckout');
                    $setting_so_onepagecheckout_general         = $setting_so_onepagecheckout['so_onepagecheckout_general'];
                    $setting_so_onepagecheckout_layout_setting  = $setting_so_onepagecheckout['so_onepagecheckout_layout_setting'];
                    
                    $data['type'] = $type;
                    $data['name'] = $name;

                    $data['button_upload'] = $this->language->get('button_upload');
                    $data['text_address_existing'] = $this->language->get('text_address_existing');
                    $data['text_address_new'] = $this->language->get('text_address_new');
                    $data['text_select'] = $this->language->get('text_select');
                    $data['text_none'] = $this->language->get('text_none');

                    $data['entry_firstname'] = $this->language->get('entry_firstname');
                    $data['entry_lastname'] = $this->language->get('entry_lastname');
                    $data['entry_company'] = $this->language->get('entry_company');
                    $data['entry_company_id'] = $this->language->get('entry_company_id');
                    $data['entry_tax_id'] = $this->language->get('entry_tax_id');
                    $data['entry_address_1'] = $this->language->get('entry_address_1');
                    $data['entry_address_2'] = $this->language->get('entry_address_2');
                    $data['entry_postcode'] = $this->language->get('entry_postcode');
                    $data['entry_city'] = $this->language->get('entry_city');
                    $data['entry_country'] = $this->language->get('entry_country');
                    $data['entry_zone'] = $this->language->get('entry_zone');

                    $data['custom_fields'] = $this->model_extension_module_so_onepagecheckout->getCustomFields($type);
                    $data['order_data'] = $this->model_extension_module_so_onepagecheckout->getOrder();

                    $data['addresses'] = $this->model_account_address->getAddresses();
                    $data['countries'] = $this->model_localisation_country->getCountries();

                    $address = $this->model_extension_module_so_onepagecheckout->getAddress($type);
                    foreach ($address as $key => $value) {
                        $data[$key] = $value;
                    }

                    if ($this->isLoggedIn()) {
                        $data['is_logged_in'] = true;
                    } else {
                        $data['is_logged_in'] = false;
                    }

                    if (isset($setting_so_onepagecheckout_general['so_onepagecheckout_country_id']) && $setting_so_onepagecheckout_general['so_onepagecheckout_country_id']) {
                        $data['country_id'] = $setting_so_onepagecheckout_general['so_onepagecheckout_country_id'];
                    }

                    if (isset($setting_so_onepagecheckout_general['so_onepagecheckout_zone_id']) && $setting_so_onepagecheckout_general['so_onepagecheckout_zone_id']) {
                        $data['zone_id'] = $setting_so_onepagecheckout_general['so_onepagecheckout_zone_id'];
                    }

                    return $this->load->view('extension/module/so_onepagecheckout/checkout/address_form', $data);
                }

                public function shipping($load = false) {
                    $this->load->model('setting/setting');
                    $setting_so_onepagecheckout                 = $this->model_setting_setting->getSetting('so_onepagecheckout');
                    $setting_so_onepagecheckout_general         = $setting_so_onepagecheckout['so_onepagecheckout_general'];
                    $setting_so_onepagecheckout_layout_setting  = $setting_so_onepagecheckout['so_onepagecheckout_layout_setting'];
                    $data['setting_so_onepagecheckout']                     = $setting_so_onepagecheckout;
                    $data['setting_so_onepagecheckout_general']             = $setting_so_onepagecheckout_general;
                    $data['setting_so_onepagecheckout_layout_setting']      = $setting_so_onepagecheckout_layout_setting;
                    
                    $data['text_shipping_method'] = $this->language->get('text_shipping_method');
                    $data['text_title_shipping_method'] = $this->language->get('text_title_shipping_method');
                    $data['error_shipping_method'] = $this->language->get('error_shipping_method');

                    $data['shipping_methods'] = $this->model_extension_module_so_onepagecheckout->getShippingMethods();
                    $shipping_methods = array();
                    if (count($data['shipping_methods'])>0) {
                        foreach ($data['shipping_methods'] as $key=>$shipping_method) {
                            if (@$setting_so_onepagecheckout_layout_setting[$key.'_status'] == 1) {
                                $shipping_methods[] = $shipping_method;
                            }
                        }
                    }
                    $data['shipping_methods'] = $shipping_methods;
                    $data['code'] = $this->model_extension_module_so_onepagecheckout->getShippingMethodCode();

                    if (!$data['shipping_methods']) {
                        $data['error_warning'] = sprintf($this->language->get('error_no_shipping'), $this->url->link('information/contact', '', true));
                    } else {
                        $data['error_warning'] = '';
                    }

                    if ($load)
                        return $this->load->view('extension/module/so_onepagecheckout/checkout/shipping_methods', $data);
                    else
                        return $this->response->setOutput($this->load->view('extension/module/so_onepagecheckout/checkout/shipping_methods', $data));

                }

                public function payment($load = false) {
                    $this->load->model('setting/setting');
                    $setting_so_onepagecheckout                 = $this->model_setting_setting->getSetting('so_onepagecheckout');
                    $setting_so_onepagecheckout_general         = $setting_so_onepagecheckout['so_onepagecheckout_general'];
                    $setting_so_onepagecheckout_layout_setting  = $setting_so_onepagecheckout['so_onepagecheckout_layout_setting'];
                    $data['setting_so_onepagecheckout']                     = $setting_so_onepagecheckout;
                    $data['setting_so_onepagecheckout_general']             = $setting_so_onepagecheckout_general;
                    $data['setting_so_onepagecheckout_layout_setting']      = $setting_so_onepagecheckout_layout_setting;

                    $data['text_payment_method']        = $this->language->get('text_payment_method');
                    $data['text_title_payment_method']  = $this->language->get('text_title_payment_method');

                    $data['payment_methods'] = $this->model_extension_module_so_onepagecheckout->getPaymentMethods();
                    $payment_methods = array();
                    if (count($data['payment_methods'])>0) {
                        foreach ($data['payment_methods'] as $key=>$payment_method) {
                            if (@$setting_so_onepagecheckout_layout_setting[$key.'_status'] == 1) {
                                $payment_methods[] = $payment_method;
                            }
                        }
                    }
                    $data['payment_methods'] = $payment_methods;
                    $data['code'] = $this->model_extension_module_so_onepagecheckout->getPaymentMethodCode();

                    if (!$data['payment_methods']) {
                        $data['error_warning'] = sprintf($this->language->get('error_no_payment'), $this->url->link('information/contact', '', true));
                    } else {
                        $data['error_warning'] = '';
                    }

                    if ($load)
                        return $this->load->view('extension/module/so_onepagecheckout/checkout/payment_methods', $data);
                    else
                        return $this->response->setOutput($this->load->view('extension/module/so_onepagecheckout/checkout/payment_methods', $data));
                }

                public function change_coupon_voucher_reward() {
                    $this->load->model('setting/setting');
                    $this->load->language('checkout/cart');
                    $this->load->language('checkout/checkout');
                    $this->load->language('extension/module/so_onepagecheckout');
                    $setting_so_onepagecheckout                 = $this->model_setting_setting->getSetting('so_onepagecheckout');
                    $setting_so_onepagecheckout_general         = $setting_so_onepagecheckout['so_onepagecheckout_general'];
                    $setting_so_onepagecheckout_layout_setting  = $setting_so_onepagecheckout['so_onepagecheckout_layout_setting'];
                    $data['setting_so_onepagecheckout']                     = $setting_so_onepagecheckout;
                    $data['setting_so_onepagecheckout_general']             = $setting_so_onepagecheckout_general;
                    $data['setting_so_onepagecheckout_layout_setting']      = $setting_so_onepagecheckout_layout_setting;

                    $data['text_loading'] = $this->language->get('text_loading');
                    $data['text_coupon_voucher'] = $this->language->get('text_coupon_voucher');
                    $data['text_enter_coupon_code'] = $this->language->get('text_enter_coupon_code');
                    $data['text_enter_voucher_code'] = $this->language->get('text_enter_voucher_code');
                    $data['text_apply_voucher'] = $this->language->get('text_apply_voucher');
                    $data['text_enter_reward_points'] = $this->language->get('text_enter_reward_points');
                    $data['text_apply_points'] = $this->language->get('text_apply_points');

                    $_data = $this->request->post;

                    if (@$_data['so_checkout_account'] == 'login') {
                        $data['coupon_status'] = $this->config->get('total_coupon_status') && $setting_so_onepagecheckout_layout_setting['coupon_login_status'];
                    }else if (@$_data['so_checkout_account'] == 'register') {
                        $data['coupon_status'] = $this->config->get('total_coupon_status') && $setting_so_onepagecheckout_layout_setting['coupon_register_status'];
                    }else if (@$_data['so_checkout_account'] == 'guest') {
                        $data['coupon_status'] = $this->config->get('total_coupon_status') && $setting_so_onepagecheckout_layout_setting['coupon_guest_status'];
                    }else {
                        $data['coupon_status'] = $this->config->get('total_coupon_status');
                    }
                    $data['entry_coupon'] = $this->language->get('entry_coupon');
                    $data['button_coupon'] = $this->language->get('button_coupon');
                    $data['coupon'] = $this->getProperty($this->session->data, 'coupon');

                    if (@$_data['so_checkout_account'] == 'login') {
                        $data['voucher_status'] = $this->config->get('total_voucher_status') && $setting_so_onepagecheckout_layout_setting['voucher_login_status'];
                    }else if (@$_data['so_checkout_account'] == 'register') {
                        $data['voucher_status'] = $this->config->get('total_voucher_status') && $setting_so_onepagecheckout_layout_setting['voucher_register_status'];
                    }else if (@$_data['so_checkout_account'] == 'guest') {
                        $data['voucher_status'] = $this->config->get('total_voucher_status') && $setting_so_onepagecheckout_layout_setting['voucher_guest_status'];
                    }else {
                        $data['voucher_status'] = $this->config->get('total_voucher_status');
                    }
                    $data['entry_voucher'] = $this->language->get('entry_voucher');
                    $data['button_voucher'] = $this->language->get('button_voucher');
                    $data['voucher'] = $this->getProperty($this->session->data, 'voucher');

                    $points = $this->customer->getRewardPoints();

                    $points_total = 0;

                    foreach ($this->cart->getProducts() as $product) {
                        if ($product['points']) {
                            $points_total += $product['points'];
                        }
                    }

                    if (@$_data['so_checkout_account'] == 'login') {
                        $data['reward_status'] = $points && $points_total && $this->config->get('total_reward_status') && $setting_so_onepagecheckout_layout_setting['reward_login_status'];
                    }else if (@$_data['so_checkout_account'] == 'register') {
                        $data['reward_status'] = $points && $points_total && $this->config->get('total_reward_status') && $setting_so_onepagecheckout_layout_setting['reward_register_status'];
                    }else if (@$_data['so_checkout_account'] == 'guest') {
                        $data['reward_status'] = $points && $points_total && $this->config->get('total_reward_status') && $setting_so_onepagecheckout_layout_setting['reward_guest_status'];
                    }
                    else {
                        $data['reward_status'] = $points && $points_total && $this->config->get('total_reward_status');
                    }
                    $data['entry_reward'] = $this->language->get('entry_reward');
                    $data['button_reward'] = $this->language->get('button_reward');
                    $data['reward'] = $this->getProperty($this->session->data, 'reward');

                    echo $this->load->view('extension/module/so_onepagecheckout/checkout/coupon_voucher_reward', $data);
                    exit();
                }

                public function save() {
                    $this->load->model('extension/module/so_onepagecheckout');
                    $this->load->model('account/address');
                    if ($value = $this->getProperty($this->request->post, 'shipping_address_id')) {
                        $this->session->data['shipping_address'] = $this->model_account_address->getAddress($value);
                        $this->model_extension_module_so_onepagecheckout->setAddress('shipping', $this->session->data['shipping_address']);
                    }

                    if ($value = $this->getProperty($this->request->post, 'shipping_country_id')) {
                        $this->model_extension_module_so_onepagecheckout->setAddress('shipping', array(
                            'country_id'    => $value,
                            'zone_id'       => $this->getProperty($this->request->post, 'shipping_zone_id'),
                            'postcode'      => $this->getProperty($this->request->post, 'shipping_postcode'),
                        ));
                    }

                    if ($value = $this->getProperty($this->request->post, 'shipping_method')) {
                        $shipping = explode('.', $value);
                        $this->session->data['shipping_method'] = $this->session->data['shipping_methods'][$shipping[0]]['quote'][$shipping[1]];
                    }

                    if ($value = $this->getProperty($this->request->post, 'payment_address_id')) {
                        $this->session->data['payment_address'] = $this->model_account_address->getAddress($value);
                        $this->model_extension_module_so_onepagecheckout->setAddress('payment', $this->session->data['payment_address']);
                    }

                    if ($value = $this->getProperty($this->request->post, 'payment_country_id')) {
                        $this->model_extension_module_so_onepagecheckout->setAddress('payment', array(
                            'country_id'    => $value,
                            'zone_id'       => $this->getProperty($this->request->post, 'payment_zone_id'),
                            'postcode'      => $this->getProperty($this->request->post, 'payment_postcode'),
                        ));
                    }

                    if ($value = $this->getProperty($this->request->post, 'payment_method')) {
                        $this->session->data['payment_method'] = $this->session->data['payment_methods'][$value];
                    }

                    $this->model_extension_module_so_onepagecheckout->save();

                    header('Content-Type: application/json');
                    echo '{}';

                    exit;
                }

                private function renderCouponVoucherReward() {
                    $this->load->model('setting/setting');
                    $setting_so_onepagecheckout                 = $this->model_setting_setting->getSetting('so_onepagecheckout');
                    $setting_so_onepagecheckout_general         = $setting_so_onepagecheckout['so_onepagecheckout_general'];
                    $setting_so_onepagecheckout_layout_setting  = $setting_so_onepagecheckout['so_onepagecheckout_layout_setting'];
                    $data['setting_so_onepagecheckout']                     = $setting_so_onepagecheckout;
                    $data['setting_so_onepagecheckout_general']             = $setting_so_onepagecheckout_general;
                    $data['setting_so_onepagecheckout_layout_setting']      = $setting_so_onepagecheckout_layout_setting;

                    $data['text_loading'] = $this->language->get('text_loading');
                    $data['text_coupon_voucher'] = $this->language->get('text_coupon_voucher');
                    $data['text_enter_coupon_code'] = $this->language->get('text_enter_coupon_code');
                    $data['text_enter_voucher_code'] = $this->language->get('text_enter_voucher_code');
                    $data['text_apply_voucher'] = $this->language->get('text_apply_voucher');
                    $data['text_enter_reward_points'] = $this->language->get('text_enter_reward_points');
                    $data['text_apply_points'] = $this->language->get('text_apply_points');

                    $_data = $this->session->data;

                    if (@$_data['so_checkout_account'] == 'login') {
                        $data['coupon_status'] = $this->config->get('total_coupon_status') && $setting_so_onepagecheckout_layout_setting['coupon_login_status'];
                    }else if (@$_data['so_checkout_account'] == 'register') {
                        $data['coupon_status'] = $this->config->get('total_coupon_status') && $setting_so_onepagecheckout_layout_setting['coupon_register_status'];
                    }else if (@$_data['so_checkout_account'] == 'guest') {
                        $data['coupon_status'] = $this->config->get('total_coupon_status') && $setting_so_onepagecheckout_layout_setting['coupon_guest_status'];
                    }else {
                        $data['coupon_status'] = $this->config->get('total_coupon_status');
                    }
                    $data['entry_coupon'] = $this->language->get('entry_coupon');
                    $data['button_coupon'] = $this->language->get('button_coupon');
                    $data['coupon'] = $this->getProperty($this->session->data, 'coupon');

                    if (@$_data['so_checkout_account'] == 'login') {
                        $data['voucher_status'] = $this->config->get('total_voucher_status') && $setting_so_onepagecheckout_layout_setting['voucher_login_status'];
                    }else if (@$_data['so_checkout_account'] == 'register') {
                        $data['voucher_status'] = $this->config->get('total_voucher_status') && $setting_so_onepagecheckout_layout_setting['voucher_register_status'];
                    }else if (@$_data['so_checkout_account'] == 'guest') {
                        $data['voucher_status'] = $this->config->get('total_voucher_status') && $setting_so_onepagecheckout_layout_setting['voucher_guest_status'];
                    }else {
                        $data['voucher_status'] = $this->config->get('total_voucher_status');
                    }
                    $data['entry_voucher'] = $this->language->get('entry_voucher');
                    $data['button_voucher'] = $this->language->get('button_voucher');
                    $data['voucher'] = $this->getProperty($this->session->data, 'voucher');

                    $points = $this->customer->getRewardPoints();

                    $points_total = 0;

                    foreach ($this->cart->getProducts() as $product) {
                        if ($product['points']) {
                            $points_total += $product['points'];
                        }
                    }

                    if (@$_data['so_checkout_account'] == 'login') {
                        $data['reward_status'] = $points && $points_total && $this->config->get('total_reward_status') && $setting_so_onepagecheckout_layout_setting['reward_login_status'];
                    }else if (@$_data['so_checkout_account'] == 'register') {
                        $data['reward_status'] = $points && $points_total && $this->config->get('total_reward_status') && $setting_so_onepagecheckout_layout_setting['reward_register_status'];
                    }else if (@$_data['so_checkout_account'] == 'guest') {
                        $data['reward_status'] = $points && $points_total && $this->config->get('total_reward_status') && $setting_so_onepagecheckout_layout_setting['reward_guest_status'];
                    }
                    else {
                        $data['reward_status'] = $points && $points_total && $this->config->get('total_reward_status');
                    }
                    $data['entry_reward'] = $this->language->get('entry_reward');
                    $data['button_reward'] = $this->language->get('button_reward');
                    $data['reward'] = $this->getProperty($this->session->data, 'reward');

                    return $this->load->view('extension/module/so_onepagecheckout/checkout/coupon_voucher_reward', $data);
                }

                public function cart($load = false) {
                    $this->load->model('setting/setting');
                    $this->load->model('extension/module/so_onepagecheckout');
                    $this->load->language('checkout/cart');
                    $this->load->language('checkout/checkout');
                    $this->load->language('extension/module/so_onepagecheckout');
                    $setting_so_onepagecheckout                 = $this->model_setting_setting->getSetting('so_onepagecheckout');
                    $setting_so_onepagecheckout_general         = $setting_so_onepagecheckout['so_onepagecheckout_general'];
                    $setting_so_onepagecheckout_layout_setting  = $setting_so_onepagecheckout['so_onepagecheckout_layout_setting'];
                    
                    $data['text_recurring_item'] = $this->language->get('text_recurring_item');
                    $data['text_payment_recurring'] = $this->language->get('text_payment_recurring');
                    $data['text_shopping_cart'] = $this->language->get('text_shopping_cart');
                    $data['text_payment_detail'] = $this->language->get('text_payment_detail');

                    $data['button_update'] = $this->language->get('button_update');
                    $data['button_remove'] = $this->language->get('button_remove');

                    $data['column_image'] = $this->language->get('column_image');
                    $data['column_name'] = $this->language->get('column_name');
                    $data['column_model'] = $this->language->get('column_model');
                    $data['column_quantity'] = $this->language->get('column_quantity');
                    $data['column_price'] = $this->language->get('column_price');
                    $data['column_total'] = $this->language->get('column_total');

                    $data['products'] = $this->model_extension_module_so_onepagecheckout->getProducts();
                    $data['vouchers'] = $this->model_extension_module_so_onepagecheckout->getVouchers();
                    $data['totals']   = $this->model_extension_module_so_onepagecheckout->getTotals();

                    if ($value = $this->getProperty($this->session->data, 'payment_method.code')) {
                        $data['payment'] = $this->load->controller('extension/payment/' . $value);
                    } else {
                        $data['payment'] = '';
                    }

                    $data['session_data']    = $this->session->data;

                    if ($this->config->get('config_cart_weight') && (isset($setting_so_onepagecheckout_layout_setting['show_product_weight']) && $setting_so_onepagecheckout_layout_setting['show_product_weight'])) {
                        $data['weight'] = $this->weight->format($this->cart->getWeight(), $this->config->get('config_weight_class_id'), $this->language->get('decimal_point'), $this->language->get('thousand_point'));
                    } else {
                        $data['weight'] = '';
                    }

                    $data['setting_so_onepagecheckout_layout_setting']  = $setting_so_onepagecheckout_layout_setting;

                    if ($load)
                        return $this->load->view('extension/module/so_onepagecheckout/checkout/cart', $data);
                    else
                        return $this->response->setOutput($this->load->view('extension/module/so_onepagecheckout/checkout/cart', $data));
                }

                public function cart_update() {
                    $this->load->language('checkout/cart');
                    $session_update = $this->getProperty($this->request->post, 'key');
                    $qty = $this->getProperty($this->request->post, 'quantity');
                    $this->cart->update($session_update, $qty);

                    $json = array();

                    if (!$this->checkCart()) {
                        $json['redirect'] = $this->url->link('checkout/cart', '', true);
                    } else {
                        $json['total'] = sprintf($this->language->get('text_items'), $this->cart->countProducts() + (isset($this->session->data['vouchers']) ? count($this->session->data['vouchers']) : 0), $this->registry->get('currency')->format($this->model_extension_module_so_onepagecheckout->getTotal(), $this->session->data['currency']));
                    }

                    echo json_encode($json);
                    exit;
                }

                public function cart_delete() {
                    $session_delete = $this->getProperty($this->request->post, 'key');

                    $this->cart->remove($session_delete);

                    unset($this->session->data['vouchers'][$session_delete]);

                    $json = array();

                    if (!$this->checkCart()) {
                        $json['redirect'] = $this->url->link('checkout/cart', '', true);
                    } else {
                        $json['total'] = sprintf($this->language->get('text_items'), $this->cart->countProducts() + (isset($this->session->data['vouchers']) ? count($this->session->data['vouchers']) : 0), $this->registry->get('currency')->format($this->model_extension_module_so_onepagecheckout->getTotal(), $this->session->data['currency']));
                    }

                    echo json_encode($json);
                    exit;
                }

                private function checkCart() {
                    // Validate cart has products and has stock.
                    if ((!$this->cart->hasProducts() && empty($this->session->data['vouchers'])) || (!$this->cart->hasStock() && !$this->config->get('config_stock_checkout'))) {
                        return false;
                    }

                    // Validate minimum quantity requirements.
                    $products = $this->cart->getProducts();

                    foreach ($products as $product) {
                        $product_total = 0;

                        foreach ($products as $product_2) {
                            if ($product_2['product_id'] == $product['product_id']) {
                                $product_total += $product_2['quantity'];
                            }
                        }

                        if ($product['minimum'] > $product_total) {
                            return false;
                        }
                    }

                    return true;
                }

                public function confirm() {
                    /* exit if page is accessed via get method */
                    if ($this->request->server['REQUEST_METHOD'] != 'POST') {
                        return;
                    }
                    $this->load->model('setting/setting');
                    $setting_so_onepagecheckout                 = $this->model_setting_setting->getSetting('so_onepagecheckout');
                    $setting_so_onepagecheckout_general         = $setting_so_onepagecheckout['so_onepagecheckout_general'];
                    $setting_so_onepagecheckout_layout_setting  = $setting_so_onepagecheckout['so_onepagecheckout_layout_setting'];

                    $order_data = $this->model_extension_module_so_onepagecheckout->getOrder();

                    $new_payment_address = null;
                    $new_shipping_address = null;

                    $register_account = $this->getProperty($this->request->post, 'account', 'register');

                    $errors = array();
                    $redirect_cart = '';

                    if (!$this->checkCart()) {
                        $errors['cart'] = '';
                        $redirect_cart = $this->url->link('checkout/cart', '', true);
                    }

                    if ($this->isLoggedIn()) {
                        // payment data
                        if ($this->getProperty($this->request->post, 'payment_address') === 'existing') {
                            $address_info = $this->model_account_address->getAddress($this->getProperty($this->request->post, 'payment_address_id'));
                            $order_data = array_replace($order_data, $this->getAddressData($address_info, '', 'payment_'));
                        } else {
                            $new_payment_address = $this->getAddressData($this->request->post, 'payment_', 'payment_');
                            $order_data = array_replace($order_data, $new_payment_address);
                            $errors = array_merge($errors, $this->validateAddressData($new_payment_address, 'payment_'));
                        }

                        // shipping data
                        if ($this->isShippingRequired()) {
                            if ($this->getProperty($this->request->post, 'shipping_address') === 'existing') {
                                $address_info = $this->model_account_address->getAddress($this->getProperty($this->request->post, 'shipping_address_id'));
                                $order_data = array_replace($order_data, $this->getAddressData($address_info, '', 'shipping_'));
                            } else {
                                $new_shipping_address = $this->getAddressData($this->request->post, 'shipping_', 'shipping_');
                                $order_data = array_replace($order_data, $new_shipping_address);
                                $errors = array_merge($errors, $this->validateAddressData($new_shipping_address, 'shipping_'));
                            }
                        }

                        // customer data
                        if (!$errors) {
                            $customer_info = $this->model_account_customer->getCustomer($this->customer->getId());

                            $order_data['customer_id'] = $this->customer->getId();
                            $order_data['customer_group_id'] = $customer_info['customer_group_id'];
                            $order_data['firstname'] = $customer_info['firstname'];
                            $order_data['lastname'] = $customer_info['lastname'];
                            $order_data['email'] = $customer_info['email'];
                            $order_data['telephone'] = $customer_info['telephone'];
                            $order_data['fax'] = $customer_info['fax'];
                            $order_data['custom_field'] = version_compare(VERSION, '2.1', '>=') ? json_decode($customer_info['custom_field'], true) : unserialize($customer_info['custom_field']);
                        }
                    } else {
                        // check firstname, lastname
                        $errors = array_merge($errors, $this->validateUserData($this->request->post, $register_account));

                        // check customer group id
                        if (isset($this->request->post['customer_group_id']) && is_array($this->config->get('config_customer_group_display')) && in_array($this->request->post['customer_group_id'], $this->config->get('config_customer_group_display'))) {
                            $order_data['customer_group_id'] = $this->request->post['customer_group_id'];
                        } else {
                            $order_data['customer_group_id'] = $this->config->get('config_customer_group_id');
                        }

                        if (!isset($this->request->post['account'])) {
                            $errors['account'] = array_merge($errors, array('Does not account exists! Please check configuration'));
                        }

                        // check passwords if register
                        if (($register_account == 'register') && isset($this->request->post['account'])) {
                            $errors = array_merge($errors, $this->validatePassword($this->request->post));
                        }

                        // check payment address
                        $new_payment_address = $this->getAddressData($this->request->post, 'payment_', 'payment_');
                        $order_data = array_replace($order_data, $new_payment_address);
                        $errors = array_merge($errors, $this->validateAddressData($new_payment_address, 'payment_', false));

                        // add payment firstname and lastname
                        $order_data['firstname'] = $this->request->post['firstname'];
                        $order_data['lastname'] = $this->request->post['lastname'];
                        $order_data['email'] = $this->request->post['email'];
                        $order_data['telephone'] = $this->request->post['telephone'];
                        $order_data['fax'] = $this->request->post['fax'];
                        $order_data['custom_field'] = $this->getProperty($this->request->post, 'custom_field', array());
                        $order_data['payment_firstname'] = $order_data['firstname'];
                        $order_data['payment_lastname'] = $order_data['lastname'];

                        // check delivery address
                        if ($this->isShippingRequired()) {
                            if (!$this->getProperty($this->request->post, 'shipping_address')) {
                                $new_shipping_address = $this->getAddressData($this->request->post, 'shipping_', 'shipping_');
                                $order_data = array_replace($order_data, $new_shipping_address);
                                $errors = array_merge($errors, $this->validateAddressData($new_shipping_address, 'shipping_'));
                            } else {
                                $order_data = array_replace($order_data, $this->getAddressData($order_data, 'payment_', 'shipping_'));
                            }
                        }
                    }

                    // payment method
                    if ($payment_method = $this->getProperty($this->session->data, 'payment_methods.' . $this->getProperty($this->request->post, 'payment_method') . '.title')) {
                        $order_data['payment_method'] = $payment_method;
                        $order_data['payment_code'] = $this->getProperty($this->request->post, 'payment_method');
                    } else {
                        $errors['payment_method'] = str_replace('&nbsp;', '', strip_tags($this->language->get('error_no_payment')));
                    }

                    // shipping method
                    if ($this->isShippingRequired()) {
                        $shipping = explode('.', $this->getProperty($this->request->post, 'shipping_method'));
                        if (is_array($shipping) && count($shipping) > 1) {
                            $shipping_method = $this->session->data['shipping_methods'][$shipping[0]]['quote'][$shipping[1]];
                            if ($shipping_method) {
                                $order_data['shipping_method'] = $shipping_method['title'];
                                $order_data['shipping_code'] = $this->getProperty($this->request->post, 'shipping_method');
                            } else {
                                $order_data['shipping_method'] = 'no shipping method';
                                $errors['shipping_method'] = str_replace('&nbsp;', '', strip_tags($this->language->get('error_no_shipping')));
                            }
                        } else {
                            $order_data['shipping_method'] = 'no shipping method';
                            $errors['shipping_method'] = str_replace('&nbsp;', '', strip_tags($this->language->get('error_no_shipping')));
                        }
                    }

                    // order totals
                    $totals = array();
                    $taxes = $this->cart->getTaxes();
                    $total = 0;

                    // Because __call can not keep var references so we put them into an array.
                    $total_data = array(
                        'totals' => &$totals,
                        'taxes'  => &$taxes,
                        'total'  => &$total
                    );

                    $this->load->model('setting/extension');
                    $results = $this->model_setting_extension->getExtensions('total');
                    
                    $sort_order = array();

                    foreach ($results as $key => $value) {
                        $sort_order[$key] = $this->config->get('total_'.$value['code'] . '_sort_order');
                    }

                    array_multisort($sort_order, SORT_ASC, $results);

                    foreach ($results as $result) {
                        if ($this->config->get('total_'.$result['code'] . '_status')) {
                            $this->load->model('extension/total/' . $result['code']);
                            
                            $this->{'model_extension_total_' . $result['code']}->getTotal($total_data);
                        }
                    }

                    $sort_order = array();

                    foreach ($totals as $key => $value) {
                        $sort_order[$key] = $value['sort_order'];
                    }

                    array_multisort($sort_order, SORT_ASC, $totals);

                    $order_data['totals'] = $totals;
                    $order_data['total'] = $total;

                    // order products
                    $order_data['products'] = array();

                    foreach ($this->cart->getProducts() as $product) {
                        $option_data = array();

                        foreach ($product['option'] as $option) {
                            $option_data[] = array(
                                'product_option_id'       => $option['product_option_id'],
                                'product_option_value_id' => $option['product_option_value_id'],
                                'option_id'               => $option['option_id'],
                                'option_value_id'         => $option['option_value_id'],
                                'name'                    => $option['name'],
                                'value'                   => $option['value'],
                                'type'                    => $option['type']
                            );
                        }

                        $order_data['products'][] = array(
                            'product_id' => $product['product_id'],
                            'name'       => $product['name'],
                            'model'      => $product['model'],
                            'option'     => $option_data,
                            'download'   => $product['download'],
                            'quantity'   => $product['quantity'],
                            'subtract'   => $product['subtract'],
                            'price'      => $product['price'],
                            'total'      => $product['total'],
                            'tax'        => $this->tax->getTax($product['price'], $product['tax_class_id']),
                            'reward'     => $product['reward']
                        );
                    }

                    // Gift Voucher
                    $order_data['vouchers'] = array();

                    if (!empty($this->session->data['vouchers'])) {
                        foreach ($this->session->data['vouchers'] as $voucher) {
                            $order_data['vouchers'][] = array(
                                'description'      => $voucher['description'],
                                'code'             => substr(md5(mt_rand()), 0, 10),
                                'to_name'          => $voucher['to_name'],
                                'to_email'         => $voucher['to_email'],
                                'from_name'        => $voucher['from_name'],
                                'from_email'       => $voucher['from_email'],
                                'voucher_theme_id' => $voucher['voucher_theme_id'],
                                'message'          => $voucher['message'],
                                'amount'           => $voucher['amount']
                            );
                        }
                    }

                    // comment + checkboxes
                    $order_data['comment'] = $this->getProperty($this->request->post, 'comment');
                    if ($setting_so_onepagecheckout_layout_setting['require_comment_status'] == 1 && empty($order_data['comment'])) {
                        $errors['comment']  = $this->language->get('error_comment');
                    }

                    if (!$this->isLoggedIn() && $this->config->get('config_account_id')) {
                        $this->load->model('catalog/information');

                        $information_info = $this->model_catalog_information->getInformation($this->config->get('config_account_id'));

                        if ($information_info && !isset($this->request->post['privacy'])) {
                            $errors['privacy'] = sprintf($this->language->get('error_agree'), $information_info['title']);
                        }
                    }

                    if ($this->config->get('config_checkout_id')) {
                        $this->load->model('catalog/information');

                        $information_info = $this->model_catalog_information->getInformation($this->config->get('config_checkout_id'));

                        if ($information_info && !isset($this->request->post['agree'])) {
                            $errors['agree'] = sprintf($this->language->get('error_agree'), $information_info['title']);
                        }
                    }

                    if (isset($errors['agree']) && empty($setting_so_onepagecheckout_layout_setting['show_term'])) {
                        unset($errors['agree']);
                    }

                    if ($this->config->get('config_account_id') == $this->config->get('config_checkout_id')) {
                        unset($errors['privacy']);
                    }

                    $redirect = '';

                    // update order
                    $this->model_extension_module_so_onepagecheckout->setOrderData($order_data);

                    if ($this->getProperty($this->request->get, 'saveOnly') === 'true') {
                        header('Content-Type: application/json');
                        echo json_encode(array(
                            'order_data'=> $order_data
                        ));
                        exit;
                    }

                    if (!$errors) {
                        if ($this->isLoggedIn()) {
                            // save new payment address
                            if ($new_payment_address) {
                                $this->model_account_address->addAddress($this->customer->getId(), $this->getAddressData($new_payment_address, 'payment_'));
                            }

                            // save new shipping address
                            if ($new_shipping_address && $new_shipping_address !== $new_payment_address) {
                                $this->model_account_address->addAddress($this->customer->getId(), $this->getAddressData($new_shipping_address, 'shipping_'));
                            }

                            $this->model_extension_module_so_onepagecheckout->updateCustomer();
                        } else if ($register_account == 'register') {
                            $redirect = $this->registerAccount();
                            $sql = "UPDATE `" . DB_PREFIX . "order` SET customer_id = '" . (int)($this->customer->getId()) . "', customer_group_id = '" . (int)($this->customer->getGroupId()) . "' WHERE order_id = '" . (int)($this->session->data['order_id']) . "'";
                            $this->db->query($sql);
                        } else {
                            $this->session->data['guest'] = $this->getAddressData($order_data, 'payment_');
                        }
                    }

                    $this->session->data['so_checkout_account']             = $this->getProperty($this->request->post, 'account');
                    $this->session->data['so_checkout_shipping_address']    = $this->getProperty($this->request->post, 'shipping_address', '0');

                    // send response
                    header('Content-Type: application/json');
                    echo json_encode(array(
                        'errors'    => $errors ? $errors : null,
                        'account_status' => $this->isLoggedIn() ? 1 : 0,
                        'redirect'  => $redirect,
                        'redirect_cart' => $redirect_cart,
                        'order_data'=> $order_data
                    ));
                    exit;
                }

                private function validateAddressData($data, $key, $name = true) {
                    $errors = array();

                    if ($name) {
                        // firstname
                        if ((utf8_strlen(trim($data[$key . 'firstname'])) < 1) || (utf8_strlen(trim($data[$key . 'firstname'])) > 32)) {
                            $errors[$key . 'firstname'] = $this->language->get('error_firstname');
                        }

                        // lastname
                        if ((utf8_strlen(trim($data[$key . 'lastname'])) < 1) || (utf8_strlen(trim($data[$key . 'lastname'])) > 32)) {
                            $errors[$key . 'lastname'] = $this->language->get('error_lastname');
                        }
                    }

                    if ((utf8_strlen(trim($data[$key . 'address_1'])) < 3) || (utf8_strlen(trim($data[$key . 'address_1'])) > 128)) {
                        $errors[$key . 'address_1'] = $this->language->get('error_address_1');
                    }

                    if ((utf8_strlen($data[$key . 'city']) < 2) || (utf8_strlen($data[$key . 'city']) > 32)) {
                        $errors[$key . 'city'] = $this->language->get('error_city');
                    }

                    $country_info = $this->model_localisation_country->getCountry($data[$key . 'country_id']);

                    if ($country_info && $country_info['postcode_required'] && (utf8_strlen(trim($data[$key . 'postcode'])) < 2 || utf8_strlen(trim($data[$key . 'postcode'])) > 10)) {
                        $errors[$key . 'postcode'] = $this->language->get('error_postcode');
                    }

                    if ($data[$key . 'country_id'] == '') {
                        $errors[$key . 'country'] = $this->language->get('error_country');
                    }

                    if (!isset($data[$key . 'zone_id']) || $data[$key . 'zone_id'] == '' || !is_numeric($data[$key . 'zone_id'])) {
                        $errors[$key . 'zone'] = $this->language->get('error_zone');
                    }

                    // Custom field validation
                    $custom_fields = $this->model_extension_module_so_onepagecheckout->getCustomFields();
                    foreach ($custom_fields as $custom_field) {
                        if (($custom_field['location'] == 'address') && $custom_field['required'] && empty($data[$key . 'custom_field'][$custom_field['custom_field_id']])) {
                            $errors[$key . 'custom_field' . $custom_field['custom_field_id']] = sprintf($this->language->get('error_custom_field'), $custom_field['name']);
                        }
                    }
                    
                    return $errors;
                }

                private function validateUserData($data, $register) {
                    $errors = array();

                    // firstname
                    if ((utf8_strlen(trim($data['firstname'])) < 1) || (utf8_strlen(trim($data['firstname'])) > 32)) {
                        $errors['firstname'] = $this->language->get('error_firstname');
                    }

                    // lastname
                    if ((utf8_strlen(trim($data['lastname'])) < 1) || (utf8_strlen(trim($data['lastname'])) > 32)) {
                        $errors['lastname'] = $this->language->get('error_lastname');
                    }

                    // email
                    if ((utf8_strlen($data['email']) > 96) || !preg_match('/^[^\@]+@.*.[a-z]{2,15}$/i', $data['email'])) {
                        $errors['email'] = $this->language->get('error_email');
                    } else if ($register && $this->model_account_customer->getTotalCustomersByEmail($data['email'])) {
                        $errors['email'] = $this->language->get('error_exists');
                    }

                    // telephone
                    if ((utf8_strlen($data['telephone']) < 3) || (utf8_strlen($data['telephone']) > 32)) {
                        $errors['telephone'] = $this->language->get('error_telephone');
                    }

                    // Custom field validation
                    $custom_fields = $this->model_extension_module_so_onepagecheckout->getCustomFields();

                    foreach ($custom_fields as $custom_field) {
                        if (($custom_field['location'] == 'account') && $custom_field['required'] && empty($data['custom_field'][$custom_field['custom_field_id']])) {
                            $errors['custom_field' . $custom_field['custom_field_id']] = sprintf($this->language->get('error_custom_field'), $custom_field['name']);
                        }
                    }
                    
                    return $errors;
                }

                private function validatePassword($data) {
                    $errors = array();

                    if ((utf8_strlen($data['password']) < 4) || (utf8_strlen($data['password']) > 20)) {
                        $errors['password'] = $this->language->get('error_password');
                    }

                    if ($data['confirm'] != $data['password']) {
                        $errors['confirm'] = $this->language->get('error_confirm');
                    }

                    return $errors;
                }

                private function getAddressData($array, $i_address = '', $prefix = '') {
                    $keys = array(
                        'address_1',
                        'address_2',
                        'address_id',
                        'address_format',
                        'city',
                        'company',
                        'company_id',
                        'country',
                        'country_id',
                        'firstname',
                        'lastname',
                        'method',
                        'postcode',
                        'tax_id',
                        'zone',
                        'zone_id'
                    );

                    $result = array();

                    foreach ($keys as $k) {
                        $result[$prefix . $k] = $this->getProperty($array, $i_address . $k, '');
                    }

                    if ($result[$prefix . 'country_id']) {
                        $country_info = $this->model_localisation_country->getCountry($result[$prefix . 'country_id']);
                        if ($country_info) {
                            if (!$result[$prefix . 'country']) {
                                $result[$prefix . 'country'] = $country_info['name'];
                            }
                            $result[$prefix . 'address_format'] = $country_info['address_format'];
                        }
                    }

                    if (!$result[$prefix . 'zone'] && $result[$prefix . 'zone_id']) {
                        $zone_info = $this->model_localisation_zone->getZone($result[$prefix . 'zone_id']);
                        if ($zone_info) {
                            $result[$prefix . 'zone'] = $zone_info['name'];
                        }
                    }

                    $result[$prefix . 'custom_field'] = $this->getProperty($array, $i_address . 'custom_field', array());
                    
                    return $result;
                }

                private function registerAccount() {
                    $redirect = '';

                    $data = $this->getAddressData($this->request->post, 'payment_');

                    $data = array_merge($data, array(
                        'firstname'     => $this->getProperty($this->request->post, 'firstname'),
                        'lastname'      => $this->getProperty($this->request->post, 'lastname'),
                        'customer_group_id'=> $this->getProperty($this->request->post, 'customer_group_id', $this->config->get('config_customer_group_id')),
                        'custom_field'  => array(
                            'account'   => $this->getProperty($this->request->post, 'custom_field'),
                            'address'   => $this->getProperty($this->request->post, 'payment_custom_field'),
                        ),
                        'email'         => $this->getProperty($this->request->post, 'email'),
                        'telephone'     => $this->getProperty($this->request->post, 'telephone'),
                        'fax'           => $this->getProperty($this->request->post, 'fax'),
                        'password'      => $this->getProperty($this->request->post, 'password'),
                        'newsletter'    => $this->getProperty($this->request->post, 'newsletter')
                    ));

                    $customer_id = $this->model_account_customer->addCustomer($data);

                    // Clear any previous login attempts for unregistered accounts.
                    $this->model_account_customer->deleteLoginAttempts($data['email']);
                    
                    $this->session->data['account'] = 'register';

                    $customer_group_info = $this->model_account_customer_group->getCustomerGroup($this->getProperty($this->request->post, 'customer_group_id', $this->config->get('config_customer_group_id')));

                    if ($customer_group_info && !$customer_group_info['approval']) {
                        $this->customer->login($data['email'], $data['password']);

                        if ($this->getProperty($this->request->post, 'shipping_address') != '1') {
                            $this->model_account_address->addAddress($customer_id, $this->getAddressData($this->request->post, 'shipping_'));
                        }

                        // Add to activity log
                        $activity_data = array(
                            'customer_id' => $customer_id,
                            'name' => $data['firstname'] . ' ' . $data['lastname']
                        );

                        $this->model_account_activity->addActivity('register', $activity_data);
                    }
                    else {
                        $redirect = $this->url->link('account/success');
                    }

                    return $redirect;
                }

                public function login() {
                    $json = array();

                    if ($this->customer->isLogged()) {
                        $json['redirect'] = $this->url->link('checkout/checkout', '', true);
                    }

                    if ((!$this->cart->hasProducts() && empty($this->session->data['vouchers'])) || (!$this->cart->hasStock() && !$this->config->get('config_stock_checkout'))) {
                        $json['redirect'] = $this->url->link('checkout/cart', '', true);
                    }

                    if (!$json) {
                        $this->load->model('account/customer');

                        // Check how many login attempts have been made.
                        $login_info = $this->model_account_customer->getLoginAttempts($this->request->post['email']);

                        if ($login_info && ($login_info['total'] >= $this->config->get('config_login_attempts')) && strtotime('-1 hour') < strtotime($login_info['date_modified'])) {
                            $json['error']['warning'] = $this->language->get('error_attempts');
                        }

                        // Check if customer has been approved.
                        $customer_info = $this->model_account_customer->getCustomerByEmail($this->request->post['email']);

                        if ($customer_info && !$customer_info['status']) {
                            $json['error']['warning'] = $this->language->get('error_approved');
                        }

                        if (!isset($json['error'])) {
                            if (!$this->customer->login($this->request->post['email'], $this->request->post['password'])) {
                                $json['error']['warning'] = $this->language->get('error_login');

                                $this->model_account_customer->addLoginAttempt($this->request->post['email']);
                            } else {
                                $this->model_account_customer->deleteLoginAttempts($this->request->post['email']);
                            }
                        }
                    }

                    if (!$json) {
                        unset($this->session->data['guest']);

                        $this->load->model('account/address');

                        $address_info = $this->model_account_address->getAddress($this->customer->getAddressId());

                        if ($this->config->get('config_tax_customer') == 'payment') {
                            $this->session->data['payment_address'] = $address_info;
                        }

                        if ($this->config->get('config_tax_customer') == 'shipping') {
                            $this->session->data['shipping_address'] = $address_info;
                        }

                        $this->model_extension_module_so_onepagecheckout->setAddress('shipping', $address_info);
                        $this->model_extension_module_so_onepagecheckout->setAddress('payment', $address_info);
                        $this->model_extension_module_so_onepagecheckout->save();

                        $json['redirect'] = $this->url->link('checkout/checkout', '', true);

                        // Add to activity log
                        $this->load->model('account/activity');

                        $activity_data = array(
                            'customer_id' => $this->customer->getId(),
                            'name' => $this->customer->getFirstName() . ' ' . $this->customer->getLastName()
                        );

                        $this->model_account_activity->addActivity('login', $activity_data);
                    }
                    
                    $this->response->addHeader('Content-Type: application/json');
                    $this->response->setOutput(json_encode($json));
                }
            ]]></add>
        </operation>
        
        <operation error="log">
            <search ><![CDATA[$data['breadcrumbs'] = array();]]></search>
            <add position="before"><![CDATA[
                $this->load->model('setting/setting');
                $setting_so_onepagecheckout                 = $this->model_setting_setting->getSetting('so_onepagecheckout');
                if (isset($setting_so_onepagecheckout) && count($setting_so_onepagecheckout)>0) {
                    $setting_so_onepagecheckout_general         = $setting_so_onepagecheckout['so_onepagecheckout_general'];                
                    if (isset($setting_so_onepagecheckout_general['so_onepagecheckout_enabled']) && $setting_so_onepagecheckout_general['so_onepagecheckout_enabled']) {
                        $this->document->addStyle('catalog/view/javascript/so_onepagecheckout/css/so_onepagecheckout.css');
                        $this->load->model('localisation/country');
                        $data['countries']  = $this->model_localisation_country->getCountries();
                    }
                }
            ]]></add>
        </operation>
        
        <operation error="log">
            <search ><![CDATA[$this->response->setOutput($this->load->view('checkout/checkout', $data));]]></search>
            <add position="before"><![CDATA[
                $this->load->model('setting/setting');
                $setting_so_onepagecheckout                 = $this->model_setting_setting->getSetting('so_onepagecheckout');
                if (isset($setting_so_onepagecheckout) && count($setting_so_onepagecheckout)>0) {
                    $setting_so_onepagecheckout_general         = $setting_so_onepagecheckout['so_onepagecheckout_general'];
                    $setting_so_onepagecheckout_layout_setting  = $setting_so_onepagecheckout['so_onepagecheckout_layout_setting'];

                    if (isset($setting_so_onepagecheckout_general['so_onepagecheckout_enabled']) && $setting_so_onepagecheckout_general['so_onepagecheckout_enabled']) {
                        if (isset($setting_so_onepagecheckout_layout_setting['so_onepagecheckout_account_open']) && !empty($setting_so_onepagecheckout_layout_setting['so_onepagecheckout_account_open'])) {
                            $data['default_auth'] = $setting_so_onepagecheckout_layout_setting['so_onepagecheckout_account_open'];
                        }
                        else {
                            $data['default_auth'] = $this->getProperty($this->session->data, 'so_checkout_account', 'register');
                        }

                        $data['setting_so_onepagecheckout']                 = $setting_so_onepagecheckout;
                        $data['setting_so_onepagecheckout_general']         = $setting_so_onepagecheckout_general;
                        $data['setting_so_onepagecheckout_layout_setting']  = $setting_so_onepagecheckout_layout_setting;
                        
                        $data['text_register'] = $this->language->get('text_register');
                        $data['text_guest'] = $this->language->get('text_guest');
                        $data['entry_email'] = $this->language->get('entry_email');
                        $data['entry_password'] = $this->language->get('entry_password');
                        $data['text_forgotten'] = $this->language->get('text_forgotten');
                        $data['text_loading'] = $this->language->get('text_loading');
                        $data['button_login'] = $this->language->get('button_login');
                        $data['text_i_am_returning_customer'] = $this->language->get('text_i_am_returning_customer');
                        $data['text_returning_customer'] = $this->language->get('text_returning_customer');
                        $data['text_checkout_create_account_login'] = $this->language->get('text_checkout_create_account_login');

                        $data['text_your_details'] = $this->language->get('text_your_details');
                        $data['entry_customer_group'] = $this->language->get('entry_customer_group');
                        $data['entry_firstname'] = $this->language->get('entry_firstname');
                        $data['entry_lastname'] = $this->language->get('entry_lastname');
                        $data['entry_telephone'] = $this->language->get('entry_telephone');
                        $data['entry_fax'] = $this->language->get('entry_fax');
                        $data['text_your_password'] = $this->language->get('text_your_password');
                        $data['entry_confirm'] = $this->language->get('entry_confirm');
                        $data['text_your_address'] = $this->language->get('text_your_address');
                        $data['entry_shipping'] = $this->language->get('entry_shipping');
                        $data['text_confirm_order'] = $this->language->get('text_confirm_order');

                        // address data
                        if ($this->isLoggedIn()) {
                            $data['is_logged_in'] = true;
                            $data['payment_address'] = $this->renderAddressForm('payment');
                            $data['shipping_address'] = $this->renderAddressForm('shipping');
                            $data['register_form'] = '';
                        } else {
                            $data['is_logged_in'] = false;
                            $data['allow_guest_checkout'] = $this->allowGuestCheckout();
                            $data['register_form'] = $this->renderRegisterForm();
                        }

                        // shipping
                        if ($this->isShippingRequired() && $setting_so_onepagecheckout_layout_setting['delivery_method_status']) {
                            $data['is_shipping_required'] = true;
                            $data['shipping_methods'] = $this->shipping(true);
                        } else {
                            $data['is_shipping_required'] = false;
                        }

                        // payment
                        $data['payment_methods'] = $this->payment(true);

                        // coupon + voucher
                        $data['coupon_voucher_reward'] = $this->renderCouponVoucherReward();

                        // cart
                        if (isset($setting_so_onepagecheckout_layout_setting['shopping_cart_status']) && $setting_so_onepagecheckout_layout_setting['shopping_cart_status']) {
                            $data['cart'] = $this->cart(true);
                        }
                        else {
                            $data['cart'] = '';
                        }

                        // checkboxes
                        if (!$this->isLoggedIn() && $this->config->get('config_account_id')) {
                            $this->load->model('catalog/information');

                            $information_info = $this->model_catalog_information->getInformation($this->config->get('config_account_id'));

                            if ($information_info) {
                                $data['text_privacy'] = sprintf($this->language->get('text_agree'), $this->url->link('information/information/agree', 'information_id=' . $this->config->get('config_account_id'), true), $information_info['title'], $information_info['title']);
                            } else {
                                $data['text_privacy'] = '';
                            }
                        } else {
                            $data['text_privacy'] = '';
                        }

                        if ($this->config->get('config_checkout_id')) {
                            $this->load->model('catalog/information');

                            $information_info = $this->model_catalog_information->getInformation($this->config->get('config_checkout_id'));

                            if ($information_info) {
                                $data['text_agree'] = sprintf($this->language->get('text_agree'), $this->url->link('information/information/agree', 'information_id=' . $this->config->get('config_checkout_id'), true), $information_info['title'], $information_info['title']);
                            } else {
                                $data['text_agree'] = '';
                            }
                        } else {
                            $data['text_agree'] = '';
                        }

                        if ($data['text_privacy'] === $data['text_agree']) {
                            $data['text_privacy'] = '';
                        }

                        $data['text_comments'] = $this->language->get('text_comments');

                        if ($this->isLoggedIn()) {
                            $data['entry_newsletter'] = false;
                        } else {
                            $data['entry_newsletter'] = sprintf($this->language->get('entry_newsletter'), $this->config->get('config_name'));
                        }

                        $data['comment'] = $this->model_extension_module_so_onepagecheckout->getComment();

                        if (isset($this->session->data['error'])) {
                            $data['error_warning'] = $this->session->data['error'];
                            unset($this->session->data['error']);
                        } else {
                            $data['error_warning'] = '';
                        }

                        $data['customer_groups'] = array();
                        if (is_array($this->config->get('config_customer_group_display'))) {
                            $this->load->model('account/customer_group');
                
                            $customer_groups = $this->model_account_customer_group->getCustomerGroups();
                
                            foreach ($customer_groups as $customer_group) {
                                if (in_array($customer_group['customer_group_id'], $this->config->get('config_customer_group_display'))) {
                                    $data['customer_groups'][] = $customer_group;
                                }
                            }
                        }
                        if (isset($this->request->post['customer_group_id'])) {
                            $data['customer_group_id'] = $this->request->post['customer_group_id'];
                        } else {
                            $data['customer_group_id'] = $this->config->get('config_customer_group_id');
                        }
                        
                        
                        
                        //Get cart
                        $this->load->model('tool/image');
                        $this->load->model('tool/upload');
                        
                        $data['products'] = array();
                        $products = $this->cart->getProducts();
                        foreach ($products as $product) {
                            $product_total = 0;
                            
                            foreach ($products as $product_2) {
                                if ($product_2['product_id'] == $product['product_id']) {
                                    $product_total += $product_2['quantity'];
                                }
                            }
                            
                            if ($product['minimum'] > $product_total) {
                                $data['error_warning'] = sprintf($this->language->get('error_minimum'), $product['name'], $product['minimum']);
                            }
            
                            if ($product['image']) {
                                $image = $this->model_tool_image->resize($product['image'], $this->config->get('theme_'.$this->config->get('config_theme') . '_image_cart_width'), $this->config->get('theme_'.$this->config->get('config_theme') . '_image_cart_height'));
                            } else {
                                $image = '';
                            }
            
                            $option_data = array();
            
                            foreach ($product['option'] as $option) {
                                if ($option['type'] != 'file') {
                                    $value = $option['value'];
                                } else {
                                    $upload_info = $this->model_tool_upload->getUploadByCode($option['value']);
            
                                    if ($upload_info) {
                                        $value = $upload_info['name'];
                                    } else {
                                        $value = '';
                                    }
                                }
            
                                $option_data[] = array(
                                    'name'  => $option['name'],
                                    'value' => (utf8_strlen($value) > 20 ? utf8_substr($value, 0, 20) . '..' : $value)
                                );
                            }
            
                            // Display prices
                            if ($this->customer->isLogged() || !$this->config->get('config_customer_price')) {
                                $unit_price = $this->tax->calculate($product['price'], $product['tax_class_id'], $this->config->get('config_tax'));
                                
                                $price = $this->currency->format($unit_price, $this->session->data['currency']);
                                $total = $this->currency->format($unit_price * $product['quantity'], $this->session->data['currency']);
                            } else {
                                $price = false;
                                $total = false;
                            }
            
                            $recurring = '';
            
                            if ($product['recurring']) {
                                $frequencies = array(
                                    'day'        => $this->language->get('text_day'),
                                    'week'       => $this->language->get('text_week'),
                                    'semi_month' => $this->language->get('text_semi_month'),
                                    'month'      => $this->language->get('text_month'),
                                    'year'       => $this->language->get('text_year'),
                                );
            
                                if ($product['recurring']['trial']) {
                                    $recurring = sprintf($this->language->get('text_trial_description'), $this->currency->format($this->tax->calculate($product['recurring']['trial_price'] * $product['quantity'], $product['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency']), $product['recurring']['trial_cycle'], $frequencies[$product['recurring']['trial_frequency']], $product['recurring']['trial_duration']) . ' ';
                                }
            
                                if ($product['recurring']['duration']) {
                                    $recurring .= sprintf($this->language->get('text_payment_description'), $this->currency->format($this->tax->calculate($product['recurring']['price'] * $product['quantity'], $product['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency']), $product['recurring']['cycle'], $frequencies[$product['recurring']['frequency']], $product['recurring']['duration']);
                                } else {
                                    $recurring .= sprintf($this->language->get('text_payment_cancel'), $this->currency->format($this->tax->calculate($product['recurring']['price'] * $product['quantity'], $product['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency']), $product['recurring']['cycle'], $frequencies[$product['recurring']['frequency']], $product['recurring']['duration']);
                                }
                            }
            
                            $data['products'][] = array(
                                'cart_id'   => $product['cart_id'],
                                'thumb'     => $image,
                                'name'      => $product['name'],
                                'model'     => $product['model'],
                                'option'    => $option_data,
                                'recurring' => $recurring,
                                'quantity'  => $product['quantity'],
                                'stock'     => $product['stock'] ? true : !(!$this->config->get('config_stock_checkout') || $this->config->get('config_stock_warning')),
                                'reward'    => ($product['reward'] ? sprintf($this->language->get('text_points'), $product['reward']) : ''),
                                'price'     => $price,
                                'total'     => $total,
                                'href'      => $this->url->link('product/product', 'product_id=' . $product['product_id'])
                            );
                        }
                        
                        // Gift Voucher
                        $data['vouchers'] = array();
            
                        if (!empty($this->session->data['vouchers'])) {
                            foreach ($this->session->data['vouchers'] as $key => $voucher) {
                                $data['vouchers'][] = array(
                                    'key'         => $key,
                                    'description' => $voucher['description'],
                                    'amount'      => $this->currency->format($voucher['amount'], $this->session->data['currency']),
                                    'remove'      => $this->url->link('checkout/cart', 'remove=' . $key)
                                );
                            }
                        }
                        
                        // Totals
                        $this->load->model('setting/extension');
            
                        $totals = array();
                        $taxes = $this->cart->getTaxes();
                        $total = 0;
                        
                        // Because __call can not keep var references so we put them into an array.             
                        $total_data = array(
                            'totals' => &$totals,
                            'taxes'  => &$taxes,
                            'total'  => &$total
                        );
                        
                        // Display prices
                        if ($this->customer->isLogged() || !$this->config->get('config_customer_price')) {
                            $sort_order = array();
            
                            $results = $this->model_setting_extension->getExtensions('total');
            
                            foreach ($results as $key => $value) {
                                $sort_order[$key] = $this->config->get('total_'.$value['code'] . '_sort_order');
                            }
            
                            array_multisort($sort_order, SORT_ASC, $results);
            
                            foreach ($results as $result) {
                                if ($this->config->get('total_'.$result['code'] . '_status')) {
                                    $this->load->model('extension/total/' . $result['code']);
                                    
                                    // We have to put the totals in an array so that they pass by reference.
                                    $this->{'model_extension_total_' . $result['code']}->getTotal($total_data);
                                }
                            }
            
                            $sort_order = array();
            
                            foreach ($totals as $key => $value) {
                                $sort_order[$key] = $value['sort_order'];
                            }
            
                            array_multisort($sort_order, SORT_ASC, $totals);
                        }
            
                        $data['totals'] = array();
                    
                        foreach ($totals as $total) {
                            $data['totals'][] = array(
                                'title' => $total['title'],
                                'text'  => $this->currency->format($total['value'], $this->session->data['currency'])
                            );
                        }
                    }
                }
            ]]></add>
        </operation>
        
        <operation error="log">
            <search ><![CDATA[$this->response->setOutput($this->load->view('checkout/checkout', $data));]]></search>
            <add position="replace"><![CDATA[
                if (isset($setting_so_onepagecheckout_general['so_onepagecheckout_enabled']) && $setting_so_onepagecheckout_general['so_onepagecheckout_enabled']) {
                    $data['forgotten'] = $this->url->link('account/forgotten', '', true);
                    $this->model_extension_module_so_onepagecheckout->save();
                    if ($setting_so_onepagecheckout_general['so_onepagecheckout_layout'] == 1)
                        $this->response->setOutput($this->load->view('extension/module/so_onepagecheckout/default', $data));
                    else if ($setting_so_onepagecheckout_general['so_onepagecheckout_layout'] == 2)
                        $this->response->setOutput($this->load->view('extension/module/so_onepagecheckout/default2', $data));
                }
                else {
                    $this->response->setOutput($this->load->view('checkout/checkout', $data));
                }
            ]]></add>
        </operation>
    </file>
</modification>