Stock reports

This commit is contained in:
Mike Jolley 2013-07-09 11:48:56 +01:00
parent 225f770cab
commit aa41255596
7 changed files with 265 additions and 63 deletions

View File

@ -113,8 +113,20 @@ class WC_Admin_Reports {
'stock' => array(
'title' => __( 'Stock', 'woocommerce' ),
'reports' => array(
"stock" => array(
'title' => __( 'Stock', 'woocommerce' ),
"low_in_stock" => array(
'title' => __( 'Low in stock', 'woocommerce' ),
'description' => '',
'hide_title' => true,
'callback' => array( $this, 'get_report' )
),
"out_of_stock" => array(
'title' => __( 'Out of stock', 'woocommerce' ),
'description' => '',
'hide_title' => true,
'callback' => array( $this, 'get_report' )
),
"most_stocked" => array(
'title' => __( 'Most Stocked', 'woocommerce' ),
'description' => '',
'hide_title' => true,
'callback' => array( $this, 'get_report' )

View File

@ -0,0 +1,54 @@
<?php
if ( ! defined( 'ABSPATH' ) )
exit; // Exit if accessed directly
if ( ! class_exists( 'WC_Report_Stock' ) )
require_once( 'class-wc-report-stock.php' );
/**
* WC_Report_Low_In_Stock class
*
* @extends WC_Report_Stock
*/
class WC_Report_Low_In_Stock extends WC_Report_Stock {
/**
* No items found text
*/
public function no_items() {
_e( 'No low in stock products found.', 'woocommerce' );
}
/**
* Get Products matching stock criteria
*
* @access public
*/
public function get_items( $current_page, $per_page ) {
global $wpdb;
$this->max_items = 0;
$this->items = array();
// Get products using a query - this is too advanced for get_posts :(
$stock = absint( max( get_option( 'woocommerce_notify_low_stock_amount' ), 1 ) );
$nostock = absint( max( get_option( 'woocommerce_notify_no_stock_amount' ), 0 ) );
$query_from = "FROM {$wpdb->posts} as posts
INNER JOIN {$wpdb->postmeta} AS postmeta ON posts.ID = postmeta.post_id
INNER JOIN {$wpdb->postmeta} AS postmeta2 ON posts.ID = postmeta2.post_id
WHERE 1=1
AND posts.post_type IN ('product', 'product_variation')
AND posts.post_status = 'publish'
AND (
postmeta.meta_key = '_stock' AND CAST(postmeta.meta_value AS SIGNED) <= '{$stock}' AND CAST(postmeta.meta_value AS SIGNED) > '{$nostock}' AND postmeta.meta_value != ''
)
AND (
( postmeta2.meta_key = '_manage_stock' AND postmeta2.meta_value = 'yes' ) OR ( posts.post_type = 'product_variation' )
)
";
$this->items = $wpdb->get_results( $wpdb->prepare( "SELECT posts.ID as id, posts.post_parent as parent {$query_from} GROUP BY posts.ID ORDER BY posts.post_title DESC LIMIT %d, %d;", ( $current_page - 1 ) * $per_page, $per_page ) );
$this->max_items = $wpdb->get_var( "SELECT COUNT( DISTINCT posts.ID ) {$query_from};" );
}
}

View File

@ -0,0 +1,46 @@
<?php
if ( ! defined( 'ABSPATH' ) )
exit; // Exit if accessed directly
if ( ! class_exists( 'WC_Report_Stock' ) )
require_once( 'class-wc-report-stock.php' );
/**
* WC_Report_Most_Stocked class
*
* @extends WC_Report_Stock
*/
class WC_Report_Most_Stocked extends WC_Report_Stock {
/**
* Get Products matching stock criteria
*
* @access public
*/
public function get_items( $current_page, $per_page ) {
global $wpdb;
$this->max_items = 0;
$this->items = array();
// Get products using a query - this is too advanced for get_posts :(
$stock = absint( max( get_option( 'woocommerce_notify_low_stock_amount' ), 0 ) );
$query_from = "FROM {$wpdb->posts} as posts
INNER JOIN {$wpdb->postmeta} AS postmeta ON posts.ID = postmeta.post_id
INNER JOIN {$wpdb->postmeta} AS postmeta2 ON posts.ID = postmeta2.post_id
WHERE 1=1
AND posts.post_type IN ('product', 'product_variation')
AND posts.post_status = 'publish'
AND (
postmeta.meta_key = '_stock' AND CAST(postmeta.meta_value AS SIGNED) > '{$stock}' AND postmeta.meta_value != ''
)
AND (
( postmeta2.meta_key = '_manage_stock' AND postmeta2.meta_value = 'yes' ) OR ( posts.post_type = 'product_variation' )
)
";
$this->items = $wpdb->get_results( $wpdb->prepare( "SELECT posts.ID as id, posts.post_parent as parent {$query_from} GROUP BY posts.ID ORDER BY CAST(postmeta.meta_value AS SIGNED) DESC LIMIT %d, %d;", ( $current_page - 1 ) * $per_page, $per_page ) );
$this->max_items = $wpdb->get_var( "SELECT COUNT( DISTINCT posts.ID ) {$query_from};" );
}
}

View File

@ -0,0 +1,53 @@
<?php
if ( ! defined( 'ABSPATH' ) )
exit; // Exit if accessed directly
if ( ! class_exists( 'WC_Report_Stock' ) )
require_once( 'class-wc-report-stock.php' );
/**
* WC_Report_Out_Of_Stock class
*
* @extends WC_Report_Stock
*/
class WC_Report_Out_Of_Stock extends WC_Report_Stock {
/**
* No items found text
*/
public function no_items() {
_e( 'No out of stock products found.', 'woocommerce' );
}
/**
* Get Products matching stock criteria
*
* @access public
*/
public function get_items( $current_page, $per_page ) {
global $wpdb;
$this->max_items = 0;
$this->items = array();
// Get products using a query - this is too advanced for get_posts :(
$stock = absint( max( get_option( 'woocommerce_notify_no_stock_amount' ), 0 ) );
$query_from = "FROM {$wpdb->posts} as posts
INNER JOIN {$wpdb->postmeta} AS postmeta ON posts.ID = postmeta.post_id
INNER JOIN {$wpdb->postmeta} AS postmeta2 ON posts.ID = postmeta2.post_id
WHERE 1=1
AND posts.post_type IN ('product', 'product_variation')
AND posts.post_status = 'publish'
AND (
postmeta.meta_key = '_stock' AND CAST(postmeta.meta_value AS SIGNED) <= '{$stock}' AND postmeta.meta_value != ''
)
AND (
( postmeta2.meta_key = '_manage_stock' AND postmeta2.meta_value = 'yes' ) OR ( posts.post_type = 'product_variation' )
)
";
$this->items = $wpdb->get_results( $wpdb->prepare( "SELECT posts.ID as id, posts.post_parent as parent {$query_from} GROUP BY posts.ID ORDER BY posts.post_title DESC LIMIT %d, %d;", ( $current_page - 1 ) * $per_page, $per_page ) );
$this->max_items = $wpdb->get_var( "SELECT COUNT( DISTINCT posts.ID ) {$query_from};" );
}
}

View File

@ -15,7 +15,7 @@ class WC_Report_Stock extends WP_List_Table {
*
* @access public
*/
function __construct(){
public function __construct(){
parent::__construct( array(
'singular' => __( 'Stock', 'woocommerce' ),
'plural' => __( 'Stock', 'woocommerce' ),
@ -23,10 +23,20 @@ class WC_Report_Stock extends WP_List_Table {
) );
}
/**
* No items found text
*/
public function no_items() {
_e( 'No products found.', 'woocommerce' );
}
/**
* Don't need this
*/
function display_tablenav() {}
public function display_tablenav( $position ) {
if ( $position != 'top' )
parent::display_tablenav( $position );
}
/**
* Output the report
@ -42,25 +52,78 @@ class WC_Report_Stock extends WP_List_Table {
* column_default function.
*
* @access public
* @param mixed $user
* @param mixed $item
* @param mixed $column_name
*/
function column_default( $product_id, $column_name ) {
function column_default( $item, $column_name ) {
global $woocommerce, $wpdb, $product;
if ( ! $product || $product->id !== $product_id )
$product = get_product( $product_id );
if ( ! $product || $product->id !== $item->id )
$product = get_product( $item->id );
switch( $column_name ) {
case 'stock_status' :
break;
case 'product' :
if ( $sku = $product->get_sku() )
echo $sku . ' - ';
echo $product->get_title();
// Get variation data
if ( $product->is_type( 'variation' ) ) {
$list_attributes = array();
$attributes = $product->get_variation_attributes();
foreach ( $attributes as $name => $attribute ) {
$list_attributes[] = $woocommerce->get_helper( 'attribute' )->attribute_label( str_replace( 'attribute_', '', $name ) ) . ': <strong>' . $attribute . '</strong>';
}
echo '<div class="description">' . implode( ', ', $list_attributes ) . '</div>';
}
break;
case 'parent' :
if ( $item->parent )
echo get_the_title( $item->parent );
else
echo '-';
break;
case 'stock_status' :
if ( $product->is_in_stock() ) {
echo '<mark class="instock">' . __( 'In stock', 'woocommerce' ) . '</mark>';
} else {
echo '<mark class="outofstock">' . __( 'Out of stock', 'woocommerce' ) . '</mark>';
}
break;
case 'stock_level' :
echo $product->get_stock_quantity();
break;
case 'wc_actions' :
?><p>
<?php
$actions = array();
$action_id = $product->is_type( 'variation' ) ? $item->parent : $item->id;
$actions['edit'] = array(
'url' => admin_url( 'post.php?post=' . $action_id . '&action=edit' ),
'name' => __( 'Edit', 'woocommerce' ),
'action' => "edit"
);
if ( $product->is_visible() )
$actions['view'] = array(
'url' => get_permalink( $action_id ),
'name' => __( 'View', 'woocommerce' ),
'action' => "view"
);
$actions = apply_filters( 'woocommerce_admin_stock_report_product_actions', $actions, $product );
foreach ( $actions as $action ) {
$image = ( isset( $action['image_url'] ) ) ? $action['image_url'] : $woocommerce->plugin_url() . '/assets/images/icons/' . $action['action'] . '.png';
printf( '<a class="button tips" href="%s" data-tip="%s"><img src="%s" alt="%s" width="14" /></a>', esc_url( $action['url'] ), esc_attr( $action['name'] ), esc_attr( $image ), esc_attr( $action['name'] ) );
}
?>
</p><?php
break;
}
}
@ -71,9 +134,11 @@ class WC_Report_Stock extends WP_List_Table {
*/
function get_columns(){
$columns = array(
'stock_status' => __( 'Stock Status', 'woocommerce' ),
'product' => __( 'Product', 'woocommerce' ),
'stock_level' => __( 'Units in stock', 'woocommerce' ),
'product' => __( 'Product', 'woocommerce' ),
'parent' => __( 'Parent', 'woocommerce' ),
'stock_level' => __( 'Units in stock', 'woocommerce' ),
'stock_status' => __( 'Stock status', 'woocommerce' ),
'wc_actions' => __( 'Actions', 'woocommerce' ),
);
return $columns;
@ -85,56 +150,19 @@ class WC_Report_Stock extends WP_List_Table {
* @access public
*/
public function prepare_items() {
global $wpdb;
$current_page = 1;
$per_page = 999999999999;
/**
* Init column headers
*/
$this->_column_headers = array( $this->get_columns(), array(), $this->get_sortable_columns() );
$current_page = absint( $this->get_pagenum() );
$per_page = 20;
$this->get_items( $current_page, $per_page );
/**
* Get Products
* Pagination
*/
// Low/No stock lists
$lowstockamount = get_option('woocommerce_notify_low_stock_amount');
if (!is_numeric($lowstockamount)) $lowstockamount = 1;
$nostockamount = get_option('woocommerce_notify_no_stock_amount');
if (!is_numeric($nostockamount)) $nostockamount = 0;
// Get low in stock simple/downloadable/virtual products. Grouped don't have stock. Variations need a separate query.
$args = array(
'post_type' => 'product',
'post_status' => 'publish',
'posts_per_page' => -1,
'meta_query' => array(
array(
'key' => '_manage_stock',
'value' => 'yes'
),
array(
'key' => '_stock',
'value' => $lowstockamount,
'compare' => '<=',
'type' => 'NUMERIC'
)
),
'tax_query' => array(
array(
'taxonomy' => 'product_type',
'field' => 'name',
'terms' => array('simple'),
'operator' => 'IN'
)
),
'fields' => 'id=>parent'
);
$low_stock_products = array_flip( (array) get_posts($args) );
$this->items = $low_stock_products;
$this->set_pagination_args( array(
'total_items' => $this->max_items,
'per_page' => $per_page,
'total_pages' => ceil( $this->max_items / $per_page )
) );
}
}

File diff suppressed because one or more lines are too long

View File

@ -1057,7 +1057,7 @@ ul.wc_coupon_list_block {
.column-last_order {
width: 11%;
}
.column-order_actions, .column-user_actions {
.column-order_actions, .column-user_actions, .column-wc_actions {
width:110px;
a.button {
float:left;
@ -2586,6 +2586,15 @@ img.ui-datepicker-trigger { vertical-align: middle; margin-top: -1px; cursor: po
overflow: hidden;
zoom: 1;
}
.widefat {
td {
vertical-align: top;
padding: 7px 7px;
.description {
margin: 4px 0 0 0;
}
}
}
.postbox {
&:after {
content: ".";