/**
  * Disables the gateway under any of these conditions:
  * 1) If the cart does not contain a pre-order
  * 2) If the pre-order amount is charged upfront
  * 3) On the pay page
  *
  * @since 1.0
  * @return bool
  */
 public function is_available()
 {
     $is_available = true;
     // Backwards compatibility checking for payment page
     if (function_exists('is_checkout_pay_page')) {
         $pay_page = is_checkout_pay_page();
     } else {
         $pay_page = is_page(woocommerce_get_page_id('pay'));
     }
     // on checkout page
     if (!$pay_page || defined('WOOCOMMERCE_CHECKOUT') && WOOCOMMERCE_CHECKOUT) {
         // not available if the cart does not contain a pre-order
         if (WC_Pre_Orders_Cart::cart_contains_pre_order()) {
             // not available when the pre-order amount is charged upfront
             if (WC_Pre_Orders_Product::product_is_charged_upfront(WC_Pre_Orders_Cart::get_pre_order_product())) {
                 $is_available = false;
             }
         } else {
             $is_available = false;
         }
     } else {
         // not available on the pay page (for now)
         $is_available = false;
     }
     return $is_available;
 }
 /**
  * Dispatch the email
  *
  * @since 1.0
  */
 public function trigger($args)
 {
     if (!empty($args)) {
         $defaults = array('order' => '', 'message' => '');
         $args = wp_parse_args($args, $defaults);
         extract($args);
         if (!is_object($order)) {
             return;
         }
         $this->object = $order;
         $this->recipient = $this->object->billing_email;
         $this->message = $message;
         $this->availability_date = WC_Pre_Orders_Product::get_localized_availability_date(WC_Pre_Orders_Order::get_pre_order_product($this->object));
         $this->find[] = '{order_date}';
         $this->replace[] = date_i18n(woocommerce_date_format(), strtotime($this->object->order_date));
         $this->find[] = '{release_date}';
         $this->replace[] = $this->availability_date;
         $this->find[] = '{order_number}';
         $this->replace[] = $this->object->get_order_number();
     }
     if (!$this->is_enabled() || !$this->get_recipient()) {
         return;
     }
     $this->send($this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments());
 }
 /**
  * Conditionally remove any gateways that don't support pre-orders on the checkout page when the pre-order is charged
  * upon release. This is done because payment info is not required in this case so displaying gateways/payment fields
  * is not needed.
  *
  * @since 1.0
  * @param array $available_gateways
  * @return array
  */
 public function maybe_remove_unsupported_gateways($available_gateways)
 {
     // on checkout page
     if ((!is_page(woocommerce_get_page_id('pay')) || defined('WOOCOMMERCE_CHECKOUT') && WOOCOMMERCE_CHECKOUT) && WC_Pre_Orders_Cart::cart_contains_pre_order() && WC_Pre_Orders_Product::product_is_charged_upon_release(WC_Pre_Orders_Cart::get_pre_order_product())) {
         // remove any non-supported payment gateways
         foreach ($available_gateways as $gateway_id => $gateway) {
             if (!method_exists($gateway, 'supports') || false === $gateway->supports('pre-orders')) {
                 unset($available_gateways[$gateway_id]);
             }
         }
     }
     return $available_gateways;
 }
 /**
  * Force tokenization for pre-orders
  *
  * @since 4.1.0
  * @see SV_WC_Payment_Gateway::tokenization_forced()
  * @param boolean $force_tokenization whether tokenization should be forced
  * @return boolean true if tokenization should be forced, false otherwise
  */
 public function maybe_force_tokenization($force_tokenization)
 {
     // pay page with pre-order?
     $pay_page_pre_order = false;
     if ($this->get_gateway()->is_pay_page_gateway()) {
         $order_id = $this->get_gateway()->get_checkout_pay_page_order_id();
         if ($order_id) {
             $pay_page_pre_order = WC_Pre_Orders_Order::order_contains_pre_order($order_id) && WC_Pre_Orders_Product::product_is_charged_upon_release(WC_Pre_Orders_Order::get_pre_order_product($order_id));
         }
     }
     if (WC_Pre_Orders_Cart::cart_contains_pre_order() && WC_Pre_Orders_Product::product_is_charged_upon_release(WC_Pre_Orders_Cart::get_pre_order_product()) || $pay_page_pre_order) {
         // always tokenize the card for pre-orders that are charged upon release
         $force_tokenization = true;
     }
     return $force_tokenization;
 }
 /**
  * Dispatch the email
  *
  * @since 1.0
  */
 public function trigger($order_id, $message)
 {
     if ($order_id) {
         $this->object = new WC_Order($order_id);
         $this->recipient = $this->object->billing_email;
         $this->message = $message;
         $this->find[] = '{order_date}';
         $this->replace[] = date_i18n(woocommerce_date_format(), strtotime($this->object->order_date));
         $this->find[] = '{release_date}';
         $this->replace[] = WC_Pre_Orders_Product::get_localized_availability_date(WC_Pre_Orders_Order::get_pre_order_product($this->object));
         $this->find[] = '{order_number}';
         $this->replace[] = $this->object->get_order_number();
     }
     if (!$this->is_enabled() || !$this->get_recipient()) {
         return;
     }
     $this->send($this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments());
 }
 /**
  * Disables the gateway under any of these conditions:
  * 1) If the cart does not contain a pre-order
  * 2) If the pre-order amount is charged upfront
  * 3) On the pay page
  *
  * @since 1.0
  * @return bool
  */
 public function is_available()
 {
     $is_available = parent::is_available();
     // on checkout page
     if (!is_page(woocommerce_get_page_id('pay')) || defined('WOOCOMMERCE_CHECKOUT') && WOOCOMMERCE_CHECKOUT) {
         // not available if the cart does not contain a pre-order
         if (WC_Pre_Orders_Cart::cart_contains_pre_order()) {
             // not available when the pre-order amount is charged upfront
             if (WC_Pre_Orders_Product::product_is_charged_upfront(WC_Pre_Orders_Cart::get_pre_order_product())) {
                 $is_available = false;
             }
         } else {
             $is_available = false;
         }
     } else {
         // not available on the pay page (for now)
         $is_available = false;
     }
     return $is_available;
 }
        echo get_post_permalink($item['product_id']);
        ?>
">
						<?php 
        echo $item['name'];
        ?>
					</a>
				</td>
				<td class="pre-order-status" style="text-align:left; white-space:nowrap;">
					<?php 
        echo WC_Pre_Orders_Order::get_pre_order_status_to_display($order);
        ?>
				</td>
				<td class="pre-order-release-date">
					<?php 
        echo WC_Pre_Orders_Product::get_localized_availability_date($item['product_id']);
        ?>
				</td>
				<td class="pre-order-actions order-actions">
					<?php 
        foreach ($actions[$order->id] as $key => $action) {
            ?>
					<a href="<?php 
            echo esc_url($action['url']);
            ?>
" class="button <?php 
            echo sanitize_html_class($key);
            ?>
"><?php 
            echo esc_html($action['name']);
            ?>
 /**
  * Save pre-order options
  *
  * @since 1.0
  * @param int $post_id the ID of the product being saved
  */
 public function save_product_tab_options($post_id)
 {
     // don't save any settings if there are active pre-orders
     if (WC_Pre_Orders_Product::product_has_active_pre_orders($post_id)) {
         return;
     }
     // pre-orders enabled
     if (isset($_POST['_wc_pre_orders_enabled']) && 'yes' === $_POST['_wc_pre_orders_enabled']) {
         update_post_meta($post_id, '_wc_pre_orders_enabled', 'yes');
     } else {
         update_post_meta($post_id, '_wc_pre_orders_enabled', 'no');
     }
     /*
      * Save the availability date/time
      *
      * The date/time a pre-order is released is saved as a unix timestamp adjusted for the site's timezone. For example,
      * when an admin sets a pre-order to be released on 2013-06-25 12pm EST (UTC-4), it is saved as a timestamp equivalent
      * to 2013-12-25 4pm UTC. This makes the pre-order release check much easier, as it's a simple timestamp comparison,
      * because the release datetime and the current time are both in UTC.
      */
     if (!empty($_POST['_wc_pre_orders_availability_datetime'])) {
         try {
             // get datetime object from site timezone
             $datetime = new DateTime($_POST['_wc_pre_orders_availability_datetime'], new DateTimeZone(WC_Pre_Orders_Product::get_wp_timezone_string()));
             // get the unix timestamp (adjusted for the site's timezone already)
             $timestamp = $datetime->format('U');
             // don't allow availability dates in the past
             if ($timestamp <= time()) {
                 $timestamp = '';
             }
             // set the availability datetime
             update_post_meta($post_id, '_wc_pre_orders_availability_datetime', $timestamp);
         } catch (Exception $e) {
             global $wc_pre_orders;
             $wc_pre_orders->log($e->getMessage());
         }
     } else {
         delete_post_meta($post_id, '_wc_pre_orders_availability_datetime');
     }
     // pre-order fee
     if (isset($_POST['_wc_pre_orders_fee']) && is_numeric($_POST['_wc_pre_orders_fee'])) {
         update_post_meta($post_id, '_wc_pre_orders_fee', $_POST['_wc_pre_orders_fee']);
     }
     // when to charge pre-order amount
     if (isset($_POST['_wc_pre_orders_when_to_charge']) && isset($_POST['_wc_pre_orders_enabled']) && 'yes' === $_POST['_wc_pre_orders_enabled']) {
         update_post_meta($post_id, '_wc_pre_orders_when_to_charge', 'upon_release' === $_POST['_wc_pre_orders_when_to_charge'] ? 'upon_release' : 'upfront');
     }
     do_action('wc_pre_orders_save_product_options', $post_id);
 }
 /**
  * Checks if the current cart contains a product with pre-orders enabled
  *
  * @since 1.0
  * @return bool true if the cart contains a pre-order, false otherwise
  */
 public static function cart_contains_pre_order()
 {
     global $woocommerce;
     $contains_pre_order = false;
     if (!empty($woocommerce->cart->cart_contents)) {
         foreach ($woocommerce->cart->cart_contents as $cart_item) {
             if (WC_Pre_Orders_Product::product_can_be_pre_ordered($cart_item['product_id'])) {
                 $contains_pre_order = true;
                 break;
             }
         }
     }
     return $contains_pre_order;
 }
 /**
  * Adds a 'Release Date' line to pre-order product order items on the
  * thank-you page, emails, my account, etc
  *
  * @since 1.0
  * @param array $items array of order item arrays
  * @param WC_Order $order order object
  * @return array of order item arrays
  */
 public function add_product_release_date_item_meta($items, $order)
 {
     if (self::order_contains_pre_order($order)) {
         $name = get_option('wc_pre_orders_availability_date_cart_title_text');
         foreach ($items as &$item) {
             if ('line_item' === $item['type']) {
                 $product = get_product($item['product_id']);
                 $pre_order_meta = apply_filters('wc_pre_orders_order_item_meta', WC_Pre_Orders_Product::get_localized_availability_date($product), $item, $order);
                 if (!empty($pre_order_meta)) {
                     $item['item_meta'][$name][0] = $pre_order_meta;
                 }
             }
         }
     }
     return $items;
 }
 /**
  * Process payment for an order:
  * 1) If the order contains a subscription, process the initial subscription payment (could be $0 if a free trial exists)
  * 2) If the order contains a pre-order, process the pre-order total (could be $0 if the pre-order is charged upon release)
  * 3) Otherwise use the parent::process_payment() method for regular product purchases
  *
  * @since 2.0
  * @param int $order_id
  * @return array
  */
 public function process_payment($order_id)
 {
     $order = $this->get_order($order_id);
     try {
         /* processing subscription */
         if (wc_amazon_fps()->is_subscriptions_active() && WC_Subscriptions_Order::order_contains_subscription($order)) {
             // calculate the lifetime amount to be charged for the subscription, with a multiplier applied to account for upgrades / price increases
             $order->amazon_lifetime_subscription_total = $this->calculate_lifetime_subscription_total($order);
             // set a subscription-specific description
             $order->amazon_description = sprintf(__('%s - Subscription Order %s', WC_Amazon_FPS::TEXT_DOMAIN), esc_html(get_bloginfo('name')), $order->get_order_number());
             $url = $this->get_api()->get_subscriptions_purchase_url($order);
             /* processing pre-order */
         } elseif (wc_amazon_fps()->is_pre_orders_active() && WC_Pre_Orders_Order::order_contains_pre_order($order_id) && WC_Pre_Orders_Order::order_requires_payment_tokenization($order->id)) {
             // Amazon requires an expiration date for the token so use the pre-order release date + 6 months to account for pre-order delays
             $release_date = WC_Pre_Orders_Product::get_localized_availability_date(WC_Pre_Orders_Order::get_pre_order_product($order));
             $order->amazon_pre_order_release_date = strtotime("{$release_date} +6 months");
             $url = $this->get_api()->get_pre_order_purchase_url($order);
             /* processing regular product (or a pre-order charged upfront) */
         } else {
             return parent::process_payment($order_id);
         }
         // add to log
         $this->log($url, 'request');
         // redirect to Amazon
         return array('result' => 'success', 'redirect' => $url);
     } catch (Exception $e) {
         $this->mark_order_as_failed($order, $e->getMessage());
     }
 }
 /**
  * Since a cart may only contain a single pre-ordered product, this returns the pre-ordered product object or
  * null if the cart does not contain a pre-order
  *
  * @since 1.0
  * @return object|null the pre-ordered product object, or null if the cart does not contain a pre-order
  */
 public static function get_pre_order_product()
 {
     global $woocommerce;
     if (self::cart_contains_pre_order()) {
         foreach ($woocommerce->cart->cart_contents as $cart_item) {
             if (WC_Pre_Orders_Product::product_can_be_pre_ordered($cart_item['product_id'])) {
                 // return the product object
                 return get_product($cart_item['variation_id'] ? $cart_item['variation_id'] : $cart_item['product_id']);
             }
         }
     } else {
         // cart doesn't contain pre-order
         return null;
     }
 }
 /**
  * Get column content, this is called once per column, per row item ($order)
  * returns the content to be rendered within that cell.
  *
  * @see WP_List_Table::single_row_columns()
  * @since 1.0
  * @param WC_Order $order one row (item) in the table
  * @param string $column_name the column slug
  * @return string the column content
  */
 public function column_default($order, $column_name)
 {
     switch ($column_name) {
         case 'status':
             $actions = array();
             // base action url
             $action_url = add_query_arg('order_id[]', $order->id);
             // determine any available actions
             if (WC_Pre_Orders_Manager::can_pre_order_be_changed_to('cancelled', $order)) {
                 $actions['cancel'] = sprintf('<a href="%s">%s</a>', add_query_arg('action', 'cancel', $action_url), __('Cancel', 'wc-pre-orders'));
             }
             $column_content = sprintf('<mark class="%s tips" data-tip="%s">%s</mark>', WC_Pre_Orders_Order::get_pre_order_status($order), WC_Pre_Orders_Order::get_pre_order_status_to_display($order), WC_Pre_Orders_Order::get_pre_order_status_to_display($order));
             $column_content .= $this->row_actions($actions);
             break;
         case 'customer':
             if (0 !== $order->user_id) {
                 $column_content = sprintf('<a href="%s">%s</a>', get_edit_user_link($order->user_id), $order->billing_email);
             } else {
                 $column_content = $order->billing_email;
             }
             break;
         case 'product':
             $item = WC_Pre_Orders_Order::get_pre_order_item($order);
             $product_edit = get_edit_post_link($item['product_id']);
             $column_content = $product_edit ? sprintf('<a href="%s">%s</a>', $product_edit, $item['name']) : $item['name'];
             break;
         case 'order':
             $column_content = sprintf('<a href="%s">%s</a>', get_edit_post_link($order->id), sprintf(__('Order %s', 'wc-pre-orders'), $order->get_order_number()));
             break;
         case 'order_date':
             $column_content = date_i18n(woocommerce_date_format(), strtotime($order->order_date));
             break;
         case 'availability_date':
             $product = WC_Pre_Orders_Order::get_pre_order_product($order);
             $column_content = WC_Pre_Orders_Product::get_localized_availability_date($product, '--');
             break;
         default:
             $column_content = '';
             break;
     }
     return $column_content;
 }
 /**
  * Helper function to return a formatted pre-order order total, e.g. '$99 charged on Dec 1, 2014'
  *
  * @since 1.0
  * @param string $total formatted order total to modify
  * @param object|int $product the product that the pre-order contains
  * @return string the new formatted order total
  */
 public static function get_formatted_pre_order_total($total, $product)
 {
     if (!is_object($product)) {
         $product = get_product($product);
     }
     // get order total format
     if (WC_Pre_Orders_Product::product_is_charged_upon_release($product)) {
         $formatted_total = get_option('wc_pre_orders_upon_release_order_total_format');
     } else {
         $formatted_total = get_option('wc_pre_orders_upfront_order_total_format');
     }
     // bail if no format is set
     if (!$formatted_total) {
         return $total;
     }
     // add localized availability date if needed
     $formatted_total = str_replace('{availability_date}', WC_Pre_Orders_Product::get_localized_availability_date($product), $formatted_total);
     // add order total
     $formatted_total = str_replace('{order_total}', $total, $formatted_total);
     return apply_filters('wc_pre_orders_pre_order_order_total', $formatted_total, $product);
 }