Skip to content

Commit

Permalink
v3.2.1
Browse files Browse the repository at this point in the history
  • Loading branch information
pablo-sg-pacheco committed Dec 28, 2023
1 parent 58a5cd0 commit 934fc6b
Show file tree
Hide file tree
Showing 9 changed files with 325 additions and 130 deletions.
2 changes: 1 addition & 1 deletion cost-of-goods-for-woocommerce.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Plugin Name: Cost of Goods for WooCommerce
Plugin URI: https://wpfactory.com/item/cost-of-goods-for-woocommerce/
Description: Save product purchase costs (cost of goods) in WooCommerce. Beautifully.
Version: 3.2.0
Version: 3.2.1
Author: WPFactory
Author URI: https://wpfactory.com
Text Domain: cost-of-goods-for-woocommerce
Expand Down
26 changes: 24 additions & 2 deletions includes/alg-wc-cog-functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
/**
* Cost of Goods for WooCommerce - Functions.
*
* @version 2.9.5
* @since 1.4.0
* @version 3.2.1
* @since 3.2.1
* @author WPFactory
*/

Expand Down Expand Up @@ -351,4 +351,26 @@ function alg_wc_cog_get_cost_subtracting_tax_rate( $args = null ) {
}
return $cost / ( 1 + ( $tax_rate->tax_rate / 100 ) );
}
}

if ( ! function_exists( 'alg_wc_cog_generate_wpdb_prepare_placeholders_from_array' ) ) {
/**
* alg_wc_cog_generate_wpdb_prepare_placeholders_from_array.
*
* @link https://stackoverflow.com/a/72147500/1193038
*
* @version 3.2.1
* @since 3.2.1
*
* @param $array
*
* @return string
*/
function alg_wc_cog_generate_wpdb_prepare_placeholders_from_array( $array ) {
$placeholders = array_map( function ( $item ) {
return is_string( $item ) ? '%s' : ( is_float( $item ) ? '%f' : ( is_int( $item ) ? '%d' : '' ) );
}, $array );

return '(' . join( ',', $placeholders ) . ')';
}
}
2 changes: 1 addition & 1 deletion includes/analytics/build/index.asset.php
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<?php return array('dependencies' => array('wc-currency', 'wp-hooks', 'wp-i18n'), 'version' => 'c0714b7b3b4e9ba7bd0dc855ff0ee60a');
<?php return array('dependencies' => array('wc-currency', 'wp-hooks', 'wp-i18n'), 'version' => '444b8115c92b726d04d1c79a8cbfef62');
2 changes: 1 addition & 1 deletion includes/analytics/build/index.js

Large diffs are not rendered by default.

181 changes: 178 additions & 3 deletions includes/analytics/class-alg-wc-cog-analytics-stock.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/**
* Cost of Goods for WooCommerce - Analytics - Stock.
*
* @version 2.5.5
* @version 3.2.1
* @since 2.4.5
* @author WPFactory
*/
Expand All @@ -25,7 +25,7 @@ class Alg_WC_Cost_of_Goods_Analytics_Stock {
/**
* Constructor.
*
* @version 2.4.5
* @version 3.2.1
* @since 2.4.5
*
* @todo Add cost and profit totals on summary.
Expand All @@ -41,6 +41,180 @@ function __construct() {
add_filter( 'woocommerce_report_stock_prepare_export_item', array( $this, 'export_columns_values' ), 10, 2 );
// COG Filter (Filter products with costs).
add_filter( 'posts_join', array( $this, 'get_only_products_with_costs' ), 10, 2 );
// Calculate total cost and profit.
add_filter( 'woocommerce_analytics_stock_stats_query', array( $this, 'get_total_cost_and_profit' ) );
// Delete stock cost and profit totals from cache
add_action( 'woocommerce_update_product', array( $this, 'clear_stock_cost_and_profit_totals_cache' ) );
add_action( 'woocommerce_new_product', array( $this, 'clear_stock_cost_and_profit_totals_cache' ) );
add_action( 'update_option_woocommerce_notify_low_stock_amount', array( $this, 'clear_stock_cost_and_profit_totals_cache' ) );
add_action( 'update_option_woocommerce_notify_no_stock_amount', array( $this, 'clear_stock_cost_and_profit_totals_cache' ) );
}

/**
* clear_stock_cost_and_profit_totals_cache.
*
* @version 3.2.1
* @since 3.2.1
*
* @return void
*/
function clear_stock_cost_and_profit_totals_cache() {
global $wpdb;
$prefix = '_transient_alg_wc_cog_scpt_';
$meta_key_pattern = $wpdb->esc_like( $prefix ) . '%';
$query = $wpdb->prepare( "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s", $meta_key_pattern );
$wpdb->query( $query );
}

/**
* get_total_cost_and_profit.
*
* @version 3.2.1
* @since 3.2.1
*
* @param $query_results
*
* @return mixed
*/
function get_total_cost_and_profit( $query_results ) {
if ( 'yes' !== get_option( 'alg_wc_cog_cost_and_profit_enabled_on_analytics_stock', 'no' ) ) {
return $query_results;
}
$args = array(
'type' => isset( $_REQUEST['type'] ) ? $_REQUEST['type'] : ''
);
$type = $args['type'];
if ( ! in_array( $type, array( 'lowstock', 'instock', 'onbackorder', 'outofstock' ) ) ) {
$type = '';
}

$transient_name = 'alg_wc_cog_scpt_' . md5( maybe_serialize( $args ) );
if ( false === ( $total_cost_and_profit_info = get_transient( $transient_name ) ) ) {
$filtered_product_ids = array();
if ( 'lowstock' === $type ) {
$filtered_product_ids = $this->get_low_stock_product_ids();
} else {
$filtered_product_ids = $this->get_product_ids_by_stock_status( $type );
}
$total_cost_and_profit_info = $this->get_total_cost_and_profit_from_database( $filtered_product_ids );
set_transient( $transient_name, $total_cost_and_profit_info );
}

if ( ! empty( $total_cost_and_profit_info ) ) {
$query_results['cost'] = $total_cost_and_profit_info['cost'];
$query_results['cost_with_qty'] = $total_cost_and_profit_info['cost_with_qty'];
$query_results['profit'] = $total_cost_and_profit_info['profit'];
$query_results['profit_with_qty'] = $total_cost_and_profit_info['profit_with_qty'];
}

return $query_results;
}

/**
* get_total_cost_and_profit_from_database.
*
* @version 3.2.1
* @since 3.2.1
*
* @param $post_ids
*
* @return array|object|stdClass|null
*/
function get_total_cost_and_profit_from_database( $post_ids = array() ) {
global $wpdb;

$query = "
SELECT COUNT(DISTINCT posts.ID) as total_products, SUM(alg_wc_cog_cost_pm.meta_value) AS cost, SUM(alg_wc_cog_cost_pm.meta_value * IFNULL(stock_pm.meta_value, 1)) AS cost_with_qty, SUM(alg_wc_cog_profit_pm.meta_value) AS profit, SUM(alg_wc_cog_profit_pm.meta_value * IFNULL(stock_pm.meta_value, 1)) AS profit_with_qty, SUM(IFNULL(stock_pm.meta_value, 1)) AS stock
FROM {$wpdb->posts} posts
LEFT JOIN {$wpdb->postmeta} alg_wc_cog_cost_pm ON posts.ID = alg_wc_cog_cost_pm.post_id and alg_wc_cog_cost_pm.meta_key = '_alg_wc_cog_cost'
LEFT JOIN {$wpdb->postmeta} alg_wc_cog_profit_pm ON posts.ID = alg_wc_cog_profit_pm.post_id and alg_wc_cog_profit_pm.meta_key = '_alg_wc_cog_profit'
LEFT JOIN wp_postmeta stock_pm ON posts.ID = stock_pm.post_id AND stock_pm.meta_key = '_stock'
WHERE posts.post_type IN ( 'product', 'product_variation' )
AND alg_wc_cog_cost_pm.meta_value NOT IN ('',0) AND alg_wc_cog_profit_pm.meta_value NOT IN ('',0)
";

if ( ! empty( $post_ids ) ) {
$in_str = alg_wc_cog_generate_wpdb_prepare_placeholders_from_array( $post_ids );
$query .= "AND posts . ID IN {$in_str}";
}

$prepare_args = $post_ids;

return $wpdb->get_row(
$wpdb->prepare( $query, $prepare_args ),
ARRAY_A
);
}

/**
* Get count for the passed in stock status.
*
* @version 3.2.1
* @since 3.2.1
*
* @see Automattic\WooCommerce\Admin\API\Reports\Stock\Stats\DataStore::get_count()
*
* @param string $status Status slug.
*/
private function get_product_ids_by_stock_status( $status ) {
global $wpdb;

return $wpdb->get_col(
$wpdb->prepare(
"
SELECT DISTINCT posts.ID FROM {$wpdb->posts} posts
LEFT JOIN {$wpdb->wc_product_meta_lookup} wc_product_meta_lookup ON posts.ID = wc_product_meta_lookup.product_id
WHERE posts.post_type IN ( 'product', 'product_variation' )
AND wc_product_meta_lookup.stock_status = %s
",
$status
)
);
}

/**
* Get low stock count (products with stock < low stock amount, but greater than no stock amount).
*
* @version 3.2.1
* @since 3.2.1
*
* @see Automattic\WooCommerce\Admin\API\Reports\Stock\Stats\DataStore::get_low_stock_count()
*/
private function get_low_stock_product_ids() {
global $wpdb;

$no_stock_amount = absint( max( get_option( 'woocommerce_notify_no_stock_amount' ), 0 ) );
$low_stock_amount = absint( max( get_option( 'woocommerce_notify_low_stock_amount' ), 1 ) );

return $wpdb->get_col(
$wpdb->prepare(
"
SELECT posts.ID FROM {$wpdb->posts} posts
LEFT JOIN {$wpdb->wc_product_meta_lookup} wc_product_meta_lookup ON posts.ID = wc_product_meta_lookup.product_id
LEFT JOIN {$wpdb->postmeta} low_stock_amount_meta ON posts.ID = low_stock_amount_meta.post_id AND low_stock_amount_meta.meta_key = '_low_stock_amount'
WHERE posts.post_type IN ( 'product', 'product_variation' )
AND wc_product_meta_lookup.stock_quantity IS NOT NULL
AND wc_product_meta_lookup.stock_status = 'instock'
AND (
(
low_stock_amount_meta.meta_value > ''
AND wc_product_meta_lookup.stock_quantity <= CAST(low_stock_amount_meta.meta_value AS SIGNED)
AND wc_product_meta_lookup.stock_quantity > %d
)
OR (
(
low_stock_amount_meta.meta_value IS NULL OR low_stock_amount_meta.meta_value <= ''
)
AND wc_product_meta_lookup.stock_quantity <= %d
AND wc_product_meta_lookup.stock_quantity > %d
)
)
",
$no_stock_amount,
$low_stock_amount,
$no_stock_amount
)
);
}

/**
Expand Down Expand Up @@ -179,7 +353,7 @@ function get_column_values( WP_REST_Response $response, $product ) {
/**
* add_analytics_localization_info.
*
* @version 2.4.5
* @version 3.2.1
* @since 2.4.5
*
* @param $info
Expand All @@ -190,6 +364,7 @@ function add_analytics_localization_info( $info ) {
$info['cost_and_profit_enabled_on_stock'] = 'yes' === get_option( 'alg_wc_cog_cost_and_profit_enabled_on_analytics_stock', 'no' );
$info['category_enabled_on_stock'] = 'yes' === get_option( 'alg_wc_cog_category_enabled_on_analytics_stock', 'no' );
$info['filter_enabled_on_stock'] = 'yes' === get_option( 'alg_wc_cog_filter_enabled_on_analytics_stock', 'no' );
$info['consider_stock_for_calculation'] = $this->consider_stock_for_calculation();
return $info;
}

Expand Down
Loading

0 comments on commit 934fc6b

Please sign in to comment.