diff --git a/stock_average_daily_sale/__init__.py b/stock_average_daily_sale/__init__.py
index 0650744..64face1 100644
--- a/stock_average_daily_sale/__init__.py
+++ b/stock_average_daily_sale/__init__.py
@@ -1 +1 @@
-from . import models
+from . import models, wizards
diff --git a/stock_average_daily_sale/__manifest__.py b/stock_average_daily_sale/__manifest__.py
index 8194f54..582a9d3 100644
--- a/stock_average_daily_sale/__manifest__.py
+++ b/stock_average_daily_sale/__manifest__.py
@@ -13,18 +13,23 @@
"sale",
"stock_storage_type_putaway_abc",
"product_abc_classification",
+ "product_abc_classification_sale_stock",
"product_route_mto",
"stock_location_zone",
],
"data": [
"security/stock_average_daily_sale_config.xml",
"security/stock_average_daily_sale.xml",
+ "security/stock_average_daily_sale_demo.xml",
"views/stock_average_daily_sale_config.xml",
"views/stock_average_daily_sale.xml",
+ "views/abc_classification_profile.xml",
"views/stock_warehouse.xml",
"data/ir_cron.xml",
],
+ "external_dependencies": {"python": ["freezegun"]},
"demo": [
"demo/stock_average_daily_sale_config.xml",
+ "demo/stock_move.xml",
],
}
diff --git a/stock_average_daily_sale/demo/stock_average_daily_sale_config.xml b/stock_average_daily_sale/demo/stock_average_daily_sale_config.xml
index 4a8e836..2b90e84 100644
--- a/stock_average_daily_sale/demo/stock_average_daily_sale_config.xml
+++ b/stock_average_daily_sale/demo/stock_average_daily_sale_config.xml
@@ -6,6 +6,10 @@
model="stock.average.daily.sale.config"
id="stock_average_daily_sale_config_level_a"
>
+
a
2
week
@@ -17,6 +21,10 @@
model="stock.average.daily.sale.config"
id="stock_average_daily_sale_config_level_b"
>
+
b
13
week
@@ -28,6 +36,10 @@
model="stock.average.daily.sale.config"
id="stock_average_daily_sale_config_level_c"
>
+
c
26
week
diff --git a/stock_average_daily_sale/demo/stock_move.xml b/stock_average_daily_sale/demo/stock_move.xml
new file mode 100644
index 0000000..20ba109
--- /dev/null
+++ b/stock_average_daily_sale/demo/stock_move.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
diff --git a/stock_average_daily_sale/models/__init__.py b/stock_average_daily_sale/models/__init__.py
index f6a34f5..756ee7b 100644
--- a/stock_average_daily_sale/models/__init__.py
+++ b/stock_average_daily_sale/models/__init__.py
@@ -1,3 +1,4 @@
from . import stock_warehouse # isort:skip
from . import stock_average_daily_sale_config # isort:skip
from . import stock_average_daily_sale # isort:skip
+from . import abc_classification_profile
diff --git a/stock_average_daily_sale/models/abc_classification_profile.py b/stock_average_daily_sale/models/abc_classification_profile.py
new file mode 100644
index 0000000..e6275ab
--- /dev/null
+++ b/stock_average_daily_sale/models/abc_classification_profile.py
@@ -0,0 +1,15 @@
+# Copyright 2023 ACSONE SA/NV
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
+
+from odoo import fields, models
+
+
+class AbcClassificationProfile(models.Model):
+
+ _inherit = "abc.classification.profile"
+
+ stock_average_daily_sale_config_ids = fields.One2many(
+ comodel_name="stock.average.daily.sale.config",
+ inverse_name="abc_classification_profile_id",
+ string="Average Daily Sale Configurations",
+ )
diff --git a/stock_average_daily_sale/models/stock_average_daily_sale.py b/stock_average_daily_sale/models/stock_average_daily_sale.py
index 5eb4d9c..0dfb148 100644
--- a/stock_average_daily_sale/models/stock_average_daily_sale.py
+++ b/stock_average_daily_sale/models/stock_average_daily_sale.py
@@ -22,6 +22,11 @@ class StockAverageDailySale(models.Model):
_order = "abc_classification_level ASC, product_id ASC"
_description = "Average Daily Sale for Products"
+ abc_classification_profile_id = fields.Many2one(
+ comodel_name="abc.classification.profile",
+ required=True,
+ index=True,
+ )
abc_classification_level = fields.Selection(
selection=ABC_SELECTION, required=True, readonly=True, index=True
)
@@ -282,6 +287,7 @@ class StockAverageDailySale(models.Model):
date_to,
config_id,
abc_classification_level,
+ cfg.abc_classification_profile_id,
sale_ok,
is_mto,
sqty.qty_in_stock as qty_in_stock,
diff --git a/stock_average_daily_sale/models/stock_average_daily_sale_config.py b/stock_average_daily_sale/models/stock_average_daily_sale_config.py
index 95496a6..4b2521f 100644
--- a/stock_average_daily_sale/models/stock_average_daily_sale_config.py
+++ b/stock_average_daily_sale/models/stock_average_daily_sale_config.py
@@ -13,6 +13,11 @@ class StockAverageDailySaleConfig(models.Model):
_name = "stock.average.daily.sale.config"
_description = "Average daily sales computation parameters"
+ abc_classification_profile_id = fields.Many2one(
+ comodel_name="abc.classification.profile",
+ required=True,
+ ondelete="cascade",
+ )
abc_classification_level = fields.Selection(
selection=ABC_SELECTION, required=True, readonly=True
)
diff --git a/stock_average_daily_sale/security/stock_average_daily_sale_demo.xml b/stock_average_daily_sale/security/stock_average_daily_sale_demo.xml
new file mode 100644
index 0000000..44ad925
--- /dev/null
+++ b/stock_average_daily_sale/security/stock_average_daily_sale_demo.xml
@@ -0,0 +1,14 @@
+
+
+
+
+ stock.average.daily.sale.demo access user
+
+
+
+
+
+
+
+
diff --git a/stock_average_daily_sale/views/abc_classification_profile.xml b/stock_average_daily_sale/views/abc_classification_profile.xml
new file mode 100644
index 0000000..600e734
--- /dev/null
+++ b/stock_average_daily_sale/views/abc_classification_profile.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ abc.classification.profile.form (in stock_average_daily_sale)
+ abc.classification.profile
+
+
+
+
+
+
+
+
diff --git a/stock_average_daily_sale/wizards/__init__.py b/stock_average_daily_sale/wizards/__init__.py
new file mode 100644
index 0000000..d11cee8
--- /dev/null
+++ b/stock_average_daily_sale/wizards/__init__.py
@@ -0,0 +1 @@
+from . import stock_average_daily_sale_demo
diff --git a/stock_average_daily_sale/wizards/stock_average_daily_sale_demo.py b/stock_average_daily_sale/wizards/stock_average_daily_sale_demo.py
new file mode 100644
index 0000000..be60f4b
--- /dev/null
+++ b/stock_average_daily_sale/wizards/stock_average_daily_sale_demo.py
@@ -0,0 +1,91 @@
+# Copyright 2023 ACSONE SA/NV
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
+import logging
+
+from dateutil.relativedelta import relativedelta
+from freezegun import freeze_time
+
+from odoo import _, api, models
+from odoo.fields import Date, Datetime
+
+_logger = logging.getLogger(__name__)
+
+
+class StockAverageDailySaleDemo(models.TransientModel):
+
+ _name = "stock.average.daily.sale.demo"
+ _description = "Wizard to populate demo data with past moves for Average Daily Sale"
+
+ def _create_move(self, product, origin_location, qty):
+ suppliers = self.env.ref("stock.stock_location_suppliers")
+ customers = self.env.ref("stock.stock_location_customers")
+ move_obj = self.env["stock.move"]
+ # Create first an incoming move to avoid negative quantities
+ move = move_obj.create(
+ {
+ "product_id": product.id,
+ "name": product.name,
+ "location_id": suppliers.id,
+ "location_dest_id": customers.id,
+ "product_uom_qty": qty,
+ }
+ )
+ move._action_confirm()
+ move._action_assign()
+ move.quantity_done = move.product_uom_qty
+ move._action_done()
+
+ # Create the OUT move
+ move = move_obj.create(
+ {
+ "product_id": product.id,
+ "name": product.name,
+ "location_id": origin_location.id,
+ "location_dest_id": customers.id,
+ "product_uom_qty": qty,
+ "priority": "1",
+ }
+ )
+ return move
+
+ @api.model
+ def _create_movement(self, product):
+ now = Datetime.now()
+ stock = self.env.ref("stock.stock_location_stock")
+ move_1_date = Date.to_string(now - relativedelta(weeks=11))
+ with freeze_time(move_1_date):
+ move = self._create_move(product, stock, 10.0)
+ move._action_confirm()
+ move._action_assign()
+ move.quantity_done = move.product_uom_qty
+ move._action_done()
+ move.priority = "1"
+ move_2_date = Date.to_string(now - relativedelta(weeks=9))
+ with freeze_time(move_2_date):
+ move = self._create_move(product, stock, 12.0)
+ move._action_confirm()
+ move._action_assign()
+ move.quantity_done = move.product_uom_qty
+ move._action_done()
+ move.priority = "1"
+
+ @api.model
+ def _action_create_data(self):
+ """
+ This is called through an xml function in order to populate
+ demo data with past moves as the report depends on that.
+ """
+ module = self.env["ir.module.module"].search(
+ [("name", "=", "stock_average_daily_sale"), ("demo", "=", True)]
+ )
+ if not module:
+ _logger.warning(
+ _("You cannot call the _action_create_data() on production database.")
+ )
+ return
+ product = self.env.ref("product.product_product_25")
+ self._create_movement(product)
+ product = self.env.ref("product.product_product_27")
+ self._create_movement(product)
+
+ self.env["stock.average.daily.sale"].refresh_view()