public function execute()
 {
     $order_id = waRequest::request('order_id', 0, 'int');
     $id = waRequest::request('id', 0, 'int');
     $to = waRequest::request('to');
     $nm = new shopNotificationModel();
     $n = $nm->getById($id);
     if (!$n) {
         $this->errors = sprintf_wp('%s entry not found', _w('Notification'));
         return;
     }
     $om = new shopOrderModel();
     $o = $om->getById($order_id);
     if (!$o) {
         $this->errors = _w('Order not found');
         return;
     }
     shopHelper::workupOrders($o, true);
     $opm = new shopOrderParamsModel();
     $o['params'] = $opm->get($order_id);
     try {
         $contact = $o['contact_id'] ? new shopCustomer($o['contact_id']) : wa()->getUser();
         $contact->getName();
     } catch (Exception $e) {
         $contact = new shopCustomer(wa()->getUser()->getId());
     }
     $cm = new shopCustomerModel();
     $customer = $cm->getById($contact->getId());
     if (!$customer) {
         $customer = $cm->getEmptyRow();
     }
     $workflow = new shopWorkflow();
     // send notifications
     shopNotifications::sendOne($id, array('order' => $o, 'customer' => $contact, 'status' => $workflow->getStateById($o['state_id'])->getName()), $to);
 }
 public function execute()
 {
     $id = waRequest::get('id');
     $model = new shopNotificationModel();
     $n = $model->getById($id);
     $params_model = new shopNotificationParamsModel();
     $params = $params_model->getParams($id);
     // Orders used as sample data for testing
     $om = new shopOrderModel();
     $test_orders = $om->where("paid_date IS NOT NULL AND state_id <> 'deleted'")->order('id DESC')->limit(10)->fetchAll('id');
     shopHelper::workupOrders($test_orders);
     $im = new shopOrderItemsModel();
     foreach ($im->getByField('order_id', array_keys($test_orders), true) as $i) {
         $test_orders[$i['order_id']]['items'][] = $i;
     }
     foreach ($test_orders as &$o) {
         $o['items'] = ifset($o['items'], array());
         $o['total_formatted'] = waCurrency::format('%{s}', $o['total'], $o['currency']);
     }
     $this->view->assign('n', $n);
     $this->view->assign('params', $params);
     $this->view->assign('transports', self::getTransports());
     $this->view->assign('events', $this->getEvents());
     $this->view->assign('test_orders', $test_orders);
     $this->view->assign('default_email_from', $this->getConfig()->getGeneralSettings('email'));
     $this->view->assign('sms_from', $this->getSmsFrom());
     $this->view->assign('routes', wa()->getRouting()->getByApp('shop'));
 }
 public function getOrders($offset, $limit)
 {
     if ($this->orders === null) {
         $this->orders = $this->collection->getOrders("*,items,contact,params", $offset, $limit);
         $this->extendContacts($this->orders);
         shopHelper::workupOrders($this->orders);
     }
     return $this->orders;
 }
 public function execute()
 {
     $id = waRequest::get('id', null, waRequest::TYPE_INT);
     if ($id) {
         $model = new shopOrderModel();
         if ($model->delete($id)) {
             $this->response = shopHelper::workupOrders($model->getOrder($id), true);
         }
     }
 }
 public function execute()
 {
     if (wa()->getUser()->getRights('shop', 'orders')) {
         $om = new shopOrderModel();
         $orders = $om->order('id DESC')->limit(30)->fetchAll('id');
         shopHelper::workupOrders($orders);
         $this->view->assign('orders', $orders);
     } else {
         $this->view->assign('orders', false);
     }
     wa()->getResponse()->setTitle(_w('Orders'));
     parent::execute();
 }
 private function formatData($data, $type)
 {
     if ($type == 'order') {
         $orders = array();
         foreach ($data as $k => $item) {
             if ($item['autocomplete_item_type'] == 'order') {
                 $orders[] = $item;
                 unset($data[$k]);
             }
         }
         if ($orders) {
             shopHelper::workupOrders($orders);
             $data = array_merge($orders, $data);
         }
         foreach ($data as &$item) {
             if ($item['autocomplete_item_type'] == 'order') {
                 $item['value'] = shopHelper::encodeOrderId($item['id']);
                 $item['label'] = '';
                 if (!empty($item['icon'])) {
                     $item['label'] .= "<i class='{$item['icon']}'></i>";
                 }
                 $item['label'] .= $item['value'] . " " . $item['total_str'];
                 $item['label'] .= ' <span class="hint">' . htmlspecialchars($item['customer_name']) . '</span>';
                 $item = array('id' => $item['id'], 'value' => $item['value'], 'label' => $item['label'], 'autocomplete_item_type' => 'order');
             }
         }
         return $data;
     } else {
         if ($type == 'product') {
             $with_counts = waRequest::get('with_counts', 0, waRequest::TYPE_INT);
             $with_sku_name = waRequest::get('with_sku_name', 0, waRequest::TYPE_INT);
             foreach ($data as &$item) {
                 if (empty($item['label'])) {
                     $item['label'] = htmlspecialchars($item['value']);
                 }
                 if ($with_counts) {
                     $item['label'] .= ' ' . shopHelper::getStockCountIcon($item['count'], null, true);
                 }
                 if ($with_sku_name) {
                     $item['label'] .= ' <span class="hint">' . $item['sku_name'] . '</span>';
                 }
             }
         }
     }
     return $data;
 }
 public function execute()
 {
     $action_id = waRequest::get('id', null, waRequest::TYPE_STRING_TRIM);
     if (!$action_id) {
         throw new waException('No action id given.');
     }
     $chunk_size = 100;
     $offset = (int) waRequest::get('offset');
     $workflow = new shopWorkflow();
     $order_model = new shopOrderModel();
     // collect orders under which has performed actions
     $updated_orders_ids = array();
     $hash = $this->getHash();
     if ($hash === null) {
         return;
     }
     $collection = new shopOrdersCollection($hash);
     $total_count = $collection->count();
     $orders = $collection->getOrders('*', $offset, $chunk_size);
     foreach ($orders as $order) {
         $actions = $workflow->getStateById($order['state_id'])->getActions();
         if (isset($actions[$action_id])) {
             $actions[$action_id]->run($order['id']);
             $updated_orders_ids[] = $order['id'];
         }
     }
     if (!$updated_orders_ids) {
         return;
     }
     $this->response = array('offset' => $offset + count($orders), 'total_count' => $total_count);
     // sidebar counters
     if ($this->response['offset'] >= $this->response['total_count']) {
         $order_model = new shopOrderModel();
         $state_counters = $order_model->getStateCounters();
         $pending_count = (!empty($state_counters['new']) ? $state_counters['new'] : 0) + (!empty($state_counters['processing']) ? $state_counters['processing'] : 0) + (!empty($state_counters['paid']) ? $state_counters['paid'] : 0);
         $this->response['state_counters'] = $state_counters;
         $this->response['pending_count'] = $pending_count;
     }
     $collection = new shopOrdersCollection('id/' . implode(',', $updated_orders_ids));
     $total_count = $collection->count();
     $orders = $collection->getOrders('*,contact', 0, $total_count);
     // orders for update items in table
     shopHelper::workupOrders($orders);
     $this->response['orders'] = array_values($orders);
 }
 public function execute()
 {
     $id = waRequest::request('id', null, waRequest::TYPE_INT);
     $contact = new waContact($id);
     $contact->getName();
     // Customer orders
     $im = new shopOrderItemsModel();
     $orders_collection = new shopOrdersCollection('search/contact_id=' . $id);
     $orders = $orders_collection->getOrders('*,items,params', 0, 500);
     shopHelper::workupOrders($orders);
     foreach ($orders as &$o) {
         $o['total_formatted'] = waCurrency::format('%{s}', $o['total'], $o['currency']);
         $o['shipping_name'] = ifset($o['params']['shipping_name'], '');
         $o['payment_name'] = ifset($o['params']['payment_name'], '');
     }
     $this->view->assign('orders', $orders);
     $this->view->assign('contact', $contact);
     $this->view->assign('def_cur_tmpl', str_replace('0', '%s', waCurrency::format('%{s}', 0, wa()->getConfig()->getCurrency())));
 }
 public function execute()
 {
     $order_id = waRequest::request('order_id', 0, 'int');
     $followup_id = waRequest::request('followup_id', 0, 'int');
     $email = waRequest::request('email');
     $fm = new shopFollowupModel();
     $f = $fm->getById($followup_id);
     if (!$f) {
         $this->errors = sprintf_wp('%s entry not found', _w('Follow-up'));
         return;
     }
     $om = new shopOrderModel();
     $o = $om->getById($order_id);
     if (!$o) {
         $this->errors = _w('Order not found');
         return;
     }
     shopHelper::workupOrders($o, true);
     $opm = new shopOrderParamsModel();
     $o['params'] = $opm->get($order_id);
     try {
         $contact = $o['contact_id'] ? new shopCustomer($o['contact_id']) : wa()->getUser();
         $contact->getName();
     } catch (Exception $e) {
         $contact = new shopCustomer(wa()->getUser()->getId());
     }
     $cm = new shopCustomerModel();
     $customer = $cm->getById($contact->getId());
     if (!$customer) {
         $customer = $cm->getEmptyRow();
     }
     $to = array($email => $contact->getName());
     if (!shopFollowupCli::sendOne($f, $o, $customer, $contact, $to)) {
         $this->errors = "Unable to send follow-up #{$f['id']} for order #{$o['id']}: waMessage->send() returned FALSE.";
         return;
     }
     $this->response = 'ok';
 }
 public function execute()
 {
     $id = waRequest::request('id', 0, 'int');
     $coupm = new shopCouponModel();
     $coupon = $coupm->getById($id);
     if ($coupon) {
         $coupon['value'] = (double) $coupon['value'];
         if (waRequest::request('delete')) {
             $coupm->delete($id);
             exit;
         }
     } else {
         if ($id) {
             throw new waException('Coupon not found.', 404);
         } else {
             // show form to create new coupon
             $coupon = $coupm->getEmptyRow();
             $coupon['code'] = self::generateCode();
         }
     }
     //
     // Process POST data
     //
     $duplicate_code_error = null;
     if (waRequest::post()) {
         $post_coupon = waRequest::post('coupon');
         if (is_array($post_coupon)) {
             $post_coupon = array_intersect_key($post_coupon, $coupon) + array('code' => '', 'type' => '%');
             if (empty($post_coupon['limit'])) {
                 $post_coupon['limit'] = null;
             }
             if (!empty($post_coupon['value'])) {
                 $post_coupon['value'] = (double) str_replace(',', '.', $post_coupon['value']);
             }
             if (empty($post_coupon['code'])) {
                 throw new waException('Bad parameters', 500);
                 // rely on JS validation
             }
             if (!empty($post_coupon['expire_datetime']) && strlen($post_coupon['expire_datetime']) == 10) {
                 $post_coupon['expire_datetime'] .= ' 23:59:59';
             }
             if ($post_coupon['type'] == '%') {
                 $post_coupon['value'] = min(max($post_coupon['value'], 0), 100);
             }
             if ($id) {
                 $coupm->updateById($id, $post_coupon);
                 echo '<script>window.location.hash = "#/coupons/' . $id . '";$.orders.dispatch();</script>';
                 exit;
             } else {
                 $post_coupon['create_contact_id'] = wa()->getUser()->getId();
                 $post_coupon['create_datetime'] = date('Y-m-d H:i:s');
                 try {
                     $id = $coupm->insert($post_coupon);
                     echo '<script>' . 'var counter = $("#s-coupons .count");' . 'var cnt = parseInt(counter.text(), 10) || 0;' . 'counter.text(cnt + 1);' . 'window.location.hash = "#/coupons/' . $id . '";' . '</script>';
                     exit;
                 } catch (waDbException $e) {
                     // Duplicate code. Show error in form.
                     $coupon = $post_coupon + $coupon;
                     $duplicate_code_error = true;
                 }
             }
         }
     }
     // Coupon types
     $curm = new shopCurrencyModel();
     $currencies = $curm->getAll('code');
     $types = self::getTypes($currencies);
     // Orders this coupon was used for
     $orders = array();
     $overall_discount = 0;
     $overall_discount_formatted = '';
     if ($coupon['id']) {
         $om = new shopOrderModel();
         $cm = new shopCurrencyModel();
         $orders = $om->getByCoupon($coupon['id']);
         shopHelper::workupOrders($orders);
         foreach ($orders as &$o) {
             $discount = ifset($o['params']['coupon_discount'], 0);
             $o['coupon_discount_formatted'] = waCurrency::format('%{s}', $discount, $o['currency']);
             if ($discount) {
                 $overall_discount += $cm->convert($discount, $o['currency'], $cm->getPrimaryCurrency());
                 $o['coupon_discount_percent'] = round($discount * 100.0 / ($discount + $o['total']), 1);
             } else {
                 $o['coupon_discount_percent'] = 0;
             }
         }
         unset($o);
         $overall_discount_formatted = waCurrency::format('%{s}', $overall_discount, $cm->getPrimaryCurrency());
     }
     $this->view->assign('types', $types);
     $this->view->assign('orders', $orders);
     $this->view->assign('coupon', $coupon);
     $this->view->assign('duplicate_code_error', $duplicate_code_error);
     $this->view->assign('overall_discount', $overall_discount);
     $this->view->assign('overall_discount_formatted', $overall_discount_formatted);
     $this->view->assign('formatted_value', shopCouponsAction::formatValue($coupon, $currencies));
     $this->view->assign('is_enabled', shopCouponsAction::isEnabled($coupon));
 }
Exemple #11
0
 private function _getOrder($id)
 {
     $order = $this->getModel()->getOrder($id);
     if (!$order) {
         return false;
     }
     $workflow = new shopWorkflow();
     $order['state'] = $workflow->getStateById($order['state_id']);
     $order = shopHelper::workupOrders($order, true);
     $sku_ids = array();
     $stock_ids = array();
     foreach ($order['items'] as $item) {
         if ($item['stock_id']) {
             $stock_ids[] = $item['stock_id'];
         }
         if ($item['sku_id']) {
             $sku_ids[] = $item['sku_id'];
         }
     }
     $sku_ids = array_unique($sku_ids);
     $stock_ids = array_unique($stock_ids);
     // extend items by stocks
     $stocks = $this->getStocks($stock_ids);
     foreach ($order['items'] as &$item) {
         if (!empty($stocks[$item['stock_id']])) {
             $item['stock'] = $stocks[$item['stock_id']];
         }
     }
     unset($item);
     $skus = $this->getSkus($sku_ids);
     $sku_stocks = $this->getSkuStocks($sku_ids);
     foreach ($order['items'] as &$item) {
         // product and existing sku
         if (isset($skus[$item['sku_id']])) {
             $s = $skus[$item['sku_id']];
             // for that counts that lower than low_count-thresholds show icon
             if ($s['count'] !== null) {
                 if (isset($item['stock'])) {
                     if (isset($sku_stocks[$s['id']][$item['stock']['id']])) {
                         $count = $sku_stocks[$s['id']][$item['stock']['id']]['count'];
                         if ($count <= $item['stock']['low_count']) {
                             $item['stock_icon'] = shopHelper::getStockCountIcon($count, $item['stock']['id'], true);
                         }
                     }
                 } else {
                     if ($s['count'] <= shopStockModel::LOW_DEFAULT) {
                         $item['stock_icon'] = shopHelper::getStockCountIcon($s['count'], null, true);
                     }
                 }
             }
         }
     }
     unset($item);
     return $order;
 }
 public function execute()
 {
     $id = waRequest::request('id', 0, 'int');
     if (!$id || !wa()->getUser()->getRights('shop', 'orders')) {
         $this->redirect(wa()->getAppUrl());
     }
     // Order
     $om = new shopOrderModel();
     $order = $om->getOrder($id);
     shopHelper::workupOrders($order, true);
     $order['tax'] = (double) $order['tax'];
     $order['discount'] = (double) $order['discount'];
     // Order params
     $opm = new shopOrderParamsModel();
     $order['params'] = $opm->get($order['id']);
     // Order subtotal
     $order_subtotal = 0;
     foreach ($order['items'] as $i) {
         $order_subtotal += $i['price'] * $i['quantity'];
     }
     // Format addresses
     $settings = wa('shop')->getConfig()->getCheckoutSettings();
     $form_fields = ifset($settings['contactinfo']['fields'], array());
     $formatter = new waContactAddressSeveralLinesFormatter();
     $shipping_address = shopHelper::getOrderAddress($order['params'], 'shipping');
     $shipping_address = $formatter->format(array('data' => $shipping_address));
     $shipping_address = $shipping_address['value'];
     if (isset($form_fields['address.billing'])) {
         $billing_address = shopHelper::getOrderAddress($order['params'], 'billing');
         $billing_address = $formatter->format(array('data' => $billing_address));
         $billing_address = $billing_address['value'];
         if ($billing_address === $shipping_address) {
             $billing_address = null;
         }
     } else {
         $billing_address = null;
     }
     // Order history
     $log_model = new shopOrderLogModel();
     $log = $log_model->getLog($order['id']);
     // Customer
     $contact = $customer = self::getCustomer($order);
     $top = array();
     foreach (array('email', 'phone') as $f) {
         if ($v = $contact->get($f, 'top,html')) {
             $top[] = array('id' => $f, 'name' => waContactFields::get($f)->getName(), 'value' => is_array($v) ? implode(', ', $v) : $v);
         }
     }
     // Workflow stuff: actions and state
     $workflow = new shopWorkflow();
     $workflow_state = $workflow->getStateById($order['state_id']);
     $workflow_buttons = array();
     foreach ($workflow_state->getActions() as $a_id => $action) {
         if ($a_id === 'edit' || $a_id === 'delete') {
             continue;
         }
         $workflow_buttons[] = $action->getButton();
     }
     $this->view->assign('top', $top);
     $this->view->assign('log', $log);
     $this->view->assign('order', $order);
     $this->view->assign('uniqid', uniqid('f'));
     $this->view->assign('customer', $customer);
     $this->view->assign('workflow_state', $workflow_state);
     $this->view->assign('workflow_buttons', $workflow_buttons);
     $this->view->assign('shipping_address', $shipping_address);
     $this->view->assign('billing_address', $billing_address);
     $this->view->assign('order_subtotal', $order_subtotal);
     $this->view->assign('currency', ifempty($order['currency'], wa()->getConfig()->getCurrency()));
     wa()->getResponse()->setTitle(_w('Order') . ' ' . $order['id_str']);
     parent::execute();
 }
 public function execute()
 {
     $id = waRequest::request('id', null, waRequest::TYPE_INT);
     $scm = new shopCustomerModel();
     $customer = $scm->getById($id);
     try {
         $contact = new waContact($id);
         $contact->getName();
     } catch (waException $e) {
         // !!! What to do when shop_customer exists, but no wa_contact found?
         throw $e;
     }
     $ccsm = new waContactCategoriesModel();
     $contact_categories = $ccsm->getContactCategories($id);
     $contacts_url = wa()->getAppUrl('contacts');
     // Info above tabs
     $top = array();
     foreach (array('email', 'phone', 'im') as $f) {
         if ($v = $contact->get($f, 'top,html')) {
             $top[] = array('id' => $f, 'name' => waContactFields::get($f)->getName(), 'value' => is_array($v) ? implode(', ', $v) : $v);
         }
     }
     // Get photo
     $photo = $contact->get('photo');
     $config = $this->getConfig();
     $use_gravatar = $config->getGeneralSettings('use_gravatar');
     $gravatar_default = $config->getGeneralSettings('gravatar_default');
     if (!$photo && $use_gravatar) {
         $photo = shopHelper::getGravatar($contact->get('email', 'default'), 96, $gravatar_default);
     } else {
         $photo = $contact->getPhoto(96);
     }
     $contact['photo'] = $photo;
     // Customer orders
     $im = new shopOrderItemsModel();
     $orders_collection = new shopOrdersCollection('search/contact_id=' . $id);
     $total_count = $orders_collection->count();
     $orders = $orders_collection->getOrders('*,items,params', 0, $total_count);
     shopHelper::workupOrders($orders);
     foreach ($orders as &$o) {
         $o['total_formatted'] = waCurrency::format('%{s}', $o['total'], $o['currency']);
         $o['shipping_name'] = ifset($o['params']['shipping_name'], '');
         $o['payment_name'] = ifset($o['params']['payment_name'], '');
         // !!! TODO: shipping and payment icons
     }
     // Customer reviews
     $prm = new shopProductReviewsModel();
     $reviews = $prm->getList('*,is_new,product', array('escape' => false, 'where' => array('contact_id' => $id), 'limit' => false));
     // Customer affiliate transactions history
     $atm = new shopAffiliateTransactionModel();
     $affiliate_history = $atm->getByContact($id);
     $this->view->assign('top', $top);
     $this->view->assign('orders', $orders);
     $this->view->assign('reviews', $reviews);
     $this->view->assign('contact', $contact);
     $this->view->assign('customer', $customer);
     $this->view->assign('contacts_url', $contacts_url);
     $this->view->assign('affiliate_history', $affiliate_history);
     $this->view->assign('contact_categories', $contact_categories);
     $this->view->assign('def_cur_tmpl', str_replace('0', '%s', waCurrency::format('%{s}', 0, wa()->getConfig()->getCurrency())));
     $this->view->assign('point_rate', str_replace(',', '.', (double) str_replace(',', '.', wa()->getSetting('affiliate_usage_rate'))));
     $fields = waContactFields::getAll('person');
     if (isset($fields['name'])) {
         unset($fields['name']);
     }
     $this->view->assign('fields', $fields);
     $this->view->assign('orders_default_view', $config->getOption('orders_default_view'));
     /*
      * @event backend_customer
      * @return array[string]array $return[%plugin_id%] array of html output
      * @return array[string][string]string $return[%plugin_id%]['info_section'] html output
      * @return array[string][string]string $return[%plugin_id%]['name_suffix'] html output
      * @return array[string][string]string $return[%plugin_id%]['header'] html output
      * @return array[string][string]string $return[%plugin_id%]['action_link'] html output
      */
     $this->view->assign('backend_customer', wa()->event('backend_customer', $customer));
 }
Exemple #14
0
 public function execute()
 {
     $fm = new shopFollowupModel();
     $opm = new shopOrderParamsModel();
     $asm = new waAppSettingsModel();
     $olm = new shopOrderLogModel();
     $cm = new shopCustomerModel();
     $om = new shopOrderModel();
     $asm->set('shop', 'last_followup_cli', time());
     $view = wa()->getView();
     $empty_customer = $cm->getEmptyRow();
     $general = wa('shop')->getConfig()->getGeneralSettings();
     foreach ($fm->getAllEnabled() as $f) {
         $between_from = date('Y-m-d', strtotime($f['last_cron_time']) - 24 * 3600);
         $between_to = date('Y-m-d 23:59:59', time() - $f['delay'] - 10 * 3600);
         $orders = $om->where('paid_date >= ? AND paid_date < ?', $between_from, $between_to)->fetchAll('id');
         if ($orders) {
             $f_param_key = 'followup_' . $f['id'];
             // Params for all orders with one query
             $params = $opm->get(array_keys($orders));
             // Customer data for all orders with one query
             $cids = array();
             foreach ($orders as $o) {
                 $cids[] = $o['contact_id'];
             }
             $customers = $cm->getById($cids);
             $sent_count = 0;
             foreach ($orders as $o) {
                 try {
                     // Is there a recipient in the first place?
                     if (empty($o['contact_id'])) {
                         if (waSystemConfig::isDebug()) {
                             waLog::log("Unable to send follow-up #{$f['id']} for order #{$o['id']}: no contact_id");
                         }
                         continue;
                     }
                     // Check that this is the first order of this customer
                     if ($f['first_order_only']) {
                         $first_order_id = $om->select('MIN(id)')->where('contact_id=? AND paid_date IS NOT NULL', $o['contact_id'])->fetchField();
                         if ($first_order_id != $o['id']) {
                             if (waSystemConfig::isDebug()) {
                                 waLog::log("Skipping follow-up #{$f['id']} for order #{$o['id']}: not the first order of a customer.");
                             }
                             continue;
                         }
                     }
                     $o['params'] = ifset($params[$o['id']], array());
                     $source = 'backend';
                     if (!empty($o['params']['storefront'])) {
                         $source = rtrim($o['params']['storefront'], '/') . '/*';
                     }
                     if ($f['source'] && $f['source'] != $source) {
                         continue;
                     }
                     // Make sure we have not send follow-up for this order yet
                     if (isset($o['params'][$f_param_key])) {
                         if (waSystemConfig::isDebug()) {
                             waLog::log("Skipping follow-up #{$f['id']} for order #{$o['id']}: already sent before.");
                         }
                         continue;
                     }
                     shopHelper::workupOrders($o, true);
                     // Recipient info
                     $customer = ifset($customers[$o['contact_id']], $empty_customer);
                     $contact = new shopCustomer($o['contact_id']);
                     $email = $contact->get('email', 'default');
                     // this with throw exception if contact does not exist; that's ok
                     if (!$email) {
                         if (waSystemConfig::isDebug()) {
                             waLog::log("Unable to send follow-up #{$f['id']} for order #{$o['id']}: contact has no email");
                         }
                         continue;
                     }
                     $to = array($email => $contact->getName());
                     if (self::sendOne($f, $o, $customer, $contact, $to, $view, $general)) {
                         $sent_count++;
                         // Write to order log
                         $olm->add(array('order_id' => $o['id'], 'contact_id' => null, 'action_id' => '', 'text' => sprintf_wp("Follow-up <strong>%s</strong> (%s) sent to customer.", htmlspecialchars($f['name']), $f['id']), 'before_state_id' => $o['state_id'], 'after_state_id' => $o['state_id']));
                         // Write to order params
                         $opm->insert(array('order_id' => $o['id'], 'name' => $f_param_key, 'value' => date('Y-m-d H:i:s')));
                     } else {
                         waLog::log("Unable to send follow-up #{$f['id']} for order #{$o['id']}: waMessage->send() returned FALSE.");
                     }
                 } catch (Exception $e) {
                     waLog::log("Unable to send follow-up #{$f['id']} for order #{$o['id']}:\n" . $e);
                 }
             }
             /**
              * Notify plugins about sending followup
              * @event followup_send
              * @param array[string]int $params['sent_count'] number of emails successfully sent
              * @param array[string]int $params['id'] followup_id
              * @return void
              */
             $event_params = $f;
             $event_params['sent_count'] = $sent_count;
             wa()->event('followup_send', $event_params);
         }
         $fm->updateById($f['id'], array('last_cron_time' => $between_to));
     }
 }
 public function execute()
 {
     $id = waRequest::request('id');
     $fm = new shopFollowupModel();
     // Save data when POST came
     if ($id && waRequest::post()) {
         if (waRequest::post('delete')) {
             $f = $fm->getById($id);
             if ($f) {
                 /**
                  * @event followup_delete
                  *
                  * Notify plugins about deleted followup
                  *
                  * @param array[string]int $params['id'] followup_id
                  * @return void
                  */
                 wa()->event('followup_delete', $f);
                 $fm->deleteById($id);
             }
             exit;
         }
         $followup = waRequest::post('followup');
         if ($followup && is_array($followup)) {
             $empty_row = $fm->getEmptyRow();
             $followup = array_intersect_key($followup, $empty_row) + $empty_row;
             unset($followup['id']);
             $followup['delay'] = (double) str_replace(',', '.', ifempty($followup['delay'], '3')) * 24 * 3600;
             if (empty($followup['name'])) {
                 $followup['name'] = _w('<no name>');
             }
             $followup['from'] = $followup['from'] ? $followup['from'] : null;
             $followup['source'] = $followup['source'] ? $followup['source'] : null;
             if ($followup['from'] === 'other') {
                 $followup['from'] = waRequest::post('from');
             }
             if ($id && $id !== 'new') {
                 unset($followup['last_cron_time']);
                 $fm->updateById($id, $followup);
                 $just_created = false;
             } else {
                 $followup['last_cron_time'] = date('Y-m-d H:i:s');
                 $id = $fm->insert($followup);
                 $just_created = true;
             }
             $f = $fm->getById($id);
             if ($f) {
                 $f['just_created'] = $just_created;
                 /**
                  * Notify plugins about created or modified followup
                  * @event followup_save
                  * @param array[string]int $params['id'] followup_id
                  * @param array[string]bool $params['just_created']
                  * @return void
                  */
                 wa()->event('followup_save', $f);
             }
         }
     }
     // List of all follow-ups
     $followups = $fm->getAll('id');
     // Get data to show in form
     $followup = null;
     if ($id) {
         if (empty($followups[$id])) {
             if ($followups) {
                 $followup = reset($followups);
             }
         } else {
             $followup = $followups[$id];
         }
     }
     $test_orders = array();
     if (empty($followup)) {
         $followup = $fm->getEmptyRow();
         $followup['body'] = self::getDefaultBody();
     } else {
         // Orders used as sample data for testing
         $om = new shopOrderModel();
         $test_orders = $om->where("paid_date IS NOT NULL AND state_id <> 'deleted'")->order('id DESC')->limit(10)->fetchAll('id');
         shopHelper::workupOrders($test_orders);
         $im = new shopOrderItemsModel();
         foreach ($im->getByField('order_id', array_keys($test_orders), true) as $i) {
             $test_orders[$i['order_id']]['items'][] = $i;
         }
         foreach ($test_orders as &$o) {
             $o['items'] = ifset($o['items'], array());
             $o['total_formatted'] = waCurrency::format('%{s}', $o['total'], $o['currency']);
         }
     }
     $this->view->assign('followup', $followup);
     $this->view->assign('followups', $followups);
     $this->view->assign('test_orders', $test_orders);
     $this->view->assign('last_cron', wa()->getSetting('last_followup_cli'));
     $this->view->assign('cron_ok', wa()->getSetting('last_followup_cli') + 3600 * 36 > time());
     $this->view->assign('cron_command', 'php ' . wa()->getConfig()->getRootPath() . '/cli.php shop followup');
     $this->view->assign('default_email_from', $this->getConfig()->getGeneralSettings('email'));
     $this->view->assign('routes', wa()->getRouting()->getByApp('shop'));
 }
 public function workupOrder($order)
 {
     if (!empty($order['items'])) {
         foreach ($order['items'] as &$item) {
             $item['name'] = htmlspecialchars($item['name']);
             unset($item);
         }
     }
     $order['contact']['name'] = htmlspecialchars($order['contact']['name']);
     $orders = array($order);
     shopHelper::workupOrders($orders);
     return $orders[0];
 }