Skip to content

Commit

Permalink
[UPD] merge two modules into sale_forecast
Browse files Browse the repository at this point in the history
  • Loading branch information
ntsirintanis committed Mar 19, 2024
1 parent 06a0889 commit d7ceb61
Show file tree
Hide file tree
Showing 18 changed files with 1,131 additions and 120 deletions.
85 changes: 85 additions & 0 deletions sale_forecast/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
=============
Sale Forecast
=============

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:c228a211927681f6c87e30ba3f2776cfb98fb52e4009f211d7d90bff440e1c61
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png
:target: https://odoo-community.org/page/development-status
:alt: Alpha
.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fsale--workflow-lightgray.png?logo=github
:target: https://github.com/OCA/sale-workflow/tree/16.0/sale_forecast
:alt: OCA/sale-workflow
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/sale-workflow-16-0/sale-workflow-16-0-sale_forecast
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/sale-workflow&target_branch=16.0
:alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|

This module allows to create demand estimates for a given product and
location, on configurable time periods.

The module does not provide in itself any specific usage of the estimates.

.. IMPORTANT::
This is an alpha version, the data model and design can change at any time without warning.
Only for development or testing purpose, do not use in production.
`More details on development status <https://odoo-community.org/page/development-status>`_

**Table of contents**

.. contents::
:local:

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/sale-workflow/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/sale-workflow/issues/new?body=module:%20sale_forecast%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
~~~~~~~

* Therp BV

Contributors
~~~~~~~~~~~~

* Jordi Ballester Alomar <[email protected]>
* Lois Rilo <[email protected]>

Maintainers
~~~~~~~~~~~

This module is maintained by the OCA.

.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org

OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

This module is part of the `OCA/sale-workflow <https://github.com/OCA/sale-workflow/tree/16.0/sale_forecast>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
25 changes: 16 additions & 9 deletions sale_forecast/__manifest__.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
# Copyright 2024 Therp BV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
# Copyright 2016-20 ForgeFlow S.L. (https://www.forgeflow.com)
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
{
"name": "Sale Forecast",
"summary": "Sale forecast report",
"summary": "Enable forecast for Sales",
"version": "16.0.1.0.0",
"category": "Generic Modules/Sale",
"author": "Therp BV, Odoo Community Association (OCA)",
"development_status": "Alpha",
"website": "https://github.com/OCA/sale-workflow",
"depends": ["sale", "stock_demand_estimate", "stock_demand_estimate_matrix"],
"category": "Generic Modules/Sale",
"depends": [
"sale_management",
"stock",
"web_widget_x2many_2d_matrix",
"date_range",
],
"data": [
"security/ir.model.access.csv",
"views/date_range.xml",
"views/sale_forecast.xml",
"wizards/wizard_view.xml",
"security/sale_security.xml",
"views/sale_forecast_view.xml",
"wizards/sale_forecast_wizard_view.xml",
],
"license": "AGPL-3",
"license": "LGPL-3",
"installable": True,
}
1 change: 1 addition & 0 deletions sale_forecast/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
from . import date_range
from . import sale_forecast
19 changes: 19 additions & 0 deletions sale_forecast/models/date_range.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright 2019 ForgeFlow S.L. (https://www.forgeflow.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from odoo import api, fields, models


class DateRange(models.Model):
_inherit = "date.range"

days = fields.Integer(
string="Days between dates",
compute="_compute_days",
readonly=True,
)

@api.depends("date_start", "date_end")
def _compute_days(self):
for rec in self.filtered(lambda x: x.date_start and x.date_end):
rec.days = abs((rec.date_end - rec.date_start).days) + 1
153 changes: 148 additions & 5 deletions sale_forecast/models/sale_forecast.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,154 @@
from odoo import fields, models
# Copyright 2016-20 ForgeFlow S.L. (https://www.forgeflow.com)
# Copyright 2016 Aleph Objects, Inc. (https://www.alephobjects.com/)
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).

from datetime import date, timedelta

from odoo import _, api, fields, models
from odoo.exceptions import UserError


class SaleForecast(models.Model):
_name = "sale.forecast"
_inherits = {"stock.demand.estimate": "stock_demand_id"}
_description = "Sale forecast"
_description = "Sale Forecast"

stock_demand_id = fields.Many2one(
comodel_name="stock.demand.estimate", required=True, ondelete="cascade"
date_from = fields.Date(
compute="_compute_dates", string="From (computed)", store=True
)
date_to = fields.Date(compute="_compute_dates", string="To (computed)", store=True)
manual_date_from = fields.Date(string="From")
manual_date_to = fields.Date(string="To")
manual_duration = fields.Integer(
string="Duration", help="Duration (in days)", default=1
)
duration = fields.Integer(
compute="_compute_dates", string="Duration (computed))", store=True
)
product_id = fields.Many2one(
comodel_name="product.product", string="Product", required=True
)
product_uom = fields.Many2one(comodel_name="uom.uom", string="Unit of measure")
location_id = fields.Many2one(
comodel_name="stock.location", string="Location", required=True
)
product_uom_qty = fields.Float(string="Quantity", digits="Product Unit of Measure")
product_qty = fields.Float(
string="Quantity (Product UoM)",
compute="_compute_product_quantity",
inverse="_inverse_product_quantity",
digits=0,
store=True,
help="Quantity in the default UoM of the product",
readonly=True,
)
daily_qty = fields.Float(string="Quantity / Day", compute="_compute_daily_qty")
company_id = fields.Many2one(
comodel_name="res.company",
string="Company",
required=True,
default=lambda self: self.env.company,
)
date_range_id = fields.Many2one(
comodel_name="date.range", string="Estimating Period", ondelete="restrict"
)

@api.depends(
"date_range_id", "manual_duration", "manual_date_from", "manual_date_to"
)
def _compute_dates(self):
today = date.today()
for rec in self:
if rec.date_range_id:
rec.date_from = rec.date_range_id.date_start
rec.date_to = rec.date_range_id.date_end
rec.duration = rec.date_range_id.days
continue
rec.date_from = rec.manual_date_from or today
if rec.manual_date_to:
rec.date_to = rec.manual_date_to
rec.duration = (rec.manual_date_to - rec.date_from).days + 1
elif rec.manual_duration:
rec.date_to = rec.date_from + timedelta(days=rec.manual_duration - 1)
rec.duration = rec.manual_duration
else:
rec.date_to = rec.date_from + timedelta(days=1)
rec.duration = 2

@api.depends("product_qty", "duration")
def _compute_daily_qty(self):
for rec in self:
if rec.duration:
rec.daily_qty = rec.product_qty / rec.duration
else:
rec.daily_qty = 0.0

@api.depends("product_id", "product_uom", "product_uom_qty")
def _compute_product_quantity(self):
for rec in self:
if rec.product_uom:
rec.product_qty = rec.product_uom._compute_quantity(
rec.product_uom_qty, rec.product_id.uom_id
)
else:
rec.product_qty = rec.product_uom_qty

def _inverse_product_quantity(self):
raise UserError(
_(
"The requested operation cannot be "
"processed because of a programming error "
"setting the `product_qty` field instead "
"of the `product_uom_qty`."
)
)

def name_get(self):
res = []
for rec in self:
if rec.date_range_id:
name = "{} - {} - {}".format(
rec.date_range_id.name,
rec.product_id.name,
rec.location_id.name,
)
else:
name = "{} - {}: {} - {}".format(
rec.date_from,
rec.date_to,
rec.product_id.name,
rec.location_id.name,
)
res.append((rec.id, name))
return res

@api.onchange("manual_date_to")
def _onchange_manual_date_to(self):
for rec in self:
if rec.manual_date_from:
rec.manual_duration = (
rec.manual_date_to - rec.manual_date_from
).days + 1

@api.onchange("manual_duration")
def _onchange_manual_duration(self):
for rec in self:
if rec.manual_date_from:
rec.manual_date_to = rec.manual_date_from + timedelta(
days=rec.manual_duration - 1
)

@api.model
def get_quantity_by_date_range(self, date_start, date_end):
"""To be used in other modules"""
# Check if the dates overlap with the period
period_date_start = self.date_from
period_date_end = self.date_to

# We need only the periods that overlap
# the dates introduced by the user.
if period_date_start <= date_end and period_date_end >= date_start:
overlap_date_start = max(period_date_start, date_start)
overlap_date_end = min(period_date_end, date_end)
days = (abs(overlap_date_end - overlap_date_start)).days + 1
return days * self.daily_qty
return 0.0
2 changes: 2 additions & 0 deletions sale_forecast/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
* Jordi Ballester Alomar <[email protected]>
* Lois Rilo <[email protected]>
4 changes: 4 additions & 0 deletions sale_forecast/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
This module allows to create demand estimates for a given product and
location, on configurable time periods.

The module does not provide in itself any specific usage of the estimates.
7 changes: 2 additions & 5 deletions sale_forecast/security/ir.model.access.csv
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_sale_forecast,sale.forcast,model_sale_forecast,stock.group_stock_user,1,0,0,0
access_sale_forecast_system,sale.forecast.system,model_sale_forecast,stock.group_stock_manager,1,1,1,1
sale_forecast.access_sale_forecast_sheet,access_sale_forecast_sheet,sale_forecast.model_sale_forecast_sheet,stock.group_stock_manager,1,1,1,1
sale_forecast.access_sale_forecast_sheet_line,access_sale_forecast_sheet_line,sale_forecast.model_sale_forecast_sheet_line,stock.group_stock_manager,1,1,1,1
sale_forecast.access_sale_forecast_wizard,access_sale_forecast_wizard,sale_forecast.model_sale_forecast_wizard,stock.group_stock_manager,1,1,1,1
access_stock_demand_estimate,stock.orderpoint.demand.estimate,model_stock_demand_estimate,stock.group_stock_user,1,0,0,0
access_stock_demand_estimate_system,stock.orderpoint.demand.estimate system,model_stock_demand_estimate,stock.group_stock_manager,1,1,1,1
11 changes: 11 additions & 0 deletions sale_forecast/security/sale_security.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo noupdate="1">
<record id="sale_forecast_comp_rule" model="ir.rule">
<field name="name">Sale forecast multi-company</field>
<field name="model_id" ref="model_sale_forecast" />
<field name="global" eval="True" />
<field
name="domain_force"
>['|',('company_id','=',False),('company_id', 'in', company_ids)]</field>
</record>
</odoo>
Binary file added sale_forecast/static/description/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit d7ceb61

Please sign in to comment.