public function display()
 {
     if (!$this->form) {
         $this->form = shopHelper::getCustomerForm();
     }
     $contact = $this->getContact();
     if ($contact) {
         $this->form->setValue($contact);
         // Make sure there are no more than one address of each type in the form
         foreach (array('address', 'address.shipping', 'address.billing') as $fld) {
             if (isset($this->form->values[$fld]) && count($this->form->values[$fld]) > 1) {
                 $this->form->values[$fld] = array(reset($this->form->values[$fld]));
             }
         }
     }
     $view = wa()->getView();
     $view->assign('checkout_contact_form', $this->form);
     $view->assign('customer', $contact ? $contact : new waContact());
     if (!$view->getVars('error')) {
         $view->assign('error', array());
     }
     $checkout_flow = new shopCheckoutFlowModel();
     $step_number = shopOnestepCheckout::getStepNumber('contactinfo');
     // IF no errors
     $checkout_flow->add(array('step' => $step_number));
     // ELSE
     //        $checkout_flow->add(array(
     //            'step' => $step_number,
     //            'description' => ERROR MESSAGE HERE
     //        ));
 }
 public function execute()
 {
     list($start_date, $end_date, $group_by) = shopReportsSalesAction::getTimeframeParams();
     $checkout_flow = new shopCheckoutFlowModel();
     $stat = $checkout_flow->getStat($start_date, $end_date);
     $app_settings_model = new waAppSettingsModel();
     $this->view->assign(array('stat' => $stat, 'checkout_flow_changed' => $app_settings_model->get('shop', 'checkout_flow_changed', 0)));
 }
 public function execute()
 {
     if (waRequest::post()) {
         $checkout_flow = new shopCheckoutFlowModel();
         $checkout_flow->clear();
         $app_settings_model = new waAppSettingsModel();
         $app_settings_model->del('shop', 'checkout_flow_changed');
     }
 }
 public function display()
 {
     $plugin_model = new shopPluginModel();
     if (waRequest::param('payment_id') && is_array(waRequest::param('payment_id'))) {
         $methods = $plugin_model->getById(waRequest::param('payment_id'));
     } else {
         $methods = $plugin_model->listPlugins('payment');
     }
     $shipping = $this->getSessionData('shipping');
     if ($shipping) {
         $disabled = shopHelper::getDisabledMethods('payment', $shipping['id']);
     } else {
         $disabled = array();
     }
     $currencies = wa('shop')->getConfig()->getCurrencies();
     $selected = null;
     foreach ($methods as $key => $m) {
         $method_id = $m['id'];
         if (in_array($method_id, $disabled)) {
             unset($methods[$key]);
             continue;
         }
         $plugin = shopPayment::getPlugin($m['plugin'], $m['id']);
         $plugin_info = $plugin->info($m['plugin']);
         $methods[$key]['icon'] = $plugin_info['icon'];
         $custom_fields = $this->getCustomFields($method_id, $plugin);
         $custom_html = '';
         foreach ($custom_fields as $c) {
             $custom_html .= '<div class="wa-field">' . $c . '</div>';
         }
         $methods[$key]['custom_html'] = $custom_html;
         $allowed_currencies = $plugin->allowedCurrency();
         if ($allowed_currencies !== true) {
             $allowed_currencies = (array) $allowed_currencies;
             if (!array_intersect($allowed_currencies, array_keys($currencies))) {
                 $methods[$key]['error'] = sprintf(_w('Payment procedure cannot be processed because required currency %s is not defined in your store settings.'), implode(', ', $allowed_currencies));
             }
         }
         if (!$selected && empty($methods[$key]['error'])) {
             $selected = $method_id;
         }
     }
     $view = wa()->getView();
     $view->assign('checkout_payment_methods', $methods);
     $view->assign('payment_id', $this->getSessionData('payment', $selected));
     $checkout_flow = new shopCheckoutFlowModel();
     $step_number = shopCheckout::getStepNumber('payment');
     // IF no errors
     $checkout_flow->add(array('step' => $step_number));
     // ELSE
     //        $checkout_flow->add(array(
     //            'step' => $step_number,
     //            'description' => ERROR MESSAGE HERE
     //        ));
 }
 public function display()
 {
     $settings = wa('shop')->getConfig()->getCheckoutSettings();
     if (!empty($settings['confirmation']['terms']) && waRequest::get('terms')) {
         echo $settings['confirmation']['terms'];
         exit;
     }
     $cart = new shopCart();
     $items = $cart->items(false);
     $subtotal = $cart->total(false);
     $order = array('contact' => $this->getContact(), 'total' => $subtotal, 'items' => $items);
     $order['discount'] = shopDiscounts::calculate($order);
     $contact = $this->getContact();
     $view = wa()->getView();
     if (!$contact) {
         $view->assign('error', _w('Not enough data in the contact information to place the order.'));
         return;
     }
     $shipping_address = $contact->getFirst('address.shipping');
     if (!$shipping_address) {
         $shipping_address = array('data' => array(), 'value' => '');
     }
     $billing_address = $contact->getFirst('address.billing');
     if (!$billing_address) {
         $billing_address = array('data' => array(), 'value' => '');
     }
     $discount_rate = (double) $subtotal ? $order['discount'] / $subtotal : 0;
     $taxes = shopTaxes::apply($items, array('shipping' => $shipping_address['data'], 'billing' => $billing_address['data'], 'discount_rate' => $discount_rate));
     $tax = 0;
     $tax_included = 0;
     foreach ($taxes as $t) {
         if (isset($t['sum'])) {
             $tax += $t['sum'];
         }
         if (isset($t['sum_included'])) {
             $tax_included += $t['sum_included'];
         }
     }
     if (!isset($order['shipping'])) {
         $shipping_step = new shopOnestepCheckoutShipping();
         $rate = $shipping_step->getRate();
         if ($rate) {
             $order['shipping'] = $rate['rate'];
         } else {
             $order['shipping'] = 0;
         }
     }
     $plugin_model = new shopPluginModel();
     $params = array();
     if ($shipping = $this->getSessionData('shipping')) {
         $params['shipping_id'] = $shipping['id'];
         if ($shipping['id']) {
             $plugin_info = $plugin_model->getById($shipping['id']);
             $params['shipping_rate_id'] = $shipping['rate_id'];
             $params['shipping_name'] = $shipping['name'];
             $params['shipping_description'] = $plugin_info['description'];
         }
     }
     if ($payment_id = $this->getSessionData('payment')) {
         $params['payment_id'] = $payment_id;
         $plugin_info = $plugin_model->getById($payment_id);
         $params['payment_name'] = $plugin_info['name'];
         $params['payment_plugin'] = $plugin_info['plugin'];
         $params['payment_description'] = $plugin_info['description'];
     }
     $view->assign(array('params' => $params, 'contact' => $contact, 'items' => $items, 'shipping' => $order['shipping'], 'discount' => $order['discount'], 'total' => $subtotal - $order['discount'] + $order['shipping'] + $tax, 'tax' => $tax_included + $tax, 'subtotal' => $subtotal, 'shipping_address' => $shipping_address, 'billing_address' => !empty($settings['contactinfo']['fields']['address.billing']) ? $billing_address : false, 'terms' => !empty($settings['confirmation']['terms']) ? $settings['confirmation']['terms'] : false));
     $checkout_flow = new shopCheckoutFlowModel();
     $step_number = shopOnestepCheckout::getStepNumber('confirmation');
     // IF no errors
     $checkout_flow->add(array('step' => $step_number));
     // ELSE
     //        $checkout_flow->add(array(
     //            'step' => $step_number,
     //            'description' => ERROR MESSAGE HERE
     //        ));
 }
 protected function createOrder()
 {
     $checkout_data = wa()->getStorage()->get('shop/checkout');
     if (wa()->getUser()->isAuth()) {
         $contact = wa()->getUser();
     } else {
         if (!empty($checkout_data['contact']) && $checkout_data['contact'] instanceof waContact) {
             $contact = $checkout_data['contact'];
         } else {
             $contact = new waContact();
         }
     }
     $cart = new shopCart();
     $items = $cart->items(false);
     // remove id from item
     foreach ($items as &$item) {
         unset($item['id']);
         unset($item['parent_id']);
     }
     unset($item);
     $order = array('contact' => $contact, 'items' => $items, 'total' => $cart->total(false), 'params' => isset($checkout_data['params']) ? $checkout_data['params'] : array());
     $order['discount_description'] = null;
     $order['discount'] = shopDiscounts::apply($order, $order['discount_description']);
     if (isset($checkout_data['shipping'])) {
         $order['params']['shipping_id'] = $checkout_data['shipping']['id'];
         $order['params']['shipping_rate_id'] = $checkout_data['shipping']['rate_id'];
         $shipping_step = new shopOnestepCheckoutShipping();
         $rate = $shipping_step->getRate($order['params']['shipping_id'], $order['params']['shipping_rate_id']);
         $order['params']['shipping_plugin'] = $rate['plugin'];
         $order['params']['shipping_name'] = $rate['name'];
         if (isset($rate['est_delivery'])) {
             $order['params']['shipping_est_delivery'] = $rate['est_delivery'];
         }
         if (!isset($order['shipping'])) {
             $order['shipping'] = $rate['rate'];
         }
         if (!empty($order['params']['shipping'])) {
             foreach ($order['params']['shipping'] as $k => $v) {
                 $order['params']['shipping_params_' . $k] = $v;
             }
             unset($order['params']['shipping']);
         }
     } else {
         $order['shipping'] = 0;
     }
     if (isset($checkout_data['payment'])) {
         $order['params']['payment_id'] = $checkout_data['payment'];
         $plugin_model = new shopPluginModel();
         $plugin_info = $plugin_model->getById($checkout_data['payment']);
         $order['params']['payment_name'] = $plugin_info['name'];
         $order['params']['payment_plugin'] = $plugin_info['plugin'];
         if (!empty($order['params']['payment'])) {
             foreach ($order['params']['payment'] as $k => $v) {
                 $order['params']['payment_params_' . $k] = $v;
             }
             unset($order['params']['payment']);
         }
     }
     if ($skock_id = waRequest::post('stock_id')) {
         $order['params']['stock_id'] = $skock_id;
     }
     $routing_url = wa()->getRouting()->getRootUrl();
     $order['params']['storefront'] = wa()->getConfig()->getDomain() . ($routing_url ? '/' . $routing_url : '');
     if ($ref = waRequest::cookie('referer')) {
         $order['params']['referer'] = $ref;
         $ref_parts = @parse_url($ref);
         $order['params']['referer_host'] = $ref_parts['host'];
         // try get search keywords
         if (!empty($ref_parts['query'])) {
             $search_engines = array('text' => 'yandex\\.|rambler\\.', 'q' => 'bing\\.com|mail\\.|google\\.', 's' => 'nigma\\.ru', 'p' => 'yahoo\\.com');
             $q_var = false;
             foreach ($search_engines as $q => $pattern) {
                 if (preg_match('/(' . $pattern . ')/si', $ref_parts['host'])) {
                     $q_var = $q;
                     break;
                 }
             }
             // default query var name
             if (!$q_var) {
                 $q_var = 'q';
             }
             parse_str($ref_parts['query'], $query);
             if (!empty($query[$q_var])) {
                 $order['params']['keyword'] = $query[$q_var];
             }
         }
     }
     if ($utm = waRequest::cookie('utm')) {
         $utm = json_decode($utm, true);
         if ($utm && is_array($utm)) {
             foreach ($utm as $k => $v) {
                 $order['params']['utm_' . $k] = $v;
             }
         }
     }
     if (($landing = waRequest::cookie('landing')) && ($landing = @parse_url($landing))) {
         if (!empty($landing['query'])) {
             @parse_str($landing['query'], $arr);
             if (!empty($arr['gclid']) && !empty($order['params']['referer_host']) && strpos($order['params']['referer_host'], 'google') !== false) {
                 $order['params']['referer_host'] .= ' (cpc)';
                 $order['params']['cpc'] = 1;
             } else {
                 if (!empty($arr['_openstat']) && !empty($order['params']['referer_host']) && strpos($order['params']['referer_host'], 'yandex') !== false) {
                     $order['params']['referer_host'] .= ' (cpc)';
                     $order['params']['openstat'] = $arr['_openstat'];
                     $order['params']['cpc'] = 1;
                 }
             }
         }
         $order['params']['landing'] = $landing['path'];
     }
     // A/B tests
     /*
             $abtest_variants_model = new shopAbtestVariantsModel();
             foreach (waRequest::cookie() as $k => $v) {
                 if (substr($k, 0, 5) == 'waabt') {
                     $variant_id = $v;
                     $abtest_id = substr($k, 5);
                     if (wa_is_int($abtest_id) && wa_is_int($variant_id)) {
                         $row = $abtest_variants_model->getById($variant_id);
                         if ($row && $row['abtest_id'] == $abtest_id) {
                             $order['params']['abt' . $abtest_id] = $variant_id;
                         }
                     }
                 }
             }
     */
     $order['params']['ip'] = waRequest::getIp();
     $order['params']['user_agent'] = waRequest::getUserAgent();
     foreach (array('shipping', 'billing') as $ext) {
         $address = $contact->getFirst('address.' . $ext);
         if ($address) {
             foreach ($address['data'] as $k => $v) {
                 $order['params'][$ext . '_address.' . $k] = $v;
             }
         }
     }
     if (isset($checkout_data['comment'])) {
         $order['comment'] = $checkout_data['comment'];
     }
     $workflow = new shopWorkflow();
     if ($order_id = $workflow->getActionById('create')->run($order)) {
         $step_number = shopOnestepCheckout::getStepNumber();
         $checkout_flow = new shopCheckoutFlowModel();
         $checkout_flow->add(array('step' => $step_number));
         $cart->clear();
         wa()->getStorage()->remove('shop/checkout');
         wa()->getStorage()->set('shop/order_id', $order_id);
         return $order_id;
     } else {
         return false;
     }
 }
 protected function createOrder()
 {
     $checkout_data = $this->getStorage()->get('shop/checkout');
     $contact = $this->getUser()->isAuth() ? $this->getUser() : $checkout_data['contact'];
     $cart = new shopCart();
     $items = $cart->items(false);
     // remove id from item
     foreach ($items as &$item) {
         unset($item['id']);
         unset($item['parent_id']);
     }
     unset($item);
     $order = array('contact' => $contact, 'items' => $items, 'total' => $cart->total(false), 'params' => isset($checkout_data['params']) ? $checkout_data['params'] : array());
     $order['discount'] = shopDiscounts::apply($order);
     if (isset($checkout_data['shipping'])) {
         $order['params']['shipping_id'] = $checkout_data['shipping']['id'];
         $order['params']['shipping_rate_id'] = $checkout_data['shipping']['rate_id'];
         $shipping_step = new shopCheckoutShipping();
         $rate = $shipping_step->getRate($order['params']['shipping_id'], $order['params']['shipping_rate_id']);
         $order['params']['shipping_plugin'] = $rate['plugin'];
         $order['params']['shipping_name'] = $rate['name'];
         if (isset($rate['est_delivery'])) {
             $order['params']['shipping_est_delivery'] = $rate['est_delivery'];
         }
         if (!isset($order['shipping'])) {
             $order['shipping'] = $rate['rate'];
         }
         if (!empty($order['params']['shipping'])) {
             foreach ($order['params']['shipping'] as $k => $v) {
                 $order['params']['shipping_params_' . $k] = $v;
             }
             unset($order['params']['shipping']);
         }
     } else {
         $order['shipping'] = 0;
     }
     if (isset($checkout_data['payment'])) {
         $order['params']['payment_id'] = $checkout_data['payment'];
         $plugin_model = new shopPluginModel();
         $plugin_info = $plugin_model->getById($checkout_data['payment']);
         $order['params']['payment_name'] = $plugin_info['name'];
         $order['params']['payment_plugin'] = $plugin_info['plugin'];
         if (!empty($order['params']['payment'])) {
             foreach ($order['params']['payment'] as $k => $v) {
                 $order['params']['payment_params_' . $k] = $v;
             }
             unset($order['params']['payment']);
         }
     }
     if ($skock_id = waRequest::post('stock_id')) {
         $order['params']['stock_id'] = $skock_id;
     }
     $routing_url = wa()->getRouting()->getRootUrl();
     $order['params']['storefront'] = wa()->getConfig()->getDomain() . ($routing_url ? '/' . $routing_url : '');
     if (($ref = wa()->getStorage()->get('shop/referer')) || ($ref = waRequest::cookie('referer'))) {
         $order['params']['referer'] = $ref;
         $ref_parts = parse_url($ref);
         $order['params']['referer_host'] = $ref_parts['host'];
         // try get search keywords
         if (!empty($ref_parts['query'])) {
             $search_engines = array('text' => 'yandex\\.|rambler\\.', 'q' => 'bing\\.com|mail\\.|google\\.', 's' => 'nigma\\.ru', 'p' => 'yahoo\\.com');
             $q_var = false;
             foreach ($search_engines as $q => $pattern) {
                 if (preg_match('/(' . $pattern . ')/si', $ref_parts['host'])) {
                     $q_var = $q;
                     break;
                 }
             }
             // default query var name
             if (!$q_var) {
                 $q_var = 'q';
             }
             parse_str($ref_parts['query'], $query);
             if (!empty($query[$q_var])) {
                 $order['params']['keyword'] = $query[$q_var];
             }
         }
     }
     if ($utm = waRequest::cookie('utm')) {
         $utm = json_decode($utm, true);
         if ($utm && is_array($utm)) {
             foreach ($utm as $k => $v) {
                 $order['params']['utm_' . $k] = $v;
             }
         }
     }
     $order['params']['ip'] = waRequest::getIp();
     $order['params']['user_agent'] = waRequest::getUserAgent();
     foreach (array('shipping', 'billing') as $ext) {
         $address = $contact->getFirst('address.' . $ext);
         if ($address) {
             foreach ($address['data'] as $k => $v) {
                 $order['params'][$ext . '_address.' . $k] = $v;
             }
         }
     }
     if (isset($checkout_data['comment'])) {
         $order['comment'] = $checkout_data['comment'];
     }
     $workflow = new shopWorkflow();
     if ($order_id = $workflow->getActionById('create')->run($order)) {
         $step_number = shopCheckout::getStepNumber();
         $checkout_flow = new shopCheckoutFlowModel();
         $checkout_flow->add(array('step' => $step_number));
         $cart->clear();
         wa()->getStorage()->remove('shop/checkout');
         wa()->getStorage()->set('shop/order_id', $order_id);
         return true;
     }
 }
 public function display()
 {
     $plugin_model = new shopPluginModel();
     if (waRequest::param('shipping_id') && is_array(waRequest::param('shipping_id'))) {
         $methods = $plugin_model->getById(waRequest::param('shipping_id'));
     } else {
         $methods = $plugin_model->listPlugins('shipping');
     }
     $address = $this->getAddress();
     $empty = true;
     foreach ($address as $v) {
         if ($v) {
             $empty = false;
             break;
         }
     }
     if ($empty) {
         $address = array();
     }
     $items = $this->getItems();
     $cart = new shopCart();
     $total = $cart->total();
     $settings = wa('shop')->getConfig()->getCheckoutSettings();
     $address_form = !isset($settings['contactinfo']) || !isset($settings['contactinfo']['fields']['address.shipping']);
     if (!isset($settings['contactinfo']) || !isset($settings['contactinfo']['fields']['address.shipping']) && !isset($settings['contactinfo']['fields']['address'])) {
         $settings = wa('shop')->getConfig()->getCheckoutSettings(true);
     }
     if (!$address) {
         $shipping_address = array();
         $address_form = true;
         if ($settings['contactinfo']['fields']['address']) {
             foreach ($settings['contactinfo']['fields']['address']['fields'] as $k => $f) {
                 if (!empty($f['value'])) {
                     $shipping_address[$k] = $f['value'];
                 }
             }
         }
     } else {
         $shipping_address = $address;
     }
     if (waRequest::method() == 'post') {
         $shipping_id = waRequest::post('shipping_id');
         $rate_id = waRequest::post('rate_id');
         $selected_shipping = array('id' => $shipping_id, 'rate_id' => !empty($rate_id[$shipping_id]) ? $rate_id[$shipping_id] : '');
     } else {
         $selected_shipping = $this->getSessionData('shipping', array());
     }
     $dimension = shopDimension::getInstance()->getDimension('weight');
     $currencies = wa('shop')->getConfig()->getCurrencies();
     foreach ($methods as $method_id => $m) {
         $plugin = shopShipping::getPlugin($m['plugin'], $m['id']);
         $plugin_info = $plugin->info($m['plugin']);
         $m['icon'] = $plugin_info['icon'];
         $m['img'] = $plugin_info['img'];
         $m['currency'] = $plugin->allowedCurrency();
         $weight_unit = $plugin->allowedWeightUnit();
         if ($weight_unit != $dimension['base_unit']) {
             $shipping_items = array();
             foreach ($items as $item_id => $item) {
                 if ($item['weight']) {
                     $item['weight'] = $item['weight'] / $dimension['units'][$weight_unit]['multiplier'];
                 }
                 $shipping_items[$item_id] = $item;
             }
         } else {
             $shipping_items = $items;
         }
         $m['external'] = $selected_shipping && $selected_shipping['id'] == $m['id'] ? 0 : $plugin->getProperties('external');
         if ($m['external']) {
             $m['rates'] = array();
         } else {
             $m['rates'] = $plugin->getRates($shipping_items, $shipping_address, array('total_price' => $total));
         }
         if (is_array($m['rates'])) {
             if (!isset($currencies[$m['currency']])) {
                 $m['rate'] = 0;
                 $m['error'] = sprintf(_w('Shipping rate was not calculated because required currency %s is not defined in your store settings.'), $m['currency']);
                 $methods[$method_id] = $m;
                 continue;
             }
             foreach ($m['rates'] as &$r) {
                 if (is_array($r['rate'])) {
                     $r['rate'] = max($r['rate']);
                 }
             }
             if ($m['rates']) {
                 if (!empty($selected_shipping['rate_id']) && isset($m['rates'][$selected_shipping['rate_id']])) {
                     $rate = $m['rates'][$selected_shipping['rate_id']];
                 } else {
                     $rate = reset($m['rates']);
                 }
                 $m['rate'] = $rate['rate'];
                 $m['est_delivery'] = isset($rate['est_delivery']) ? $rate['est_delivery'] : '';
                 if (!empty($rate['comment'])) {
                     $m['comment'] = $rate['comment'];
                 }
             } else {
                 $m['rates'] = array();
                 $m['rate'] = null;
             }
         } elseif (is_string($m['rates'])) {
             if ($address) {
                 $m['error'] = $m['rates'];
             } else {
                 $m['rates'] = array();
                 $m['rate'] = null;
             }
         } else {
             unset($methods[$method_id]);
             continue;
         }
         $custom_fields = $this->getCustomFields($method_id, $plugin);
         $custom_html = '';
         foreach ($custom_fields as $c) {
             $custom_html .= '<div class="wa-field">' . $c . '</div>';
         }
         if ($custom_html) {
             $m['custom_html'] = $custom_html;
         }
         $f = $this->getAddressForm($m['id'], $plugin, $settings, $address, $address_form);
         if ($f) {
             $m['form'] = $f;
             $m['form']->setValue($this->getContact());
         }
         $methods[$method_id] = $m;
     }
     $view = wa()->getView();
     $view->assign('checkout_shipping_methods', $methods);
     $default_method = '';
     foreach ($methods as $m) {
         if (empty($m['error'])) {
             $default_method = $m['id'];
             break;
         }
     }
     $view->assign('shipping', $selected_shipping ? $selected_shipping : array('id' => $default_method, 'rate_id' => ''));
     $checkout_flow = new shopCheckoutFlowModel();
     $step_number = shopOnestepCheckout::getStepNumber('shipping');
     // IF no errors
     $checkout_flow->add(array('step' => $step_number));
     // ELSE
     //        $checkout_flow->add(array(
     //            'step' => $step_number,
     //            'description' => ERROR MESSAGE HERE
     //        ));
 }
 public function execute()
 {
     $this->getResponse()->addHeader("Cache-Control", "no-store, no-cache, must-revalidate");
     $this->getResponse()->addHeader("Expires", date("r"));
     if (waRequest::method() == 'post') {
         $data = wa()->getStorage()->get('shop/checkout', array());
         if ($coupon_code = waRequest::post('coupon_code')) {
             $data['coupon_code'] = $coupon_code;
         } elseif (isset($data['coupon_code'])) {
             unset($data['coupon_code']);
         }
         if (($use = waRequest::post('use_affiliate')) !== null) {
             if ($use) {
                 $data['use_affiliate'] = 1;
             } elseif (isset($data['use_affiliate'])) {
                 unset($data['use_affiliate']);
             }
         }
         if ($coupon_code || $use) {
             wa()->getStorage()->set('shop/checkout', $data);
             wa()->getStorage()->remove('shop/cart');
         }
     }
     $cart_model = new shopCartItemsModel();
     $cart = new shopCart();
     $code = $cart->getCode();
     $errors = array();
     if (waRequest::post('checkout')) {
         $saved_quantity = $cart_model->select('id,quantity')->where("type='product' AND code = s:code", array('code' => $code))->fetchAll('id');
         $quantity = waRequest::post('quantity');
         foreach ($quantity as $id => $q) {
             if ($q != $saved_quantity[$id]) {
                 $cart->setQuantity($id, $q);
             }
         }
         $not_available_items = $cart_model->getNotAvailableProducts($code, !wa()->getSetting('ignore_stock_count'));
         foreach ($not_available_items as $row) {
             if ($row['sku_name']) {
                 $row['name'] .= ' (' . $row['sku_name'] . ')';
             }
             if ($row['available']) {
                 $errors[$row['id']] = sprintf(_w('Only %d pcs of %s are available, and you already have all of them in your shopping cart.'), $row['count'], $row['name']);
             } else {
                 $errors[$row['id']] = _w('Oops! %s is not available for purchase at the moment. Please remove this product from your shopping cart to proceed.');
             }
         }
         if (!$errors) {
             $this->redirect(wa()->getRouteUrl('/frontend/checkout'));
         }
     }
     $this->setThemeTemplate('cart.html');
     $items = $cart_model->where('code= ?', $code)->order('parent_id')->fetchAll('id');
     $product_ids = $sku_ids = $service_ids = $type_ids = array();
     foreach ($items as $item) {
         $product_ids[] = $item['product_id'];
         $sku_ids[] = $item['sku_id'];
     }
     $product_ids = array_unique($product_ids);
     $sku_ids = array_unique($sku_ids);
     $product_model = new shopProductModel();
     if (waRequest::param('url_type') == 2) {
         $products = $product_model->getWithCategoryUrl($product_ids);
     } else {
         $products = $product_model->getById($product_ids);
     }
     $sku_model = new shopProductSkusModel();
     $skus = $sku_model->getByField('id', $sku_ids, 'id');
     $image_model = new shopProductImagesModel();
     $delete_items = array();
     foreach ($items as $item_id => &$item) {
         if (!isset($skus[$item['sku_id']])) {
             unset($items[$item_id]);
             $delete_items[] = $item_id;
             continue;
         }
         if ($item['type'] == 'product') {
             $item['product'] = $products[$item['product_id']];
             $sku = $skus[$item['sku_id']];
             if ($sku['image_id'] && $sku['image_id'] != $item['product']['image_id']) {
                 $img = $image_model->getById($sku['image_id']);
                 if ($img) {
                     $item['product']['image_id'] = $sku['image_id'];
                     $item['product']['ext'] = $img['ext'];
                 }
             }
             $item['sku_name'] = $sku['name'];
             $item['sku_code'] = $sku['sku'];
             $item['price'] = $sku['price'];
             $item['compare_price'] = $sku['compare_price'];
             $item['currency'] = $item['product']['currency'];
             $type_ids[] = $item['product']['type_id'];
             if (isset($errors[$item_id])) {
                 $item['error'] = $errors[$item_id];
                 if (strpos($item['error'], '%s') !== false) {
                     $item['error'] = sprintf($item['error'], $item['product']['name'] . ($item['sku_name'] ? ' (' . $item['sku_name'] . ')' : ''));
                 }
             }
         }
     }
     unset($item);
     if ($delete_items) {
         $cart_model->deleteByField(array('code' => $code, 'id' => $delete_items));
     }
     $type_ids = array_unique($type_ids);
     // get available services for all types of products
     $type_services_model = new shopTypeServicesModel();
     $rows = $type_services_model->getByField('type_id', $type_ids, true);
     $type_services = array();
     foreach ($rows as $row) {
         $service_ids[] = $row['service_id'];
         $type_services[$row['type_id']][$row['service_id']] = true;
     }
     // get services for all products
     $product_services_model = new shopProductServicesModel();
     $rows = $product_services_model->getByProducts($product_ids);
     $product_services = $sku_services = array();
     foreach ($rows as $row) {
         if ($row['sku_id'] && !in_array($row['sku_id'], $sku_ids)) {
             continue;
         }
         $service_ids[] = $row['service_id'];
         if (!$row['sku_id']) {
             $product_services[$row['product_id']][$row['service_id']]['variants'][$row['service_variant_id']] = $row;
         }
         if ($row['sku_id']) {
             $sku_services[$row['sku_id']][$row['service_id']]['variants'][$row['service_variant_id']] = $row;
         }
     }
     $service_ids = array_unique($service_ids);
     $service_model = new shopServiceModel();
     $variant_model = new shopServiceVariantsModel();
     $services = $service_model->getByField('id', $service_ids, 'id');
     foreach ($services as &$s) {
         unset($s['id']);
     }
     unset($s);
     $rows = $variant_model->getByField('service_id', $service_ids, true);
     foreach ($rows as $row) {
         $services[$row['service_id']]['variants'][$row['id']] = $row;
         unset($services[$row['service_id']]['variants'][$row['id']]['id']);
     }
     foreach ($items as $item_id => $item) {
         if ($item['type'] == 'product') {
             $p = $item['product'];
             $item_services = array();
             // services from type settings
             if (isset($type_services[$p['type_id']])) {
                 foreach ($type_services[$p['type_id']] as $service_id => &$s) {
                     $item_services[$service_id] = $services[$service_id];
                 }
             }
             // services from product settings
             if (isset($product_services[$item['product_id']])) {
                 foreach ($product_services[$item['product_id']] as $service_id => $s) {
                     if (!isset($s['status']) || $s['status']) {
                         if (!isset($item_services[$service_id])) {
                             $item_services[$service_id] = $services[$service_id];
                         }
                         // update variants
                         foreach ($s['variants'] as $variant_id => $v) {
                             if ($v['status']) {
                                 if ($v['price'] !== null) {
                                     $item_services[$service_id]['variants'][$variant_id]['price'] = $v['price'];
                                 }
                             } else {
                                 unset($item_services[$service_id]['variants'][$variant_id]);
                             }
                         }
                     } elseif (isset($item_services[$service_id])) {
                         // remove disabled service
                         unset($item_services[$service_id]);
                     }
                 }
             }
             // services from sku settings
             if (isset($sku_services[$item['sku_id']])) {
                 foreach ($sku_services[$item['sku_id']] as $service_id => $s) {
                     if (!isset($s['status']) || $s['status']) {
                         // update variants
                         foreach ($s['variants'] as $variant_id => $v) {
                             if ($v['status']) {
                                 if ($v['price'] !== null) {
                                     $item_services[$service_id]['variants'][$variant_id]['price'] = $v['price'];
                                 }
                             } else {
                                 unset($item_services[$service_id]['variants'][$variant_id]);
                             }
                         }
                     } elseif (isset($item_services[$service_id])) {
                         // remove disabled service
                         unset($item_services[$service_id]);
                     }
                 }
             }
             foreach ($item_services as $s_id => &$s) {
                 if (!$s['variants']) {
                     unset($item_services[$s_id]);
                     continue;
                 }
                 if ($s['currency'] == '%') {
                     foreach ($s['variants'] as $v_id => $v) {
                         $s['variants'][$v_id]['price'] = $v['price'] * $item['price'] / 100;
                     }
                     $s['currency'] = $item['currency'];
                 }
                 if (count($s['variants']) == 1) {
                     $v = reset($s['variants']);
                     $s['price'] = $v['price'];
                     unset($s['variants']);
                 }
             }
             unset($s);
             uasort($item_services, array('shopServiceModel', 'sortServices'));
             $items[$item_id]['services'] = $item_services;
         } else {
             $items[$item['parent_id']]['services'][$item['service_id']]['id'] = $item['id'];
             if (isset($item['service_variant_id'])) {
                 $items[$item['parent_id']]['services'][$item['service_id']]['variant_id'] = $item['service_variant_id'];
             }
             unset($items[$item_id]);
         }
     }
     foreach ($items as $item_id => $item) {
         $price = shop_currency($item['price'] * $item['quantity'], $item['currency'], null, false);
         if (isset($item['services'])) {
             foreach ($item['services'] as $s) {
                 if (!empty($s['id'])) {
                     if (isset($s['variants'])) {
                         $price += shop_currency($s['variants'][$s['variant_id']]['price'] * $item['quantity'], $s['currency'], null, false);
                     } else {
                         $price += shop_currency($s['price'] * $item['quantity'], $s['currency'], null, false);
                     }
                 }
             }
         }
         $items[$item_id]['full_price'] = $price;
     }
     $total = $cart->total(false);
     $order = array('total' => $total, 'items' => $items);
     $order['discount'] = $discount = shopDiscounts::calculate($order);
     $order['total'] = $total = $total - $order['discount'];
     $data = wa()->getStorage()->get('shop/checkout');
     $this->view->assign('cart', array('items' => $items, 'total' => $total, 'count' => $cart->count()));
     $this->view->assign('coupon_code', isset($data['coupon_code']) ? $data['coupon_code'] : '');
     if (shopAffiliate::isEnabled()) {
         $affiliate_bonus = 0;
         if ($this->getUser()->isAuth()) {
             $customer_model = new shopCustomerModel();
             $customer = $customer_model->getById($this->getUser()->getId());
             $affiliate_bonus = $customer ? round($customer['affiliate_bonus'], 2) : 0;
         }
         $this->view->assign('affiliate_bonus', $affiliate_bonus);
         $use = !empty($data['use_affiliate']);
         $this->view->assign('use_affiliate', $use);
         if ($use) {
             $discount -= shop_currency(shopAffiliate::convertBonus($order['params']['affiliate_bonus']), $this->getConfig()->getCurrency(true), null, false);
             $this->view->assign('used_affiliate_bonus', $order['params']['affiliate_bonus']);
         }
         $order['currency'] = $this->getConfig()->getCurrency(false);
         $add_affiliate_bonus = shopAffiliate::calculateBonus($order);
         $this->view->assign('add_affiliate_bonus', round($add_affiliate_bonus, 2));
     }
     $this->view->assign('discount', $discount);
     /**
      * @event frontend_cart
      * @return array[string]string $return[%plugin_id%] html output
      */
     $this->view->assign('frontend_cart', wa()->event('frontend_cart'));
     $this->getResponse()->setTitle(_w('Cart'));
     $checkout_flow = new shopCheckoutFlowModel();
     $checkout_flow->add(array('code' => $code, 'step' => 0, 'description' => null));
 }