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 function processListingDataResults($feed_rows, $result_rows)
 {
     $lm = new WPLA_ListingsModel();
     // index results by SKU
     $results = array();
     foreach ($result_rows as $r) {
         if (!isset($r['sku']) && isset($r['SKU'])) {
             $r['sku'] = $r['SKU'];
         }
         // translate column SKU -> sku
         if (!isset($r['sku']) || empty($r['sku'])) {
             continue;
         }
         $results[$r['sku']][] = $r;
         WPLA()->logger->info('result sku: ' . $r['sku']);
     }
     // process each result row
     foreach ($feed_rows as $row) {
         $listing_data = array();
         $row_sku = isset($row['item_sku']) ? $row['item_sku'] : $row['sku'];
         if (!$row_sku) {
             WPLA()->logger->warn('skipping row without SKU: ' . print_r($row, 1));
             continue;
         }
         $row_results = isset($results[$row_sku]) ? $results[$row_sku] : false;
         WPLA()->logger->info('processing feed sku: ' . $row_sku);
         // check if this is a delete feed (Inventory Loader)
         $add_delete_column = isset($row['add-delete']) ? $row['add-delete'] : '';
         $is_delete_feed = $add_delete_column == 'x' ? true : false;
         // if there are no result rows for this SKU, set status to 'online'
         if (!$row_results) {
             if ($is_delete_feed) {
                 $listing = $lm->getItemBySKU($row_sku);
                 if (!$listing) {
                     continue;
                 }
                 if ($listing->status == 'trashed') {
                     $lm->deleteItem($listing->id);
                     WPLA()->logger->info('DELETED listing ID ' . $listing->id . ' SKU: ' . $row_sku);
                 } else {
                     WPLA()->logger->warn('INVALID listing status for deletion - ID ' . $listing->id . ' / SKU: ' . $row_sku . ' / status: ' . $listing->status);
                 }
                 continue;
             }
             $listing_data['status'] = 'online';
             $listing_data['history'] = '';
             $lm->updateWhere(array('sku' => $row_sku, 'account_id' => $this->account_id), $listing_data);
             WPLA()->logger->info('changed status to online: ' . $row_sku);
             continue;
         }
         // handle errors and warnings
         $errors = array();
         $warnings = array();
         $processed_keys = array();
         foreach ($row_results as $row_result) {
             // translate error-type
             if ($row_result['error-type'] == 'Fehler') {
                 $row_result['error-type'] = 'Error';
             }
             // amazon.de
             if ($row_result['error-type'] == 'Warnung') {
                 $row_result['error-type'] = 'Warning';
             }
             if ($row_result['error-type'] == 'Erreur') {
                 $row_result['error-type'] = 'Error';
             }
             // amazon.fr
             if ($row_result['error-type'] == 'Avertissement') {
                 $row_result['error-type'] = 'Warning';
             }
             // compute hash to identify duplicate errors
             $row_key = md5($row_result['sku'] . $row_result['error-code'] . $row_result['error-type'] . $row_result['original-record-number']);
             // store feed id in error array
             $row_result['feed_id'] = $this->id;
             if ('Error' == $row_result['error-type']) {
                 WPLA()->logger->info('error: ' . $row_sku . ' - ' . $row_key . ' - ' . $row_result['error-message']);
                 if (!in_array($row_key, $processed_keys)) {
                     $errors[] = $row_result;
                     $processed_keys[] = $row_key;
                 }
             } elseif ('Warning' == $row_result['error-type']) {
                 WPLA()->logger->info('warning: ' . $row_sku . ' - ' . $row_key . ' - ' . $row_result['error-message']);
                 if (!in_array($row_key, $processed_keys)) {
                     $warnings[] = $row_result;
                     $processed_keys[] = $row_key;
                 }
             }
         }
         // foreach result row
         // update listing
         if (!empty($errors)) {
             $listing_data['status'] = 'failed';
             $listing_data['history'] = serialize(array('errors' => $errors, 'warnings' => $warnings));
             $lm->updateWhere(array('sku' => $row_sku, 'account_id' => $this->account_id), $listing_data);
             WPLA()->logger->info('changed status to FAILED: ' . $row_sku);
             $this->errors = array_merge($this->errors, $errors);
             $this->warnings = array_merge($this->warnings, $warnings);
         } elseif (!empty($warnings)) {
             $listing_data['status'] = $is_delete_feed ? 'trashed' : 'online';
             $listing_data['history'] = serialize(array('errors' => $errors, 'warnings' => $warnings));
             $lm->updateWhere(array('sku' => $row_sku, 'account_id' => $this->account_id), $listing_data);
             WPLA()->logger->info('changed status to online: ' . $row_sku);
             $this->warnings = array_merge($this->warnings, $warnings);
         }
     }
     // foreach row
 }
 public function fixNewVariationListings($variations, $parent_listing)
 {
     WPLA()->logger->info("fixNewVariationListings()");
     $lm = new WPLA_ListingsModel();
     // get post_id of parent which has been created by now
     // $parent_listing = $lm->getItemByASIN( $parent_listing->asin );
     $parent_listing = $lm->getItemBySKU($parent_listing->sku);
     // catch Invalid argument error
     if (!is_array($variations)) {
         WPLA()->logger->error("no variations found for parent variable ASIN {$parent_listing->asin} (not checked)");
         WPLA()->logger->error("no variations found for parent variable SKU  {$parent_listing->sku}");
         WPLA()->logger->error('variations:' . print_r($variations, 1));
         // echo 'Error: no variations found for variable ASIN '.$parent_listing->asin.'<br>';
         // echo "<pre>variations: ";print_r($variations);echo"</pre>";#die();
         return;
     }
     foreach ($variations as $var) {
         $post_id = WPLA_ProductBuilder::getProductIdBySKU($var->sku);
         if (!$post_id) {
             WPLA()->logger->warn("fixing SKU {$var->sku} ... no product found for this SKU!!");
             continue;
         }
         $data = array('post_id' => $post_id, 'parent_id' => $parent_listing->post_id);
         $lm->updateListing($var->listing_id, $data);
         WPLA()->logger->info("fixed SKU {$var->sku} - post_id: {$post_id}");
     }
 }
 public static function processFBAReportPage($report, $rows, $job, $task)
 {
     $listingsModel = new WPLA_ListingsModel();
     $errors = array();
     // get default fulfillment center ID
     $fba_default_fcid = get_option('wpla_fba_fulfillment_center_id', 'AMAZON_NA');
     // if fallback is enabled, clear FBA data before processing first page
     $account_id = $report->account_id;
     $fba_enable_fallback = get_option('wpla_fba_enable_fallback', 0);
     $fba_only_mode = get_option('wpla_fba_only_mode', 0);
     if ($task['from_row'] == 1 && $fba_enable_fallback) {
         // reset FBA info for all items using this account
         $update_data = array('fba_quantity' => null, 'fba_fcid' => null);
         $listingsModel->updateWhere(array('account_id' => $account_id), $update_data);
     }
     // process rows
     if (is_array($rows)) {
         foreach ($rows as $row) {
             // skip error rows (single element array)
             if (sizeof($row) <= 1) {
                 $error = new stdClass();
                 $error->HtmlMessage = strip_tags(reset($row));
                 $errors[] = $error;
                 continue;
             }
             $asin = $row['asin'];
             $sku = $row['seller-sku'];
             $fba_quantity = $row['Quantity Available'];
             $fba_condition = $row['Warehouse-Condition-code'];
             // skip rows if condition is UNSELLABLE
             if ($fba_condition == 'UNSELLABLE') {
                 continue;
             }
             // if fallback enabled, skip rows with zero quantity
             if ($fba_quantity == 0 && $fba_enable_fallback && !$fba_only_mode) {
                 continue;
             }
             $update_data = array('fba_quantity' => $fba_quantity, 'fba_fcid' => $fba_default_fcid);
             // update listings table - by SKU
             // if ( $asin ) $listingsModel->updateWhere( array( 'asin' => $asin ), $update_data );
             if ($sku) {
                 $listingsModel->updateWhere(array('sku' => $sku), $update_data);
             }
             // update quantity in WooCommerce - only if current stock level is less than FBA quantity
             if ($listing_item = $listingsModel->getItemBySKU($sku)) {
                 $post_id = $listing_item->post_id;
                 if ($post_id) {
                     // update stock level - if lower than FBA, or FBA only mode enabled
                     $woo_stock = get_post_meta($post_id, '_stock', true);
                     if ($woo_stock < $fba_quantity || $fba_only_mode == 1) {
                         update_post_meta($post_id, '_stock', $fba_quantity);
                         $woo_stock = $fba_quantity;
                         // // update out of stock attribute
                         // if ( $fba_quantity > 0 ) {
                         // 	update_post_meta( $post_id, '_stock_status', 'instock' );
                         // } else {
                         // 	update_post_meta( $post_id, '_stock_status', 'outofstock' );
                         // }
                     }
                     // update stock status based on actual stock - if required
                     $woo_stock_status = get_post_meta($post_id, '_stock_status', true);
                     $new_stock_status = $woo_stock > 0 ? 'instock' : 'outofstock';
                     if ($new_stock_status != $woo_stock_status) {
                         update_post_meta($post_id, '_stock_status', $new_stock_status);
                     }
                 }
                 // if $post_id
             }
             // if $listing_item
         }
     }
     // foreach report row
     // build response
     $response = new stdClass();
     $response->job = $job;
     $response->task = $task;
     $response->errors = $errors;
     $response->success = true;
     return $response;
 }
 function processListingItem($item, $order)
 {
     global $wpdb;
     // abort if item data is invalid
     if (!isset($item->ASIN) && !isset($item->QuantityOrdered)) {
         $history_message = "Error fetching order line items - request throttled?";
         $history_details = array();
         $this->addHistory($order->AmazonOrderId, 'request_throttled', $history_message, $history_details);
         return false;
     }
     $order_id = $order->AmazonOrderId;
     $asin = $item->ASIN;
     $sku = $item->SellerSKU;
     $quantity_purchased = $item->QuantityOrdered;
     // get listing item
     $lm = new WPLA_ListingsModel();
     $listing = $lm->getItemBySKU($sku);
     // skip if this listing does not exist in WP-Lister
     if (!$listing) {
         $history_message = "Skipped unknown SKU {$sku} ({$asin})";
         $history_details = array('sku' => $sku, 'asin' => $asin);
         $this->addHistory($order_id, 'skipped_item', $history_message, $history_details);
         return true;
     }
     // handle FBA orders
     if ($order->FulfillmentChannel == 'AFN') {
         // update quantity for FBA orders
         $fba_quantity = $listing->fba_quantity - $quantity_purchased;
         $quantity_sold = $listing->quantity_sold + $quantity_purchased;
         $wpdb->update($wpdb->prefix . 'amazon_listings', array('fba_quantity' => $fba_quantity, 'quantity_sold' => $quantity_sold), array('sku' => $sku));
         // add history record
         $history_message = "FBA quantity reduced by {$quantity_purchased} for listing {$sku} ({$asin}) - FBA stock {$fba_quantity} ({$quantity_sold} sold)";
         $history_details = array('fba_quantity' => $fba_quantity, 'sku' => $sku, 'asin' => $asin, 'qty_purchased' => $quantity_purchased, 'listing_id' => $listing->id);
         $this->addHistory($order_id, 'reduce_stock', $history_message, $history_details);
     } else {
         // update quantity for non-FBA orders
         $quantity_total = $listing->quantity - $quantity_purchased;
         $quantity_sold = $listing->quantity_sold + $quantity_purchased;
         $wpdb->update($wpdb->prefix . 'amazon_listings', array('quantity' => $quantity_total, 'quantity_sold' => $quantity_sold), array('sku' => $sku));
         // add history record
         $history_message = "Quantity reduced by {$quantity_purchased} for listing {$sku} ({$asin}) - new stock: {$quantity_total} ({$quantity_sold} sold)";
         $history_details = array('newstock' => $quantity_total, 'sku' => $sku, 'asin' => $asin, 'qty_purchased' => $quantity_purchased, 'listing_id' => $listing->id);
         $this->addHistory($order_id, 'reduce_stock', $history_message, $history_details);
     }
     // mark listing as sold when last item is sold
     // if ( $quantity_total == 0 ) {
     // 	$wpdb->update( $wpdb->prefix.'amazon_listings',
     // 		array( 'status' => 'sold', 'date_finished' => $data['date_created'], ),
     // 		array( 'sku' => $sku )
     // 	);
     // 	WPLA()->logger->info( 'marked item '.$sku.' as SOLD ');
     // }
     return true;
 }