public function process_product_meta_variable($post_id)
 {
     WPLA()->logger->info('process_product_meta_variable() - ' . $post_id);
     if (!isset($_POST['variable_sku'])) {
         return;
     }
     $variable_post_id = $_POST['variable_post_id'];
     $variable_amazon_product_id = $_POST['variable_amazon_product_id'];
     $variable_amazon_id_type = $_POST['variable_amazon_id_type'];
     $variable_amazon_asin = $_POST['variable_amazon_asin'];
     $variable_sku = $_POST['variable_sku'];
     $variable_amazon_price = isset($_POST['variable_amazon_price']) ? $_POST['variable_amazon_price'] : '';
     $variable_amazon_minimum_price = isset($_POST['variable_amazon_minimum_price']) ? $_POST['variable_amazon_minimum_price'] : '';
     $variable_amazon_maximum_price = isset($_POST['variable_amazon_maximum_price']) ? $_POST['variable_amazon_maximum_price'] : '';
     $variable_amazon_condition_type = isset($_POST['variable_amazon_condition_type']) ? $_POST['variable_amazon_condition_type'] : '';
     $variable_amazon_condition_note = isset($_POST['variable_amazon_condition_note']) ? $_POST['variable_amazon_condition_note'] : '';
     $variable_amazon_is_disabled = isset($_POST['variable_amazon_is_disabled']) ? $_POST['variable_amazon_is_disabled'] : '';
     // convert decimal comma for all price fields
     $variable_amazon_price = str_replace(',', '.', $variable_amazon_price);
     $variable_amazon_minimum_price = str_replace(',', '.', $variable_amazon_minimum_price);
     $variable_amazon_maximum_price = str_replace(',', '.', $variable_amazon_maximum_price);
     $lm = new WPLA_ListingsModel();
     $all_variations_with_SKU = array();
     $all_variations_with_ASIN = array();
     $max_loop = max(array_keys($_POST['variable_post_id']));
     for ($i = 0; $i <= $max_loop; $i++) {
         if (!isset($variable_post_id[$i])) {
             continue;
         }
         $variation_id = (int) $variable_post_id[$i];
         // Update post meta
         update_post_meta($variation_id, '_amazon_product_id', trim($variable_amazon_product_id[$i]));
         update_post_meta($variation_id, '_amazon_id_type', $variable_amazon_id_type[$i]);
         update_post_meta($variation_id, '_wpla_asin', trim($variable_amazon_asin[$i]));
         update_post_meta($variation_id, '_amazon_price', isset($variable_amazon_price[$i]) ? trim($variable_amazon_price[$i]) : '');
         update_post_meta($variation_id, '_amazon_minimum_price', isset($variable_amazon_minimum_price[$i]) ? trim($variable_amazon_minimum_price[$i]) : '');
         update_post_meta($variation_id, '_amazon_maximum_price', isset($variable_amazon_maximum_price[$i]) ? trim($variable_amazon_maximum_price[$i]) : '');
         update_post_meta($variation_id, '_amazon_condition_type', isset($variable_amazon_condition_type[$i]) ? trim($variable_amazon_condition_type[$i]) : '');
         update_post_meta($variation_id, '_amazon_condition_note', isset($variable_amazon_condition_note[$i]) ? trim($variable_amazon_condition_note[$i]) : '');
         update_post_meta($variation_id, '_amazon_is_disabled', isset($variable_amazon_is_disabled[$i]) ? $variable_amazon_is_disabled[$i] : '');
         // if ( $variable_amazon_product_id[$i] !== 'parent' )
         //     update_post_meta( $variation_id, '_amazon_product_id', $variable_amazon_product_id[$i] );
         // else
         //     delete_post_meta( $variation_id, '_amazon_product_id' );
         // update min/max prices in listings table
         if (isset($_POST['variable_amazon_minimum_price'])) {
             $min_price = isset($variable_amazon_minimum_price[$i]) ? $variable_amazon_minimum_price[$i] : '';
             $max_price = isset($variable_amazon_maximum_price[$i]) ? $variable_amazon_maximum_price[$i] : '';
             $data = array();
             if ($min_price || $max_price) {
                 if ($listing = $lm->getItemByPostID($variation_id)) {
                     if ($min_price != $listing->min_price) {
                         $data['min_price'] = $min_price;
                         $data['pnq_status'] = 1;
                         // mark as changed
                     }
                     if ($max_price != $listing->max_price) {
                         $data['max_price'] = $max_price;
                         $data['pnq_status'] = 1;
                         // mark as changed
                     }
                     // update listing
                     if (!empty($data)) {
                         $lm->updateWhere(array('id' => $listing->id), $data);
                     }
                 }
             }
         }
         // collect (matched) variations with ASIN
         if ($variable_amazon_asin[$i]) {
             $all_variations_with_ASIN[$variation_id] = $variable_amazon_asin[$i];
         }
         // collect all variations with SKU
         if ($variable_sku[$i]) {
             $all_variations_with_SKU[$variation_id] = $variable_sku[$i];
         }
     }
     // each variation
     WPLA()->logger->info('Variations with ASIN: ' . print_r($all_variations_with_ASIN, 1));
     WPLA()->logger->info('Variations with SKU : ' . print_r($all_variations_with_SKU, 1));
     // process matched variations
     // check all variations with ASIN and add missing ones to listings table
     if (!empty($all_variations_with_ASIN)) {
         $lm = new WPLA_ListingsModel();
         $default_account_id = get_option('wpla_default_account_id', 1);
         if (!$default_account_id) {
             return;
         }
         // ***
         foreach ($all_variations_with_ASIN as $variation_id => $asin) {
             // check if this ASIN / ID already exist - skip if it does
             WPLA()->logger->info("searching for existing listing for #{$variation_id} / {$asin}");
             if ($lm->getItemByASIN($asin, false)) {
                 continue;
             }
             if ($lm->getItemByPostID($variation_id)) {
                 continue;
             }
             WPLA()->logger->info("no listing found for variation #{$variation_id} / {$asin}");
             // skip hidden variations
             if (get_post_meta($variation_id, '_amazon_is_disabled', true) == 'on') {
                 continue;
             }
             // insert matched listing
             $success = $lm->insertMatchedProduct($variation_id, $asin, $default_account_id);
             $error_msg = isset($lm->lastError) ? $lm->lastError : '';
             if ($success) {
                 // TODO: use persistent admin message
                 WPLA()->logger->info("Matched variation #{$variation_id} / {$asin} - {$error_msg}");
             } else {
                 echo "Failed to match variation #{$variation_id} - please report this to support: {$error_msg}";
                 WPLA()->logger->error("Failed to match variation #{$variation_id} / {$asin} - {$error_msg}");
             }
         }
         // each matched variation
     }
     // if $all_variations_with_ASIN
     // add missing variations
     // if the parent product has a listing item, then check for and add missing variation listings
     $lm = new WPLA_ListingsModel();
     $parent_listing = $lm->getItemByPostID($post_id);
     if ($parent_listing) {
         // get account from parent listing
         $account = WPLA_AmazonAccount::getAccount($parent_listing->account_id);
         if (!$account) {
             return;
         }
         foreach ($all_variations_with_SKU as $variation_id => $sku) {
             // check if this SKU / ID already exist - skip if it does
             if ($lm->getItemBySKU($sku, false)) {
                 continue;
             }
             if ($lm->getItemByPostID($variation_id)) {
                 continue;
             }
             WPLA()->logger->info("no listing found for missing variation #{$variation_id} / {$sku}");
             // check if this variation has a UPC/EAN set - skip if empty (unless brand registry is enabled)
             $_amazon_product_id = get_post_meta($variation_id, '_amazon_product_id', true);
             if (!$_amazon_product_id && !$account->is_reg_brand) {
                 continue;
             }
             // skip hidden variations
             if (get_post_meta($variation_id, '_amazon_is_disabled', true) == 'on') {
                 continue;
             }
             // insert variation listing
             $success = $lm->insertMissingVariation($variation_id, $sku, $parent_listing);
             $error_msg = isset($lm->lastError) ? $lm->lastError : '';
             if ($success) {
                 // TODO: use persistent admin message
                 WPLA()->logger->info("Matched missing variation #{$variation_id} / {$sku} - {$error_msg}");
             } else {
                 echo "Failed to match missing variation #{$variation_id} - please report this to support: {$error_msg}";
                 WPLA()->logger->error("Failed to match missing variation #{$variation_id} / {$sku} - {$error_msg}");
             }
         }
         // each variation
     }
     // if parent listing exists
 }
 public static function orderCanBeFulfilledViaFBA($post, $is_cron = false)
 {
     // make sure we have a wp post object
     if (is_numeric($post)) {
         $post = get_post($post);
     }
     // check if this is an order created by WP-Lister for Amazon
     $amazon_order_id = get_post_meta($post->ID, '_wpla_amazon_order_id', true);
     if ($amazon_order_id) {
         return 'Order was placed on Amazon';
     }
     // check if this order has already been submitted to FBA
     $submission_status = get_post_meta($post->ID, '_wpla_fba_submission_status', true);
     if ($submission_status == 'pending') {
         return __('This order is going to be submitted to Amazon and will be fulfilled via FBA.', 'wpla');
     }
     if ($submission_status == 'success') {
         return __('This order has been successfully submitted to Amazon and will be fulfilled via FBA.', 'wpla');
     }
     if ($submission_status == 'shipped') {
         return __('This order has been fulfilled by Amazon.', 'wpla');
     }
     if ($submission_status == 'failed') {
         // failed submissions can be submitted again - but only manually for now
         // (automatic resubmittion will require proper error handling for Error 560001: Delivery SLA is not available for destination address - and fallback to Standard shipping)
         if ($is_cron) {
             return __('There was a problem submitting this order to be fulfilled by Amazon!', 'wpla');
         }
     }
     // skip cancelled and pending orders
     if (!in_array($post->post_status, array('wc-processing', 'wc-completed', 'wc-on-hold'))) {
         return __('Order status is neither processing nor completed not on hold.', 'wpla');
     }
     // check if FBA is enabled (not really required)
     // if ( !  get_option( 'wpla_fba_enabled' ) ) return 'FBA support is disabled.';
     // get order and order items
     if (!function_exists('wc_get_order')) {
         return;
     }
     $_order = wc_get_order($post->ID);
     $order_items = $_order->get_items();
     // check if destination country matches fulfillment center
     $fba_default_fcid = get_option('wpla_fba_fulfillment_center_id', 'AMAZON_NA');
     if ('AMAZON_NA' == $fba_default_fcid) {
         $allowed_countries = array('US');
         if (!in_array($_order->shipping_country, $allowed_countries)) {
             return __('Shipping destination is not within the US.', 'wpla');
         }
     } elseif ('AMAZON_EU' == $fba_default_fcid) {
         $allowed_countries = array('AT', 'BE', 'BG', 'CY', 'CZ', 'DE', 'DK', 'EE', 'ES', 'FI', 'FR', 'GB', 'GR', 'HU', 'HR', 'IE', 'IT', 'LT', 'LU', 'LV', 'MT', 'NL', 'PL', 'PT', 'RO', 'SE', 'SI', 'SK');
         if (!in_array($_order->shipping_country, $allowed_countries)) {
             return __('Shipping destination is not within the EU.', 'wpla');
         }
     } elseif ('AMAZON_IN' == $fba_default_fcid) {
         $allowed_countries = array('IN');
         if (!in_array($_order->shipping_country, $allowed_countries)) {
             return __('Shipping destination is not within India.', 'wpla');
         }
     }
     // check if ordered items are available on FBA
     $items_available_on_fba = array();
     $count_not_available_on_fba = 0;
     $lm = new WPLA_ListingsModel();
     foreach ($order_items as $item) {
         // skip tax and shipping rows
         if ($item['type'] != 'line_item') {
             continue;
         }
         // find amazon listing
         $post_id = $item['variation_id'] ? $item['variation_id'] : $item['product_id'];
         $listing = $lm->getItemByPostID($post_id);
         if (!$listing) {
             $count_not_available_on_fba++;
             continue;
         }
         // check FBA inventory
         $fba_quantity = $listing->fba_quantity;
         if ($fba_quantity > 0) {
             $listing->purchased_qty = $item['qty'];
             $items_available_on_fba[] = $listing;
         } else {
             $count_not_available_on_fba++;
         }
     }
     // each order line item
     if (empty($items_available_on_fba)) {
         $msg = __('This order can not be fulfilled by Amazon.', 'wpla') . ' ';
         $msg .= __('The purchased item(s) are currently not available on FBA.', 'wpla');
         return $msg;
     }
     if ($count_not_available_on_fba > 0) {
         $msg = __('This order can not be fulfilled by Amazon.', 'wpla') . ' ';
         $msg .= __('Not all purchased items are currently available on FBA.', 'wpla');
         return $msg;
     }
     // this order can be filfilled via FBA - return array of items
     return $items_available_on_fba;
 }
 function processFbaSubmissionOrderItem($order_item, $_order)
 {
     // Flat File FBA Shipment Injection Fulfillment Feed
     $feed_type = '_POST_FLAT_FILE_FULFILLMENT_ORDER_REQUEST_DATA_';
     // use account from first order item (for now)
     $lm = new WPLA_ListingsModel();
     $post_id = $order_item['variation_id'] ? $order_item['variation_id'] : $order_item['product_id'];
     $listing = $lm->getItemByPostID($post_id);
     $account_id = $listing->account_id;
     $account = new WPLA_AmazonAccount($account_id);
     WPLA()->logger->info('updateFbaSubmissionFeed() ' . $feed_type . ' - post id: ' . $post_id . ' - account id: ' . $account->id);
     // create pending feed if it doesn't exist
     if (!($this->id = self::getPendingFeedId($feed_type, null, $account->id))) {
         # build feed data
         WPLA()->logger->info('building FBA submission feed...');
         $csv = WPLA_FeedDataBuilder::buildFbaSubmissionFeedData($post_id, $_order, $order_item, $listing, $account->id, true);
         if (!$csv) {
             WPLA()->logger->warn('no feed data - not creating feed');
             return;
         }
         // add new feed
         $this->FeedType = $feed_type;
         $this->status = 'pending';
         $this->account_id = $account->id;
         $this->date_created = date('Y-m-d H:i:s');
         $this->data = $csv;
         $this->add();
         WPLA()->logger->info('added NEW feed - id ' . $this->id);
     } else {
         WPLA()->logger->info('found existing feed ' . $this->id);
         $existing_feed = new WPLA_AmazonFeed($this->id);
         # append feed data
         WPLA()->logger->info('updating FBA submission feed...');
         $csv = WPLA_FeedDataBuilder::buildFbaSubmissionFeedData($post_id, $_order, $order_item, $listing, $account->id, false);
         $this->data = $existing_feed->data . $csv;
     }
     // update feed
     $this->line_count = sizeof($csv);
     $this->FeedProcessingStatus = 'pending';
     $this->date_created = date('Y-m-d H:i:s');
     $this->update();
     WPLA()->logger->info('feed was built and updated - ' . $this->id);
 }
 function wpla_product_admin_notices()
 {
     global $post, $post_ID;
     if (!$post) {
         return;
     }
     if (!$post_ID) {
         return;
     }
     if (!$post->post_type == 'product') {
         return;
     }
     $errors_msg = '';
     // warn about missing details
     $this->checkForMissingData($post);
     $this->checkForInvalidData($post);
     // get listing item
     $lm = new WPLA_ListingsModel();
     $listing = $lm->getItemByPostID($post_ID);
     if (!$listing) {
         return;
     }
     // parse history
     $history = maybe_unserialize($listing->history);
     if (empty($history) && $listing->product_type != 'variable') {
         return;
     }
     // echo "<pre>";print_r($history);echo"</pre>";#die();
     // show errors and warning on online and failed items only
     if (!in_array($listing->status, array('online', 'failed'))) {
         return;
     }
     // process errors and warnings
     $tips_errors = array();
     $tips_warnings = array();
     if (is_array($history)) {
         foreach ($history['errors'] as $feed_error) {
             $tips_errors[] = WPLA_FeedValidator::formatAmazonFeedError($feed_error);
         }
         foreach ($history['warnings'] as $feed_error) {
             $tips_warnings[] = WPLA_FeedValidator::formatAmazonFeedError($feed_error);
         }
     }
     if (!empty($tips_errors)) {
         $errors_msg .= 'Amazon returned the following error(s) when this product was submitted.' . ' ';
         $errors_msg .= '(Status: ' . $listing->status . ')<br>';
         $errors_msg .= '<small style="color:darkred">' . join('<br>', $tips_errors) . '</small>';
     }
     // check variations for errors
     if ($listing->product_type == 'variable') {
         $variations_msg = $errors_msg ? '<br><br>' : '';
         $variations_msg .= '<small><a href="#" onclick="jQuery(\'#variation_error_container\').slideToggle();return false;" class="button button-small">' . 'Show errors for all variations' . '</a></small>';
         $variations_msg .= '<div id="variation_error_container" style="display:none">';
         $variations_have_errors = false;
         $child_items = $lm->getAllItemsByParentID($post_ID);
         foreach ($child_items as $child) {
             $history = maybe_unserialize($child->history);
             $tips_errors = array();
             if (is_array($history)) {
                 foreach ($history['errors'] as $feed_error) {
                     $tips_errors[] = WPLA_FeedValidator::formatAmazonFeedError($feed_error);
                 }
                 // foreach ( $history['warnings'] as $feed_error ) {
                 //     $tips_warnings[] = WPLA_FeedValidator::formatAmazonFeedError( $feed_error );
                 // }
             }
             if (!empty($tips_errors)) {
                 $variations_msg .= 'Errors for variation ' . $child->sku . ':' . '<br>';
                 $variations_msg .= '<small style="color:darkred">' . join('<br>', $tips_errors) . '</small><br><br>';
                 $variations_have_errors = true;
             }
         }
         $variations_msg .= '</div>';
         if ($variations_have_errors) {
             $errors_msg .= $variations_msg;
         }
     }
     if ($errors_msg) {
         self::showMessage($errors_msg, 1, 1);
     }
 }