stock_average_daily_sale: Allow to include/exclude weekends

Allow to decide if weekends should be included or excluded
in average daily sale calculation.
This commit is contained in:
twalter-c2c
2024-08-27 16:09:24 +02:00
parent fe2ac11e8e
commit 98aeebfb17
4 changed files with 24 additions and 12 deletions

View File

@@ -12,6 +12,7 @@
<field name="standard_deviation_exclude_factor">3</field>
<field name="safety_factor">0.3</field>
<field name="number_days_qty_in_stock">2</field>
<field name="exclude_weekends">1</field>
</record>
<record
model="stock.average.daily.sale.config"
@@ -23,6 +24,7 @@
<field name="standard_deviation_exclude_factor">3</field>
<field name="safety_factor">0.3</field>
<field name="number_days_qty_in_stock">2</field>
<field name="exclude_weekends">1</field>
</record>
<record
model="stock.average.daily.sale.config"
@@ -34,5 +36,6 @@
<field name="standard_deviation_exclude_factor">3</field>
<field name="safety_factor">0.3</field>
<field name="number_days_qty_in_stock">2</field>
<field name="exclude_weekends">1</field>
</record>
</odoo>

View File

@@ -176,14 +176,16 @@ class StockAverageDailySale(models.Model):
NOW()::date - '1 day'::interval as date_to,
-- start of the analyzed period computed from the original cfg
(NOW() - (period_value::TEXT || ' ' || period_name::TEXT)::INTERVAL):: date as date_from,
-- the number of business days between start and end computed by
-- removing saturday and sunday
-- the number of days between start and end computed by
-- removing saturday and sunday if weekends should be excluded
(SELECT count(1) from (select EXTRACT(DOW FROM s.d::date) as dd
FROM generate_series(
(NOW() - (period_value::TEXT || ' ' || period_name::TEXT)::INTERVAL):: date ,
(NOW()- '1 day'::interval)::date,
'1 day') AS s(d)) t
WHERE dd not in(0,6)) AS nrb_days_without_sat_sun
WHERE exclude_weekends = False
OR (exclude_weekends = True AND dd not in(0,6))
) AS nbr_days
FROM
stock_average_daily_sale_config
),
@@ -209,9 +211,10 @@ class StockAverageDailySale(models.Model):
+ ( stddev_samp(product_uom_qty) OVER pid * cfg.standard_deviation_exclude_factor)
) as upper_bound,
coalesce ((stddev_samp(product_uom_qty) OVER pid), 0) as standard_deviation,
cfg.nrb_days_without_sat_sun,
cfg.nbr_days,
cfg.date_from,
cfg.date_to,
cfg.exclude_weekends,
cfg.id as config_id,
sm.date
FROM stock_move sm
@@ -239,16 +242,16 @@ class StockAverageDailySale(models.Model):
)::numeric AS average_qty_by_sale,
(count(product_uom_qty) FILTER
(WHERE product_uom_qty BETWEEN lower_bound AND upper_bound OR standard_deviation = 0)
/ nrb_days_without_sat_sun::numeric) AS average_daily_sales_count,
/ nbr_days::numeric) AS average_daily_sales_count,
count(product_uom_qty) FILTER
(WHERE product_uom_qty BETWEEN lower_bound AND upper_bound OR standard_deviation = 0)::double precision as nbr_sales,
standard_deviation::numeric ,
date_from,
date_to,
config_id,
nrb_days_without_sat_sun
nbr_days
FROM deliveries_last
GROUP BY product_id, warehouse_id, standard_deviation, nrb_days_without_sat_sun, date_from, date_to, config_id
GROUP BY product_id, warehouse_id, standard_deviation, nbr_days, date_from, date_to, config_id
),
-- Compute the stock by product in locations under stock
stock_qty AS (
@@ -262,7 +265,6 @@ class StockAverageDailySale(models.Model):
GROUP BY sq.product_id, sl.warehouse_id
),
-- Compute the standard deviation of the average daily sales count
-- excluding saturday and sunday
daily_standard_deviation AS(
SELECT
id,
@@ -279,7 +281,7 @@ class StockAverageDailySale(models.Model):
(WHERE product_uom_qty BETWEEN lower_bound AND upper_bound OR standard_deviation = 0)
) as daily_sales
FROM deliveries_last
WHERE EXTRACT(DOW FROM date) <> '0' AND EXTRACT(DOW FROM date) <> '6'
WHERE exclude_weekends = False OR (EXTRACT(DOW FROM date) <> '0' AND EXTRACT(DOW FROM date) <> '6')
GROUP BY product_id, warehouse_id, 1
) as averages_daily group by id, product_id, warehouse_id
@@ -303,11 +305,11 @@ class StockAverageDailySale(models.Model):
is_mto,
sqty.qty_in_stock as qty_in_stock,
ds.daily_standard_deviation,
ds.daily_standard_deviation * cfg.safety_factor * sqrt(nrb_days_without_sat_sun) as safety,
(cfg.number_days_qty_in_stock * average_qty_by_sale * average_daily_sales_count) + (ds.daily_standard_deviation * cfg.safety_factor * sqrt(nrb_days_without_sat_sun)) as safety_bin_min_qty_new,
ds.daily_standard_deviation * cfg.safety_factor * sqrt(nbr_days) as safety,
(cfg.number_days_qty_in_stock * average_qty_by_sale * average_daily_sales_count) + (ds.daily_standard_deviation * cfg.safety_factor * sqrt(nbr_days)) as safety_bin_min_qty_new,
cfg.number_days_qty_in_stock * GREATEST(average_daily_sales_count, 1) * (average_qty_by_sale + (standard_deviation * cfg.safety_factor)) as safety_bin_min_qty_old,
GREATEST(
(cfg.number_days_qty_in_stock * average_qty_by_sale * average_daily_sales_count) + (ds.daily_standard_deviation * cfg.safety_factor * sqrt(nrb_days_without_sat_sun)),
(cfg.number_days_qty_in_stock * average_qty_by_sale * average_daily_sales_count) + (ds.daily_standard_deviation * cfg.safety_factor * sqrt(nbr_days)),
(cfg.number_days_qty_in_stock * average_qty_by_sale)
) as recommended_qty
FROM averages t

View File

@@ -32,6 +32,12 @@ class StockAverageDailySaleConfig(models.Model):
),
readonly=True,
)
exclude_weekends = fields.Boolean(
string="Exclude Weekends",
help="Set to True only if you do not expect any orders/deliveries during "
"the weekends. If set to True, stock moves done on weekends won't be "
"taken into account to calculate the average daily usage",
)
period_name = fields.Selection(
string="Period analyzed unit",
selection=[

View File

@@ -10,6 +10,7 @@
<field name="arch" type="xml">
<tree editable="top" create="false" delete="false">
<field name="abc_classification_level" />
<field name="exclude_weekends" />
<field name="period_value" />
<field name="period_name" />
<field name="number_days_qty_in_stock" />