static function checkAllProductsWithStatus($status) { $problems = array(); // get all prepared products $lm = new WPLA_ListingsModel(); $listings = $lm->findAllListingsByColumn($status, 'status'); // echo "<pre>";print_r($listings);echo"</pre>";#die(); // get all post_ids global $wpdb; $post_ids = $wpdb->get_col("SELECT ID FROM {$wpdb->posts} WHERE post_type = 'product' OR post_type = 'product_variation' "); foreach ($listings as $listing_id => $item) { // check if product exists if (!in_array($item->post_id, $post_ids)) { $problems[] = array('msg' => 'The product "' . $item->listing_title . '" does not exist in WooCommerce and will not be included in the next feed submission.', 'post_id' => $item->post_id); } // check SKU - all products if ($item->sku == '') { $problems[] = array('msg' => 'The product "' . $item->listing_title . '" has no SKU and will not be included in the next feed submission.', 'post_id' => $item->post_id); } if (strlen($item->sku) > 40) { $problems[] = array('msg' => 'The SKU <b>' . $item->sku . '</b> for product "' . $item->listing_title . '" is longer than 40 characters. Amazon requires SKUs to have 40 characters or less.', 'post_id' => $item->post_id); } // run checks for variable or simple product if ($item->product_type == 'variable') { // $problems = self::checkVariableProduct( $item, $problems ); } elseif ($item->product_type == 'variation') { // $problems = self::checkSimpleProduct( $item, $problems ); } else { $problems = self::checkSimpleProduct($item, $problems); } } // foreach listing return $problems; }
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); }
public function showNotifications() { // get listing status summary $summary = WPLA_ListingsModel::getStatusSummary(); // check for prepared items and display info if (isset($summary->prepared)) { // $next_schedule = $this->print_schedule_info( 'wpla_update_schedule' ); // $msg = '<p>'; // $msg .= sprintf( __('%d %s product(s) will be submitted to Amazon %s.','wpla'), $summary->prepared, 'prepared', $next_schedule ); // $msg .= ' '; // $msg .= '<a href="admin.php?page=wpla&listing_status=prepared" id="" class="button button-small wpl_job_button">' . __('Show products','wpla') . '</a>'; // $msg .= ' '; // $msg .= '<a href="admin.php?page=wpla-feeds&action=submit_pending_feeds_to_amazon" id="" class="button button-small wpl_job_button">' . __('Submit pending feeds','wpla') . '</a>'; // $msg .= '</p>'; // $this->showMessage( $msg ); // check prepared products for problems $problems = WPLA_FeedValidator::checkPreparedProducts(); if ($problems) { $this->showMessage($problems, 1); } } // check for changed, matched and prepared items - and show message $is_feed_page = isset($_GET['page']) && $_GET['page'] == 'wpla-feeds'; if (isset($summary->changed) || isset($summary->prepared) || isset($summary->matched)) { $next_schedule = $this->print_schedule_info('wpla_update_schedule'); // build nice combined message $summary_msg = ''; $summary_array = array(); foreach (array('changed', 'prepared', 'matched') as $status) { if (!isset($summary->{$status})) { continue; } $link_url = 'admin.php?page=wpla&listing_status=' . $status; $link_title = $summary->{$status} . ' ' . $status; $summary_array[] = '<a href="' . $link_url . '">' . $link_title . '</a>'; } $summary_msg = join(' and ', $summary_array); $msg = '<p>'; $msg .= sprintf(__('%s product(s) will be submitted to Amazon %s.', 'wpla'), $summary_msg, $next_schedule); $msg .= ' '; if ($is_feed_page) { $msg .= '<a href="admin.php?page=wpla-feeds&action=submit_pending_feeds_to_amazon" id="" class="button button-small wpl_job_button">' . __('Submit pending feeds', 'wpla') . '</a>'; } else { $msg .= '<a href="admin.php?page=wpla-feeds" id="" class="button button-small wpl_job_button">' . __('Visit feeds', 'wpla') . '</a>'; } $msg .= '</p>'; $this->showMessage($msg); } }
static function updateAmazonPrice($item, $target_price, $verbose) { // make sure we don't go below min_price if ($item->min_price) { $target_price = max($target_price, $item->min_price); } // make sure we don't go above max_price (prevent feed error) if ($item->max_price) { $target_price = min($target_price, $item->max_price); } // skip if there is no change in price if ($target_price == $item->price) { return false; } // update amazon price in WooCommerce update_post_meta($item->post_id, '_amazon_price', $target_price); // update price in listings table $data = array('price' => $target_price, 'pnq_status' => 1); WPLA_ListingsModel::updateWhere(array('id' => $item->id), $data); // show message if ($verbose) { wpla_show_message($item->sku . ': price was changed from ' . $item->price . ' to <b>' . $target_price . '</b>'); } // price was changed return true; }
public static function updateMinMaxPrices($item_ids) { // echo "<pre>";print_r($item_ids);echo"</pre>"; // TODO: sanitize values $min_base_price = trim($_REQUEST['min_base_price']); $min_price_percentage = trim($_REQUEST['min_price_percentage']); $min_price_amount = trim($_REQUEST['min_price_amount']); $max_base_price = trim($_REQUEST['max_base_price']); $max_price_percentage = trim($_REQUEST['max_price_percentage']); $max_price_amount = trim($_REQUEST['max_price_amount']); $min_price_amount = str_replace(',', '.', $min_price_amount); // convert decimal comma $max_price_amount = str_replace(',', '.', $max_price_amount); // remember last used options $options = array('min_base_price' => $min_base_price, 'max_base_price' => $max_base_price, 'min_price_amount' => $min_price_amount, 'max_price_amount' => $max_price_amount, 'min_price_percentage' => $min_price_percentage, 'max_price_percentage' => $max_price_percentage); update_option('wpla_price_wizard_options', $options); $lm = new WPLA_ListingsModel(); foreach ($item_ids as $listing_id) { // load listing item $item = $lm->getItem($listing_id, OBJECT); if (!$item) { continue; } if ($item->product_type == 'variable') { continue; } $post_id = $item->post_id; // get base price (min) $base_price = 0; if ($min_base_price == 'price') { $base_price = WPLA_ProductWrapper::getPrice($post_id); } if ($min_base_price == 'sale_price') { $base_price = WPLA_ProductWrapper::getSalePrice($post_id); } if ($min_base_price == 'msrp') { $base_price = get_post_meta($post_id, '_msrp', true) ? get_post_meta($post_id, '_msrp', true) : get_post_meta($post_id, '_msrp_price', true); } // calculate new min price if ($min_price_percentage) { $base_price = $base_price + $base_price * floatval($min_price_percentage) / 100; } if ($min_price_amount) { $base_price = $base_price + floatval($min_price_amount); } if ($min_base_price == 'no_change') { $base_price = $item->min_price; } $new_min_price = round($base_price, 2); // get base price (max) $base_price = 0; if ($max_base_price == 'price') { $base_price = WPLA_ProductWrapper::getPrice($post_id); } if ($max_base_price == 'sale_price') { $base_price = WPLA_ProductWrapper::getSalePrice($post_id); } if ($max_base_price == 'msrp') { $base_price = get_post_meta($post_id, '_msrp', true) ? get_post_meta($post_id, '_msrp', true) : get_post_meta($post_id, '_msrp_price', true); } // calculate new max price if ($max_price_percentage) { $base_price = $base_price + $base_price * floatval($max_price_percentage) / 100; } if ($max_price_amount) { $base_price = $base_price + floatval($max_price_amount); } if ($max_base_price == 'no_change') { $base_price = $item->max_price; } $new_max_price = round($base_price, 2); // update listing table $data = array('min_price' => $new_min_price, 'max_price' => $new_max_price, 'pnq_status' => 1); $lm->updateWhere(array('id' => $listing_id), $data); // update product update_post_meta($item->post_id, '_amazon_minimum_price', $new_min_price); update_post_meta($item->post_id, '_amazon_maximum_price', $new_max_price); } // foreach item }
} if (!isset($row['seller-sku'])) { $product_sku = '<span style="color:darkred">Invalid Report - no SKU column found</span>'; } ?> <tr> <th scope="row" class="check-column"><input type="checkbox" name="row[]" value="<?php echo $row['seller-sku']; ?> "></th> <!-- <td><?php echo utf8_encode($row['item-name']); ?> </td> --> <td><?php echo WPLA_ListingsModel::convertToUTF8($row['item-name']); ?> </td> <td><?php echo $product_sku; ?> </td> <td><?php echo $listing_asin; ?> </td> <td style="text-align:right;"> <?php if ($row['quantity']) { echo $row['quantity']; } elseif (isset($row['fulfillment-channel']) && $row['fulfillment-channel'] != 'DEFAULT') {
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 processReportData($id) { $report = new WPLA_AmazonReport($id); // $data = $report->data; $rows = $report->get_data_rows(); $lm = new WPLA_ListingsModel(); foreach ($rows as $row) { $lm->updateItemFromReportCSV($row, $report->account_id); } $msg = 'Imported: ' . $lm->imported_count . '<br>'; $msg .= 'Updated: ' . $lm->updated_count . '<br>'; $this->showMessage($msg); }
public function jobs_load_tasks() { // quit if no job name provided if (!isset($_REQUEST['job'])) { return false; } $jobname = $_REQUEST['job']; // check if an array of listing IDs was provided $lm = new WPLA_ListingsModel(); $listing_ids = isset($_REQUEST['item_ids']) && is_array($_REQUEST['item_ids']) ? $_REQUEST['item_ids'] : false; if ($listing_ids) { $items = $lm->getItemsByIdArray($listing_ids); } // register shutdown handler global $wpla_shutdown_handler_enabled; $wpla_shutdown_handler_enabled = true; register_shutdown_function(array($this, 'shutdown_handler')); // handle job name switch ($jobname) { case 'updateProductsWithoutASIN': // get prepared items $sm = new WPLA_ListingsModel(); $items = $sm->getAllOnlineWithoutASIN(); // create job from items and send response $response = $this->_create_bulk_listing_job('updateProduct', $items, $jobname); $this->returnJSON($response); exit; case 'createAllImportedProducts': // get prepared items $sm = new WPLA_ListingsModel(); $items = $sm->getAllImported(); // DEV: limit to 10 tasks at a time *** // $items = array_slice($items, 0, 10, true); // create job from items and send response $response = $this->_create_bulk_listing_job('createProduct', $items, $jobname); $this->returnJSON($response); exit; case 'processAmazonReport': // get report $id = $_REQUEST['item_id']; $report = new WPLA_AmazonReport($id); $rows = $report->get_data_rows(); $rows_count = sizeof($rows); $page_size = 500; $number_of_pages = intval($rows_count / $page_size) + 1; $items = array(); if ($number_of_pages > 0) { for ($page = 0; $page < $number_of_pages; $page++) { $from_row = $page * $page_size + 1; $to_row = ($page + 1) * $page_size; if ($to_row > $rows_count) { $to_row = $rows_count; } $items[] = array('id' => $id, 'page' => $page, 'from_row' => $from_row, 'to_row' => $to_row, 'title' => 'Processing rows ' . $from_row . ' to ' . $to_row); } } // create job from items and send response $response = $this->_create_bulk_listing_job('processReportPage', $items, $jobname); $this->returnJSON($response); exit; case 'processRowsFromAmazonReport': $id = $_REQUEST['report_id']; $skus = $_REQUEST['sku_list']; foreach ($skus as $sku) { $items[] = array('id' => $id, 'sku' => $sku, 'title' => 'Processing SKU ' . $sku); } // create job from items and send response $response = $this->_create_bulk_listing_job('processSingleSkuFromReport', $items, $jobname); $this->returnJSON($response); exit; case 'fetchProductDescription': // create job from items and send response $response = $this->_create_bulk_listing_job('fetchFullProductDescription', $items, $jobname); $this->returnJSON($response); exit; default: // echo "unknown job"; // break; } // exit(); }
public function getListingURL($listing_id) { $lm = new WPLA_ListingsModel(); $item = $lm->getItem($listing_id); // build listing URL $listing_url = 'http://www.amazon.com/dp/' . $item['asin'] . '/'; if ($item['account_id']) { $account = new WPLA_AmazonAccount($item['account_id']); $market = new WPLA_AmazonMarket($account->market_id); $listing_url = 'http://www.' . $market->url . '/dp/' . $item['asin'] . '/'; } return $listing_url; }
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 update_products_on_shutdown() { // get queue $collected_products = get_option('wpla_updated_products_queue', array()); if (!is_array($collected_products)) { $collected_products = array(); } // DEBUG WPLA()->logger->info("CSV: update_products_on_shutdown() - collected_products: " . print_r($collected_products, 1)); // mark each queued product as modified $lm = new WPLA_ListingsModel(); foreach ($collected_products as $post_id) { // do_action( 'wpla_product_has_changed', $post_id ); $lm->markItemAsModified($post_id, true); // set $skip_updating_feeds = true } // clear queue delete_option('wpla_updated_products_queue'); // update pending feeds - after all items have been updated if (!empty($collected_products)) { WPLA_AmazonFeed::updatePendingFeeds(); } }
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; }
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); } }
public function importASINs() { $asin_list = trim($_REQUEST['wpla_asin_list']); if (!$asin_list) { $this->showMessage('You need to enter a least one ASIN to import.', 1); return false; } $lm = new WPLA_ListingsModel(); $import_account_id = $_REQUEST['wpla_import_account_id']; if (!$import_account_id) { $import_account_id = get_option('wpla_default_account_id', 1); } $asin_array = explode("\n", $asin_list); foreach ($asin_array as $ASIN) { $ASIN = trim($ASIN); if (!$ASIN) { continue; } $row = array(); $row['asin'] = $ASIN; $row['seller-sku'] = $ASIN; $row['item-name'] = $ASIN . ' (import to fetch title from Amazon)'; $row['open-date'] = date('Y-m-d H:i:s'); $row['item-description'] = ''; $row['fulfillment-channel'] = ''; $row['quantity'] = 0; $row['price'] = 0; $row['source'] = 'foreign_import'; $lm->updateItemFromReportCSV($row, $import_account_id); // $this->showMessage('Product '.$ASIN.' was prepared for import.'); } if ($lm->imported_count) { $this->showMessage($lm->imported_count . ' new products were prepared for import.'); } if ($lm->updated_count) { $this->showMessage($lm->updated_count . ' ASINs already exist and have been skipped.'); } return $lm->imported_count + $lm->updated_count; }
public function update_pricing_info_for_asins($listing_ASINs, $account_id) { $listingsModel = new WPLA_ListingsModel(); // fetch Buy Box pricing info and process result $api = new WPLA_AmazonAPI($account_id); $result = $api->getCompetitivePricingForId($listing_ASINs); $listingsModel->processBuyBoxPricingResult($result); // return if lowest offers are disabled // if ( ! get_option('wpla_repricing_use_lowest_offer') ) return; // fetch Lowest Offer info and process result $api = new WPLA_AmazonAPI($account_id); $result = $api->getLowestOfferListingsForASIN($listing_ASINs); $listingsModel->processLowestOfferPricingResult($result); }
public function checkSoldStock() { // get all published listings $lm = new WPLA_ListingsModel(); $listings = $lm->getWhere('status', 'sold'); $out_of_stock_products = array(); // process published listings foreach ($listings as $item) { // get wc product $_product = $this->getProduct($item['post_id']); // checking parent variations makes no sense in WPLA, so skip them if ($_product->product_type == 'variable') { continue; } // check stock level // $stock = WPLA_ProductWrapper::getStock( $item['post_id'] ); $stock = $_product ? $_product->get_total_stock() : 0; if ($stock == 0) { continue; } // mark listing as changed // if ( isset( $_REQUEST['mark_as_changed'] ) ) { // $lm->updateListing( $item['id'], array( 'status' => 'changed' ) ); // $item['status'] = 'changed'; // } // add to list of out of stock products $item['stock'] = $stock; $item['exists'] = $_product ? true : false; $item['parent_id'] = $_product->product_type == 'variation' ? $_product->parent->id : false; $out_of_stock_products[] = $item; } // return if empty if (empty($out_of_stock_products)) { WPLA()->showMessage('No sold products have stock in WooCommerce.', 0, 1); return; } $msg = '<p>'; $msg .= 'Warning: Some sold listings are still in stock in WooCommerce.'; $msg .= '</p>'; // table header $msg .= '<table style="width:100%">'; $msg .= "<tr>"; $msg .= "<th style='text-align:left'>Stock</th>"; $msg .= "<th style='text-align:left'>SKU</th>"; $msg .= "<th style='text-align:left'>Product</th>"; $msg .= "<th style='text-align:left'>Qty</th>"; $msg .= "<th style='text-align:left'>ASIN</th>"; $msg .= "<th style='text-align:left'>Ended at</th>"; $msg .= "<th style='text-align:left'>Status</th>"; $msg .= "</tr>"; // table rows foreach ($out_of_stock_products as $item) { // get column data // $qty = $item['quantity'] - $item['quantity_sold']; $sku = $item['sku']; $qty = $item['quantity']; $stock = $item['stock'] . ' x '; $title = $item['listing_title']; $post_id = $item['post_id']; $asin = $item['asin']; $status = $item['status']; $exists = $item['exists']; $date_ended = $item['date_finished'] ? $item['date_finished'] : $item['end_date']; // build links $amazon_url = $item['ViewItemURL'] ? $item['ViewItemURL'] : ($amazon_url = 'http://www.amazon.com/itm/' . $asin); $amazon_url = 'admin.php?page=wpla&s=' . $asin; $amazon_link = '<a href="' . $amazon_url . '" target="_blank">' . $asin . '</a>'; $edit_link = '<a href="post.php?action=edit&post=' . ($item['parent_id'] ? $item['parent_id'] : $post_id) . '" target="_blank">' . $title . '</a>'; // mark non existent products if (!$exists) { $stock = 'N/A'; $post_id .= ' missing!'; } // build table row $msg .= "<tr>"; $msg .= "<td>{$stock}</td>"; $msg .= "<td>{$sku}</td>"; $msg .= "<td>{$edit_link} (ID {$post_id})</td>"; $msg .= "<td>{$qty} x </td>"; $msg .= "<td>{$amazon_link}</td>"; $msg .= "<td>{$date_ended}</td>"; $msg .= "<td>{$status}</td>"; $msg .= "</tr>"; } $msg .= '</table>'; // show 'check again' button $msg .= '<p>'; $url = 'admin.php?page=wpla-tools&action=check_wc_sold_stock&_wpnonce=' . wp_create_nonce('wpla_tools_page'); $msg .= '<a href="' . $url . '" class="button">' . __('Check again', 'wpla') . '</a> '; $msg .= '</p>'; // $msg .= '<p>'; // $url = 'admin.php?page=wpla-tools&action=check_wc_out_of_stock&mark_as_changed=yes&_wpnonce='.wp_create_nonce('wpla_tools_page'); // $msg .= '<a href="'.$url.'" class="button">'.__('Mark all as changed','wpla').'</a> '; // $msg .= 'Click this button to mark all found listings as changed in WP-Lister.'; // $msg .= '</p>'; WPLA()->showMessage($msg, 1, 1); }
public function insertVariationListing($var, $product_node, $parent_listing, $account) { // get variation product data // $variation_id = $var['post_id']; // echo "<pre>";print_r($var);echo"</pre>";#die(); // generate title suffix from attribute values $suffix = join(', ', $var->attribute_values); // build single variation listing item $data = array(); $data['post_id'] = ''; // filled in after creating the product $data['parent_id'] = $parent_listing->post_id; $data['vtheme'] = $var->vtheme; $data['listing_title'] = $product_node->AttributeSets->ItemAttributes->Title . ' - ' . $suffix; // $data['post_content'] = $post->post_content; $data['price'] = $var->price; $data['quantity'] = $var->qty; $data['sku'] = $var->sku; $data['asin'] = $var->asin; $data['date_created'] = date('Y-m-d H:i:s', time()); $data['status'] = 'matched'; $data['source'] = 'foreign_import'; $data['account_id'] = $account->id; $data['product_type'] = 'variation'; // $data['profile_id'] = ''; $lm = new WPLA_ListingsModel(); $variation_listing_id = $lm->insertListingData($data); return $variation_listing_id; }
/** ************************************************************************ * REQUIRED! This is where you prepare your data for display. This method will * usually be used to query the database, sort and filter the data, and generally * get it ready to be displayed. At a minimum, we should set $this->items and * $this->set_pagination_args(), although the following properties and methods * are frequently interacted with here... * * @uses $this->_column_headers * @uses $this->items * @uses $this->get_columns() * @uses $this->get_sortable_columns() * @uses $this->get_pagenum() * @uses $this->set_pagination_args() **************************************************************************/ function prepare_items($items = false) { // process bulk actions $this->process_bulk_action(); // get pagination state $current_page = $this->get_pagenum(); $per_page = $this->get_items_per_page('listings_per_page', 20); // define columns $this->_column_headers = $this->get_column_info(); // fetch listings from model - if no parameter passed if (!$items) { $listingsModel = new WPLA_ListingsModel(); $this->items = $listingsModel->getPageItems($current_page, $per_page, 'repricing'); $this->total_items = $listingsModel->total_items; } else { $this->items = $items; $this->total_items = count($items); } // register our pagination options & calculations. $this->set_pagination_args(array('total_items' => $this->total_items, 'per_page' => $per_page, 'total_pages' => ceil($this->total_items / $per_page))); }
function customize_toolbar($wp_admin_bar) { // check if current user can manage listings if (!current_user_can('manage_amazon_listings')) { return; } // get stats about active and scheduled jobs $feeds_in_progress = get_option('wpla_feeds_in_progress', 0); $reports_in_progress = get_option('wpla_reports_in_progress', 0); $pending_feeds = get_option('wpla_db_version') > 0 ? WPLA_AmazonFeed::getAllPendingFeeds() : array(); $total_active_jobs = $feeds_in_progress + $reports_in_progress + sizeof($pending_feeds); if ($total_active_jobs) { add_action('admin_footer', array(&$this, 'print_admin_toolbar_styles')); } // top level 'Amazon' $extra_class = $total_active_jobs ? '-spinner' : ''; $args = array('id' => 'wpla_top', 'title' => __('Amazon', 'wpla'), 'href' => admin_url('admin.php?page=wpla'), 'meta' => array('class' => 'wpla-toolbar-top' . $extra_class)); $wp_admin_bar->add_node($args); // Activity Monitor $activity_title = sprintf(__('%s active tasks', 'wpla'), $total_active_jobs); $activity_title = $total_active_jobs ? $activity_title : __('No active tasks', 'wpla'); $args = array('id' => 'wpla_current_activity', 'title' => $activity_title, 'href' => '#', 'parent' => 'wpla_top', 'meta' => array('class' => 'wpla-toolbar-page wpla-activity-monitor')); $wp_admin_bar->add_node($args); // Activity: Reports $args = array('id' => 'wpla_current_reports', 'title' => __('Reports in progress', 'wpla') . ': ' . $reports_in_progress, 'href' => admin_url('admin.php?page=wpla-reports'), 'parent' => 'wpla_current_activity', 'meta' => array('class' => 'wpla-toolbar-page wpla-activity-monitor')); if ($reports_in_progress) { $wp_admin_bar->add_node($args); } // Activity: Feeds (submitted) $args = array('id' => 'wpla_current_feeds_submitted', 'title' => __('Feeds in progress', 'wpla') . ': ' . $feeds_in_progress, 'href' => admin_url('admin.php?page=wpla-feeds&feed_status=submitted'), 'parent' => 'wpla_current_activity', 'meta' => array('class' => 'wpla-toolbar-page wpla-activity-monitor')); if ($feeds_in_progress) { $wp_admin_bar->add_node($args); } // Activity: Feeds (pending) $args = array('id' => 'wpla_current_feeds_pending', 'title' => __('Scheduled feeds', 'wpla') . ': ' . sizeof($pending_feeds), 'href' => admin_url('admin.php?page=wpla-feeds&feed_status=pending'), 'parent' => 'wpla_current_activity', 'meta' => array('class' => 'wpla-toolbar-page wpla-activity-monitor')); if (!empty($pending_feeds)) { $wp_admin_bar->add_node($args); } // Listings page $args = array('id' => 'wpla_listings', 'title' => __('Listings', 'wpla'), 'href' => admin_url('admin.php?page=wpla'), 'parent' => 'wpla_top', 'meta' => array('class' => 'wpla-toolbar-page')); $wp_admin_bar->add_node($args); // Orders page $args = array('id' => 'wpla_orders', 'title' => __('Orders', 'wpla'), 'href' => admin_url('admin.php?page=wpla-orders'), 'parent' => 'wpla_top', 'meta' => array('class' => 'wpla-toolbar-page')); $wp_admin_bar->add_node($args); // Reports page $args = array('id' => 'wpla_reports', 'title' => __('Reports', 'wpla'), 'href' => admin_url('admin.php?page=wpla-reports'), 'parent' => 'wpla_top', 'meta' => array('class' => 'wpla-toolbar-page')); $wp_admin_bar->add_node($args); // Feeds page $args = array('id' => 'wpla_feeds', 'title' => __('Feeds', 'wpla'), 'href' => admin_url('admin.php?page=wpla-feeds'), 'parent' => 'wpla_top', 'meta' => array('class' => 'wpla-toolbar-page')); $wp_admin_bar->add_node($args); // Profiles page $args = array('id' => 'wpla_profiles', 'title' => __('Profiles', 'wpla'), 'href' => admin_url('admin.php?page=wpla-profiles'), 'parent' => 'wpla_top', 'meta' => array('class' => 'wpla-toolbar-page')); $wp_admin_bar->add_node($args); // Import page $args = array('id' => 'wpla_import', 'title' => __('Import', 'wpla'), 'href' => admin_url('admin.php?page=wpla-import'), 'parent' => 'wpla_top', 'meta' => array('class' => 'wpla-toolbar-page')); $wp_admin_bar->add_node($args); // Tools page $args = array('id' => 'wpla_tools', 'title' => __('Tools', 'wpla'), 'href' => admin_url('admin.php?page=wpla-tools'), 'parent' => 'wpla_top', 'meta' => array('class' => 'wpla-toolbar-page')); $wp_admin_bar->add_node($args); // Repricing Tool $args = array('id' => 'wpla_tools_repricing', 'title' => __('Repricing Tool', 'wpla'), 'href' => admin_url('admin.php?page=wpla-tools&tab=repricing'), 'parent' => 'wpla_tools', 'meta' => array('class' => 'wpla-toolbar-page')); $wp_admin_bar->add_node($args); // Inventory Check $args = array('id' => 'wpla_tools_inventory', 'title' => __('Inventory Check', 'wpla'), 'href' => admin_url('admin.php?page=wpla-tools&tab=inventory'), 'parent' => 'wpla_tools', 'meta' => array('class' => 'wpla-toolbar-page')); $wp_admin_bar->add_node($args); // SKU Generator $args = array('id' => 'wpla_tools_skugen', 'title' => __('SKU Generator', 'wpla'), 'href' => admin_url('admin.php?page=wpla-tools&tab=skugen'), 'parent' => 'wpla_tools', 'meta' => array('class' => 'wpla-toolbar-page')); $wp_admin_bar->add_node($args); // Developer Tools $args = array('id' => 'wpla_tools_developer', 'title' => __('Developer', 'wpla'), 'href' => admin_url('admin.php?page=wpla-tools&tab=developer'), 'parent' => 'wpla_tools', 'meta' => array('class' => 'wpla-toolbar-page')); $wp_admin_bar->add_node($args); if (current_user_can('manage_amazon_options')) { // Settings page $args = array('id' => 'wpla_settings', 'title' => __('Settings', 'wpla'), 'href' => admin_url('admin.php?page=wpla-settings'), 'parent' => 'wpla_top', 'meta' => array('class' => 'wpla-toolbar-page')); $wp_admin_bar->add_node($args); // Settings - General tab $args = array('id' => 'wpla_settings_general', 'title' => __('General Settings', 'wpla'), 'href' => admin_url('admin.php?page=wpla-settings&tab=settings'), 'parent' => 'wpla_settings', 'meta' => array('class' => 'wpla-toolbar-page')); $wp_admin_bar->add_node($args); // Settings - Accounts tab $args = array('id' => 'wpla_settings_accounts', 'title' => __('Accounts', 'wpla'), 'href' => admin_url('admin.php?page=wpla-settings&tab=accounts'), 'parent' => 'wpla_settings', 'meta' => array('class' => 'wpla-toolbar-page')); $wp_admin_bar->add_node($args); // Settings - Categories tab $args = array('id' => 'wpla_settings_categories', 'title' => __('Categories', 'wpla'), 'href' => admin_url('admin.php?page=wpla-settings&tab=categories'), 'parent' => 'wpla_settings', 'meta' => array('class' => 'wpla-toolbar-page')); $wp_admin_bar->add_node($args); // Settings - Advanced tab $args = array('id' => 'wpla_settings_advanced', 'title' => __('Advanced', 'wpla'), 'href' => admin_url('admin.php?page=wpla-settings&tab=advanced'), 'parent' => 'wpla_settings', 'meta' => array('class' => 'wpla-toolbar-page')); $wp_admin_bar->add_node($args); // Settings - Developer tab $args = array('id' => 'wpla_settings_developer', 'title' => __('Developer', 'wpla'), 'href' => admin_url('admin.php?page=wpla-settings&tab=developer'), 'parent' => 'wpla_settings', 'meta' => array('class' => 'wpla-toolbar-page')); $wp_admin_bar->add_node($args); } // if current_user_can('manage_amazon_options') if (current_user_can('manage_amazon_options') && get_option('wpla_log_to_db') == '1') { // Logs page $args = array('id' => 'wpla_log', 'title' => __('Logs', 'wpla'), 'href' => admin_url('admin.php?page=wpla-log'), 'parent' => 'wpla_top', 'meta' => array('class' => 'wpla-toolbar-page')); $wp_admin_bar->add_node($args); } // product page global $post; global $wp_query; global $pagenow; $post_id = false; if ($wp_query->in_the_loop && isset($wp_query->post->post_type) && $wp_query->post->post_type == 'product') { $post_id = $wp_query->post->ID; } elseif (is_object($post) && isset($post->post_type) && $post->post_type == 'product') { $post_id = $post->ID; } // skip product links on the main products page if ($pagenow == 'edit.php') { return; } // do we have a single product page? if (empty($post_id)) { return; } // enqueue ProductMatcher.js wp_register_script('wpla_product_matcher', WPLA_URL . '/js/classes/ProductMatcher.js?ver=' . time(), array('jquery')); wp_enqueue_script('wpla_product_matcher'); wp_localize_script('wpla_product_matcher', 'wpla_ProductMatcher_i18n', array('WPLA_URL' => WPLA_URL)); // get all items $lm = new WPLA_ListingsModel(); $listings = $lm->getAllItemsByPostOrParentID($post_id); if (sizeof($listings) > 0) { $asin = $lm->getASINFromPostID($post_id); // $url = $lm->getViewItemURLFromPostID( $post_id ); // View on Amazon link $args = array('id' => 'wpla_view_on_amazon', 'title' => __('View item on Amazon', 'wpla'), 'parent' => 'wpla_top', 'meta' => array('target' => '_blank', 'class' => 'wpla-toolbar-link')); if ($asin) { $wp_admin_bar->add_node($args); } foreach ($listings as $listing) { $listing_url = 'http://www.amazon.com/dp/' . $listing->asin . '/'; if ($listing->account_id) { $account = new WPLA_AmazonAccount($listing->account_id); $market = new WPLA_AmazonMarket($account->market_id); $listing_url = 'http://www.' . $market->url . '/dp/' . $listing->asin . '/'; } $args = array('id' => 'wpla_view_on_amazon_' . $listing->id, 'title' => '#' . $listing->asin . ': ' . $listing->listing_title, 'href' => $listing_url, 'parent' => 'wpla_view_on_amazon', 'meta' => array('target' => '_blank', 'class' => 'wpla-toolbar-link')); if ($listing_url) { $wp_admin_bar->add_node($args); } } // View in WP-Lister $url = admin_url('admin.php?page=wpla&s=' . $post_id); $args = array('id' => 'wpla_view_on_listings_page', 'title' => __('View item in WP-Lister', 'wpla'), 'href' => $url, 'parent' => 'wpla_top', 'meta' => array('target' => '_blank', 'class' => 'wpla-toolbar-link')); $wp_admin_bar->add_node($args); } else { // no listings // match product option $tb_url = admin_url('admin-ajax.php?action=wpla_show_product_matches&id=' . $post_id . '&width=640&height=420'); // echo '<a href="'.$tb_url.'" class="thickbox" title="Match product on Amazon"><img src="'.WPLA_URL.'/img/search3.png" alt="match" /></a>'; $onclick = 'tb_show("' . __('Match on Amazon', 'wpla') . '", "' . $tb_url . '");return false;'; $args = array('id' => 'wpla_match_on_amazon', 'title' => __('Match on Amazon', 'wpla'), 'href' => $tb_url, 'parent' => 'wpla_top', 'meta' => array('onclick' => $onclick, 'class' => 'wpla-toolbar-link')); $wp_admin_bar->add_node($args); // $args = $this->addPrepareActions( $args ); } // if ( current_user_can('prepare_amazon_listings') ) $this->addPrepareActions($wp_admin_bar, $post_id); }
public function deleteProfiles($profiles) { if (!is_array($profiles)) { $profiles = array($profiles); } $count = 0; foreach ($profiles as $id) { if (!$id) { continue; } // check if there are listings using this profile $lm = new WPLA_ListingsModel(); $listings = $lm->findAllListingsByColumn($id, 'profile_id'); if (!empty($listings)) { $this->showMessage('This profile is applied to ' . count($listings) . ' listings and can not be deleted.', 1, 1); continue; } $profile = new WPLA_AmazonProfile($id); $profile->delete(); $count++; } if ($count) { $this->showMessage(sprintf(__('%s profile(s) were removed.', 'wpla'), $count)); } }
public static function processQualityReportPage($report, $rows, $job, $task) { $listingsModel = new WPLA_ListingsModel(); // reset quality info for all products using this account $account_id = $report->account_id; $update_data = array('quality_status' => null, 'quality_info' => null); $listingsModel->updateWhere(array('account_id' => $account_id), $update_data); // process rows foreach ($rows as $row) { $asin = $row['asin']; $sku = $row['sku']; $quality_info = array('sku' => $row['sku'], 'product-name' => $row['product-name'], 'asin' => $row['asin'], 'field-name' => $row['field-name'], 'alert-type' => $row['alert-type'], 'current-value' => $row['current-value'], 'last-updated' => $row['last-updated'], 'alert-name' => $row['alert-name'], 'status' => $row['status'], 'explanation' => $row['explanation'], 'ts' => time()); $update_data = array('quality_status' => $row['alert-name'], 'quality_info' => serialize($quality_info)); if ($asin) { $listingsModel->updateWhere(array('asin' => $asin), $update_data); } if ($sku) { $listingsModel->updateWhere(array('sku' => $sku), $update_data); } } // build response $response = new stdClass(); $response->job = $job; $response->task = $task; $response->errors = ''; $response->success = true; return $response; }
public function displayRepricingPage() { // handle actions and show notes // $this->handleActions(); if ($this->requestAction() == 'wpla_apply_lowest_price_to_all_items') { $this->applyLowestPricesToAllItems(); } if ($this->requestAction() == 'wpla_resubmit_pnq_update') { $this->resubmitPnqUpdateForSelectedItems(); } if ($this->requestAction() == 'wpla_bulk_apply_lowest_prices') { $this->applyLowestPricesToSelectedItems(); } if ($this->requestAction() == 'wpla_bulk_apply_minmax_prices') { $this->applyMinMaxPrices(); } // handle bulk action - get_compet_price if ($this->requestAction() == 'get_compet_price') { WPLA()->pages['listings']->get_compet_price(); WPLA()->pages['listings']->get_lowest_offers(); } if ($this->requestAction() == 'wpla_resubmit_all_failed_prices') { $lm = new WPLA_ListingsModel(); $items = $lm->getWhere('pnq_status', -1); foreach ($items as $item) { // set pnq status to changed (1) $lm->updateWhere(array('id' => $item->id), array('pnq_status' => 1)); } $this->showMessage(sprintf(__('%s failed prices were scheduled for resubmission.', 'wpla'), count($items))); } // create table and fetch items to show $this->repricingTable = new WPLA_RepricingTable(); $this->repricingTable->prepare_items(); $active_tab = 'repricing'; $aData = array('plugin_url' => self::$PLUGIN_URL, 'message' => $this->message, 'listingsTable' => $this->repricingTable, 'default_account' => get_option('wpla_default_account_id'), 'tools_url' => 'admin.php?page=' . self::ParentMenuId . '-tools', 'form_action' => 'admin.php?page=' . self::ParentMenuId . '-tools' . '&tab=' . $active_tab); $this->display('tools_repricing', $aData); }
public function updateProductFromItem($item, $report_row) { global $woocommerce; WPLA()->logger->info("=============================================================================="); //WPLA()->logger->info( "updateProductFromItem() - ID: ".$data['asin'] ); // some shortcuts $asin = $item->asin; $product_id = $item->post_id; $amazon_name = $item->listing_title; $amazon_price = $item->price; $amazon_quantity = $item->quantity; $report_quantity = $report_row['quantity']; $updated = false; // get WC product for reference $product = $this->getProduct($product_id); if (!$product) { return; } // echo "<pre>";print_r($product);echo"</pre>";#die(); // get options $reports_update_woo_stock = get_option('wpla_reports_update_woo_stock', 1) == 1 ? true : false; $reports_update_woo_price = get_option('wpla_reports_update_woo_price', 1) == 1 ? true : false; $reports_update_woo_condition = get_option('wpla_reports_update_woo_condition', 1) == 1 ? true : false; // // update item-condition - if enabled // if ($reports_update_woo_condition) { $amazon_condition_type = WPLA_ImportHelper::convertNumericConditionIdToType($report_row['item-condition']); update_post_meta($product_id, '_amazon_condition_type', $amazon_condition_type); $amazon_condition_note = WPLA_ListingsModel::convertToUTF8($report_row['item-note']); update_post_meta($product_id, '_amazon_condition_note', $amazon_condition_note); WPLA()->logger->info("updated condition for product {$product_id}: {$amazon_condition_type} / " . $amazon_condition_note); // WPLA()->logger->info( "stored condition note: " . get_post_meta( $product_id, '_amazon_condition_note', true ) ); } // // update price - if enabled // if ($reports_update_woo_price) { // if this item has a profile, we need to apply the price modifiers to the product price $product_price = $product->price; $profile = $item->profile_id ? new WPLA_AmazonProfile($item->profile_id) : false; if ($profile) { $product_price = $profile->processProfilePrice($product_price); $amazon_price = $profile->reverseProfilePrice($amazon_price); } // update price - unless custom amazon price is set if ($product_price != $amazon_price) { if (!get_post_meta($product_id, '_amazon_price', true)) { update_post_meta($product_id, '_price', $amazon_price); update_post_meta($product_id, '_regular_price', $amazon_price); WPLA()->logger->info("updated price for product {$product_id} - new price: " . $amazon_price); $updated = true; } } } // if update price // // update stock - if enabled and the report quantity column is not empty // if ($reports_update_woo_stock && $report_quantity !== '' && $report_quantity !== false) { if ($product->stock != $amazon_quantity) { update_post_meta($product_id, '_stock', $amazon_quantity); WPLA()->logger->info("updated stock for product {$product_id} - new stock: " . $amazon_quantity); $updated = true; } // update out of stock attribute if ($amazon_quantity > 0) { $stock_status = 'instock'; } elseif ($item->product_type == 'variable') { $stock_status = 'instock'; } else { $stock_status = 'outofstock'; } update_post_meta($product_id, '_stock_status', $stock_status); } if ($updated) { // $woocommerce->clear_product_transients( $product_id ); if (function_exists('wc_delete_product_transients')) { wc_delete_product_transients($product_id); } WPLA()->logger->info("updated product {$product_id} ({$asin}): {$amazon_name} "); $this->updated_count++; } return $product_id; }
public function findMissingProducts() { $items = WPLA_ListingQueryHelper::findMissingProducts(); $mode = isset($_REQUEST['mode']) ? $_REQUEST['mode'] : false; if ($mode == 'delete') { foreach ($items as $item) { WPLA_ListingsModel::deleteItem($item->id); } wpla_show_message(sizeof($items) . ' items have been deleted.'); return; } if ($mode == 'import') { foreach ($items as $item) { $data = array('status' => 'imported'); WPLA_ListingsModel::updateWhere(array('id' => $item->id), $data); } wpla_show_message(sizeof($items) . ' items have been added to the import queue.'); return; } if (!empty($items)) { $nonce = wp_create_nonce('wpla_tools_page'); $btn_delete = '<a href="admin.php?page=wpla-tools&tab=inventory&action=wpla_check_for_missing_products&mode=delete&_wpnonce=' . $nonce . '" class="button button-small button-secondary">' . 'Delete all from DB' . '</a> '; $btn_import = '<a href="admin.php?page=wpla-tools&tab=inventory&action=wpla_check_for_missing_products&mode=import&_wpnonce=' . $nonce . '" class="button button-small button-primary" >' . 'Add to import queue' . '</a>'; $buttons = ' ' . $btn_delete . $btn_import; wpla_show_message('There are ' . sizeof($items) . ' listing(s) without a linked product in WooCommerce.' . $buttons, 'error'); } else { wpla_show_message('No missing products found.'); } }
public function renderDupeTable($listings, $column = 'post_id') { if (empty($listings)) { return ''; } // get current page with paging as url param $page = $_REQUEST['page']; if (isset($_REQUEST['paged'])) { $page .= '&paged=' . $_REQUEST['paged']; } $listingsModel = new WPLA_ListingsModel(); $msg = ''; foreach ($listings as $dupe) { $account_title = WPLA_AmazonAccount::getAccountTitle($dupe->account_id); $msg .= '<b>' . __('Listings for', 'wpla') . ' ' . strtoupper($column) . ' ' . $dupe->{$column} . ' (' . $account_title . '):</b>'; $msg .= '<br>'; $duplicateListings = $listingsModel->findAllListingsByColumn($dupe->{$column}, $column, $dupe->account_id); $msg .= '<table style="width:100%">'; foreach ($duplicateListings as $listing) { $color = $listing->status == 'archived' ? 'silver' : ''; // check if WooCommerce SKU matches Amazon SKU $woo_sku = get_post_meta($listing->post_id, '_sku', true); $sku_label = $listing->sku == $woo_sku ? $woo_sku : '<span style="color:darkred">' . $woo_sku . ' / ' . $listing->sku . '</span>'; $msg .= '<tr><td style="width:40%;">'; $msg .= '<span style="color:' . $color . '">'; $msg .= $listing->listing_title; $msg .= '</span>'; $msg .= '</td><td style="width:10%;">'; $msg .= '<i style="color:silver">' . $listing->product_type . '</i>'; $msg .= '</td><td style="width:10%;">'; $msg .= '<a href="admin.php?page=wpla&s=' . $listing->sku . '" title="SKU" target="_blank">'; $msg .= $sku_label . '</a>'; $msg .= '</td><td style="width:10%;">'; $msg .= '<a href="admin.php?page=wpla&s=' . $listing->asin . '" title="ASIN" target="_blank">'; $msg .= $listing->asin . '</a>'; $msg .= '</td><td style="width:10%;">'; $msg .= '<a href="admin.php?page=wpla&s=' . $listing->post_id . '" title="Product ID" target="_blank">'; $msg .= 'ID ' . $listing->post_id . '</a>'; $msg .= '</td><td style="width:10%;">'; $msg .= '<i>' . $listing->status . '</i>'; // if ( in_array( $listing->status, array( 'prepared', 'verified', 'ended', 'sold' ) ) ) { // $archive_link = sprintf('<a class="archive button button-small" href="?page=%s&action=%s&listing=%s">%s</a>',$page,'archive',$listing->id,__('Click to move to archive','wpla')); // $msg .= ' '.$archive_link; // $msg .= '<br>'; // } $msg .= '</td><td align="right" style="width:10%;">'; $delete_btn = sprintf('<a class="delete button button-small button-secondary" href="?page=%s&action=%s&listing=%s">%s</a>', $page, 'delete', $listing->id, __('Remove from database', 'wpla')); $msg .= $delete_btn; $msg .= '</td></tr>'; } $msg .= '</table>'; $msg .= '<br>'; } return $msg; }