mirror of
https://github.com/OCA/stock-logistics-warehouse.git
synced 2025-01-21 14:27:28 +02:00
1
setup/stock_exception/odoo/addons/stock_exception
Symbolic link
1
setup/stock_exception/odoo/addons/stock_exception
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../../stock_exception
|
||||
6
setup/stock_exception/setup.py
Normal file
6
setup/stock_exception/setup.py
Normal file
@@ -0,0 +1,6 @@
|
||||
import setuptools
|
||||
|
||||
setuptools.setup(
|
||||
setup_requires=['setuptools-odoo'],
|
||||
odoo_addon=True,
|
||||
)
|
||||
3
stock_exception/__init__.py
Normal file
3
stock_exception/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)
|
||||
|
||||
from . import models, wizard
|
||||
20
stock_exception/__manifest__.py
Normal file
20
stock_exception/__manifest__.py
Normal file
@@ -0,0 +1,20 @@
|
||||
# Copyright 2021 Ecosoft Co., Ltd (https://ecosoft.co.th)
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)
|
||||
|
||||
{
|
||||
"name": "Stock Exception",
|
||||
"summary": "Custom exceptions on stock picking",
|
||||
"version": "14.0.1.0.0",
|
||||
"category": "Generic Modules/Warehouse Management",
|
||||
"author": "Ecosoft, Odoo Community Association (OCA)",
|
||||
"website": "https://github.com/OCA/stock-logistics-warehouse",
|
||||
"depends": ["stock", "base_exception"],
|
||||
"license": "AGPL-3",
|
||||
"data": [
|
||||
"security/ir.model.access.csv",
|
||||
"data/stock_exception_data.xml",
|
||||
"wizard/stock_exception_confirm_view.xml",
|
||||
"views/stock_view.xml",
|
||||
],
|
||||
"installable": True,
|
||||
}
|
||||
33
stock_exception/data/stock_exception_data.xml
Normal file
33
stock_exception/data/stock_exception_data.xml
Normal file
@@ -0,0 +1,33 @@
|
||||
<odoo noupdate="1">
|
||||
<!-- Test Stock Exceptions Scheduler-->
|
||||
<record model="ir.cron" forcecreate="True" id="ir_cron_test_stock_picking_except">
|
||||
<field name="name">Stock: Test Draft Pickings Exception</field>
|
||||
<field name="model_id" ref="stock.model_stock_picking" />
|
||||
<field name="state">code</field>
|
||||
<field name="code">model.test_all_draft_pickings()</field>
|
||||
<field name="user_id" ref="base.user_root" />
|
||||
<field name="interval_number">20</field>
|
||||
<field name="interval_type">minutes</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field name="doall" eval="False" />
|
||||
<field name="active" eval="False" />
|
||||
</record>
|
||||
<record id="sp_excep_no_partner" model="exception.rule">
|
||||
<field name="name">No Partner</field>
|
||||
<field name="description">No Partner</field>
|
||||
<field name="sequence">50</field>
|
||||
<field name="model">stock.picking</field>
|
||||
<field name="code">if not self.partner_id:
|
||||
failed=True</field>
|
||||
<field name="active" eval="False" />
|
||||
</record>
|
||||
<record id="sm_excep_product_uom_qty_check" model="exception.rule">
|
||||
<field name="name">Demand Quantity not positive</field>
|
||||
<field name="description">Demand quantity must be positive</field>
|
||||
<field name="sequence">50</field>
|
||||
<field name="model">stock.move</field>
|
||||
<field name="code">if self.product_uom_qty <= 0:
|
||||
failed=True</field>
|
||||
<field name="active" eval="False" />
|
||||
</record>
|
||||
</odoo>
|
||||
5
stock_exception/models/__init__.py
Normal file
5
stock_exception/models/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)
|
||||
|
||||
from . import exception_rule
|
||||
from . import stock
|
||||
from . import stock_move
|
||||
17
stock_exception/models/exception_rule.py
Normal file
17
stock_exception/models/exception_rule.py
Normal file
@@ -0,0 +1,17 @@
|
||||
# Copyright 2021 Ecosoft Co., Ltd (https://ecosoft.co.th)
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ExceptionRule(models.Model):
|
||||
_inherit = "exception.rule"
|
||||
|
||||
picking_ids = fields.Many2many(comodel_name="stock.picking", string="Pickings")
|
||||
model = fields.Selection(
|
||||
selection_add=[
|
||||
("stock.picking", "Stock Picking"),
|
||||
("stock.move", "Stock Move"),
|
||||
],
|
||||
ondelete={"stock.picking": "cascade", "stock.move": "cascade"},
|
||||
)
|
||||
49
stock_exception/models/stock.py
Normal file
49
stock_exception/models/stock.py
Normal file
@@ -0,0 +1,49 @@
|
||||
# Copyright 2021 Ecosoft Co., Ltd (https://ecosoft.co.th)
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)
|
||||
|
||||
from odoo import api, models
|
||||
|
||||
|
||||
class StockPicking(models.Model):
|
||||
_inherit = ["stock.picking", "base.exception"]
|
||||
_name = "stock.picking"
|
||||
_order = "main_exception_id asc, priority desc, scheduled_date asc, id desc"
|
||||
|
||||
@api.model
|
||||
def test_all_draft_pickings(self):
|
||||
picking_set = self.search([("state", "=", "draft")])
|
||||
picking_set.detect_exceptions()
|
||||
return True
|
||||
|
||||
@api.model
|
||||
def _reverse_field(self):
|
||||
return "picking_ids"
|
||||
|
||||
def detect_exceptions(self):
|
||||
all_exceptions = super().detect_exceptions()
|
||||
moves = self.mapped("move_lines")
|
||||
all_exceptions += moves.detect_exceptions()
|
||||
return all_exceptions
|
||||
|
||||
@api.constrains("ignore_exception", "move_lines", "state")
|
||||
def stock_check_exception(self):
|
||||
pickings = self.filtered(
|
||||
lambda s: s.state in ["waiting", "confirmed", "assigned"]
|
||||
)
|
||||
if pickings:
|
||||
pickings._check_exception()
|
||||
|
||||
@api.onchange("move_lines")
|
||||
def onchange_ignore_exception(self):
|
||||
if self.state in ["waiting", "confirmed", "assigned"]:
|
||||
self.ignore_exception = False
|
||||
|
||||
def action_confirm(self):
|
||||
if self.detect_exceptions() and not self.ignore_exception:
|
||||
return self._popup_exceptions()
|
||||
return super().action_confirm()
|
||||
|
||||
@api.model
|
||||
def _get_popup_action(self):
|
||||
action = self.env.ref("stock_exception.action_stock_exception_confirm")
|
||||
return action
|
||||
24
stock_exception/models/stock_move.py
Normal file
24
stock_exception/models/stock_move.py
Normal file
@@ -0,0 +1,24 @@
|
||||
# Copyright 2021 Ecosoft Co., Ltd (https://ecosoft.co.th)
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class StockMove(models.Model):
|
||||
_inherit = ["stock.move", "base.exception.method"]
|
||||
_name = "stock.move"
|
||||
|
||||
ignore_exception = fields.Boolean(
|
||||
related="picking_id.ignore_exception", store=True, string="Ignore Exceptions"
|
||||
)
|
||||
|
||||
def _get_main_records(self):
|
||||
return self.mapped("picking_id")
|
||||
|
||||
@api.model
|
||||
def _reverse_field(self):
|
||||
return "picking_ids"
|
||||
|
||||
def _detect_exceptions(self, rule):
|
||||
records = super()._detect_exceptions(rule)
|
||||
return records.mapped("picking_id")
|
||||
1
stock_exception/readme/CONTRIBUTORS.rst
Normal file
1
stock_exception/readme/CONTRIBUTORS.rst
Normal file
@@ -0,0 +1 @@
|
||||
* Tharathip Chaweewongphan <tharathipc@ecosoft.co.th>
|
||||
6
stock_exception/readme/DESCRIPTION.rst
Normal file
6
stock_exception/readme/DESCRIPTION.rst
Normal file
@@ -0,0 +1,6 @@
|
||||
This module allows you attach several customizable exceptions to your
|
||||
stock picking in a way that you can filter pickings by exceptions type and fix them.
|
||||
|
||||
This is especially useful in an scenario for mass stock picking import, because it's likely some pickings have
|
||||
errors when you import them (like product not found in Odoo, wrong line
|
||||
format etc.)
|
||||
2
stock_exception/security/ir.model.access.csv
Normal file
2
stock_exception/security/ir.model.access.csv
Normal file
@@ -0,0 +1,2 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_stock_exception_confirm,access_stock_exception_confirm,model_stock_exception_confirm,base.group_user,1,1,1,1
|
||||
|
BIN
stock_exception/static/description/icon.png
Normal file
BIN
stock_exception/static/description/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.2 KiB |
82
stock_exception/views/stock_view.xml
Normal file
82
stock_exception/views/stock_view.xml
Normal file
@@ -0,0 +1,82 @@
|
||||
<odoo>
|
||||
<record id="action_stock_test_tree" model="ir.actions.act_window">
|
||||
<field name="name">Stock Exception Rules</field>
|
||||
<field name="res_model">exception.rule</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="base_exception.view_exception_rule_tree" />
|
||||
<field
|
||||
name="domain"
|
||||
>[('model', 'in', ['stock.picking', 'stock.move', 'stock.move.line'])]</field>
|
||||
<field
|
||||
name="context"
|
||||
>{'active_test': False, 'default_model' : 'stock.picking'}</field>
|
||||
</record>
|
||||
<menuitem
|
||||
action="action_stock_test_tree"
|
||||
id="menu_stock_test"
|
||||
parent="stock.menu_stock_config_settings"
|
||||
/>
|
||||
<record id="view_picking_form" model="ir.ui.view">
|
||||
<field name="name">stock_exception.view_picking_form</field>
|
||||
<field name="model">stock.picking</field>
|
||||
<field name="inherit_id" ref="stock.view_picking_form" />
|
||||
<field name="arch" type="xml">
|
||||
<sheet position="before">
|
||||
<div
|
||||
class="alert alert-danger"
|
||||
role="alert"
|
||||
style="margin-bottom:0px;"
|
||||
attrs="{'invisible': [('exceptions_summary','=',False)]}"
|
||||
>
|
||||
<p>
|
||||
<strong
|
||||
>There are exceptions blocking this stock picking:</strong>
|
||||
</p>
|
||||
<field name="exceptions_summary" />
|
||||
<button
|
||||
name="action_ignore_exceptions"
|
||||
type="object"
|
||||
class="btn-danger"
|
||||
string="Ignore Exceptions"
|
||||
help="Click here to be able to confirm this stock picking regardless of the exceptions."
|
||||
groups="base_exception.group_exception_rule_manager"
|
||||
/>
|
||||
</div>
|
||||
</sheet>
|
||||
<xpath expr="//field[@name='date_deadline']/.." position="inside">
|
||||
<field
|
||||
name="ignore_exception"
|
||||
states="waiting,confirmed,assigned"
|
||||
groups='base_exception.group_exception_rule_manager'
|
||||
/>
|
||||
<field name="exception_ids" widget="many2many_tags" readonly="True" />
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
<record id="vpicktree" model="ir.ui.view">
|
||||
<field name="name">stock_exception.vpicktree</field>
|
||||
<field name="model">stock.picking</field>
|
||||
<field name="inherit_id" ref="stock.vpicktree" />
|
||||
<field name="arch" type="xml">
|
||||
<field name="state" position="after">
|
||||
<field name="main_exception_id" />
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_picking_internal_search" model="ir.ui.view">
|
||||
<field name="name">stock_exception.view_picking_internal_search</field>
|
||||
<field name="model">stock.picking</field>
|
||||
<field name="inherit_id" ref="stock.view_picking_internal_search" />
|
||||
<field name="arch" type="xml">
|
||||
<filter name="activities_exception" position="after">
|
||||
<separator orientation="vertical" />
|
||||
<filter
|
||||
icon="fa-exclamation-circle"
|
||||
name="tofix"
|
||||
string="Blocked in Draft"
|
||||
domain="[('main_exception_id','!=',False)]"
|
||||
/>
|
||||
</filter>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
3
stock_exception/wizard/__init__.py
Normal file
3
stock_exception/wizard/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)
|
||||
|
||||
from . import stock_exception_confirm
|
||||
19
stock_exception/wizard/stock_exception_confirm.py
Normal file
19
stock_exception/wizard/stock_exception_confirm.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# Copyright 2021 Ecosoft Co., Ltd (https://ecosoft.co.th)
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class StockExceptionConfirm(models.TransientModel):
|
||||
_name = "stock.exception.confirm"
|
||||
_description = "Stock exception wizard"
|
||||
_inherit = ["exception.rule.confirm"]
|
||||
|
||||
related_model_id = fields.Many2one("stock.picking", "Stock Picking")
|
||||
|
||||
def action_confirm(self):
|
||||
self.ensure_one()
|
||||
if self.ignore:
|
||||
self.related_model_id.ignore_exception = True
|
||||
self.related_model_id.action_confirm()
|
||||
return super().action_confirm()
|
||||
10
stock_exception/wizard/stock_exception_confirm_view.xml
Normal file
10
stock_exception/wizard/stock_exception_confirm_view.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<odoo>
|
||||
<record id="action_stock_exception_confirm" model="ir.actions.act_window">
|
||||
<field name="name">Outstanding exceptions to manage</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">stock.exception.confirm</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="view_id" ref="base_exception.view_exception_rule_confirm" />
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user