-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
TA#66873 [MIG][16.0] stock_move_origin_link (#181)
Co-authored-by: Lanto Razafindrabe <[email protected]> Co-authored-by: majouda <[email protected]>
- Loading branch information
1 parent
c856867
commit 5538166
Showing
19 changed files
with
364 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
==================================== | ||
Stock Move Origin Link | ||
==================================== | ||
|
||
This module adds the `Source Document` to the list view of stock pickings and stock moves. | ||
|
||
.. image:: static/description/stock_move_list.png | ||
|
||
The text is clickable if it refers to an object within the supported types. | ||
|
||
For example, in the example above, when clicking on `MO/00003`, the user is redirected to the | ||
form view of the production order. | ||
|
||
.. image:: static/description/mrp_production_form.png | ||
|
||
Stock Pickings | ||
-------------- | ||
The feature is available for all stock picking list views. | ||
Here is an example with the list view of delivery orders. | ||
|
||
.. image:: static/description/delivery_order_list.png | ||
|
||
When clicking on `SO020`, the user is redirected to the sale order. | ||
|
||
.. image:: static/description/sale_order_form.png | ||
|
||
Form Views | ||
---------- | ||
The feature is also available on form views of stock pickings and stock moves. | ||
|
||
.. image:: static/description/delivery_order_form.png | ||
|
||
Supported Origin Documents | ||
-------------------------- | ||
The module supports the following documents as origin of a stock move: | ||
|
||
* Sale Orders | ||
* Purchase Orders | ||
* Manufacturing Orders | ||
|
||
However, the module only depends on the `Inventory` app. It detects automatically whether the `Sales`, `Purchases` and `MRP` apps are installed. | ||
|
||
Contributors | ||
------------ | ||
* Numigi (tm) and all its contributors (https://bit.ly/numigiens) | ||
|
||
More information | ||
---------------- | ||
* Meet us at https://bit.ly/numigi-com |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# Copyright 2024-today Numigi and all its contributors (https://bit.ly/numigiens) | ||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). | ||
|
||
from . import models |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Copyright 2024-today Numigi and all its contributors (https://bit.ly/numigiens) | ||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). | ||
|
||
{ | ||
"name": "Stock Move Origin Link", | ||
"version": "16.0.1.0.0", | ||
"category": "Stock", | ||
"description": "Add a link to the origin document from stock moves.", | ||
"summary": "Add a link to the origin document from stock moves.", | ||
"maintainer": "numigi", | ||
"website": "https://bit.ly/numigi-com", | ||
"license": "LGPL-3", | ||
"depends": ["stock"], | ||
"data": [ | ||
"views/stock_move_views.xml", | ||
"views/stock_move_line_views.xml", | ||
], | ||
"assets": { | ||
"web.assets_backend": ["stock_move_origin_link/static/src/*"], | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# Translation of Odoo Server. | ||
# This file contains the translation of the following modules: | ||
# * stock_move_origin_link | ||
# | ||
msgid "" | ||
msgstr "" | ||
"Project-Id-Version: Odoo Server 11.0+e\n" | ||
"Report-Msgid-Bugs-To: \n" | ||
"POT-Creation-Date: 2024-04-10 19:54+0000\n" | ||
"PO-Revision-Date: 2024-04-10 14:55-0500\n" | ||
"Last-Translator: <>\n" | ||
"Language-Team: \n" | ||
"Language: fr\n" | ||
"MIME-Version: 1.0\n" | ||
"Content-Type: text/plain; charset=UTF-8\n" | ||
"Content-Transfer-Encoding: 8bit\n" | ||
"Plural-Forms: \n" | ||
"X-Generator: Poedit 2.0.6\n" | ||
|
||
#. module: stock_move_origin_link | ||
#: model:ir.model,name:stock_move_origin_link.model_stock_move_line | ||
msgid "Product Moves (Stock Move Line)" | ||
msgstr "" | ||
|
||
#. module: stock_move_origin_link | ||
#: model:ir.model.fields,field_description:stock_move_origin_link.field_stock_move_line__origin | ||
msgid "Source Document" | ||
msgstr "Document d'origine" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Copyright 2024-today Numigi and all its contributors (https://bit.ly/numigiens) | ||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). | ||
from . import stock_move_line_with_origin |
11 changes: 11 additions & 0 deletions
11
stock_move_origin_link/models/stock_move_line_with_origin.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# Copyright 2024-today Numigi and all its contributors (https://bit.ly/numigiens) | ||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). | ||
|
||
from odoo import fields, models | ||
|
||
|
||
class StockMoveLineWithOrigin(models.Model): | ||
|
||
_inherit = "stock.move.line" | ||
|
||
origin = fields.Char(related="move_id.origin", readonly=True) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
/** @odoo-module **/ | ||
|
||
import { CharField } from "@web/views/fields/char/char_field"; | ||
import { patch } from '@web/core/utils/patch'; | ||
import { useService } from "@web/core/utils/hooks"; | ||
import { onWillStart, onMounted, onWillUpdateProps, Component } from "@odoo/owl"; | ||
import rpc from "web.rpc"; | ||
|
||
const VALID_MODELS = ["stock.picking", "stock.move", "stock.move.line"]; | ||
|
||
// AccessVerifier Class for caching access checks | ||
class AccessVerifier extends Component { | ||
constructor() { | ||
super(...arguments); | ||
this._accessCache = new Map(); | ||
} | ||
|
||
// Check if the model is readable, with caching | ||
async isModelReadable(model) { | ||
if (!this._accessCache.has(model)) { | ||
const result = await rpc.query({ | ||
model: model, | ||
method: "check_access_rights", | ||
kwargs: { operation: "read", raise_exception: false } | ||
}); | ||
this._accessCache.set(model, result); | ||
} | ||
return this._accessCache.get(model); | ||
} | ||
} | ||
|
||
// Global instance of AccessVerifier | ||
const accessVerifier = new AccessVerifier(); | ||
const originCache = new Map(); | ||
|
||
// Patch CharField prototype | ||
patch(CharField.prototype, 'stock_move_origin_link_charfield', { | ||
setup() { | ||
this.props.hasOrigin = this.hasOriginField(); | ||
this.actionService = useService("action"); | ||
this._super(...arguments); | ||
|
||
// Setup hooks | ||
onWillStart(this.updateOriginIfNeeded.bind(this)); | ||
onWillUpdateProps(this.handleUpdateProps.bind(this)); | ||
onMounted(this.updateOriginIfNeeded.bind(this)); | ||
}, | ||
|
||
// Consolidate origin update logic | ||
async updateOriginIfNeeded() { | ||
if (!this.props.originUrl && this.props.hasOrigin) { | ||
await this.updateOriginUrl(this.props.record); | ||
} | ||
}, | ||
|
||
async handleUpdateProps(nextProps) { | ||
if (nextProps.record !== this.props.record && !nextProps.originUrl && this.props.hasOrigin) { | ||
await this.updateOriginUrl(nextProps.record); | ||
} | ||
}, | ||
|
||
async updateOriginUrl(record) { | ||
try { | ||
if (originCache.has(record.id)) { | ||
const cachedOrigin = originCache.get(record.id); | ||
this.props.originRecord = cachedOrigin.record; | ||
this.props.originUrl = cachedOrigin.url; | ||
return; | ||
} | ||
|
||
if (this.hasOriginField()) { | ||
const originRecord = await this.computeOriginUrl(record); | ||
const originUrl = originRecord ? `#id=${originRecord.id}&model=${originRecord.model}` : null; | ||
this.props.originRecord = originRecord; | ||
this.props.originUrl = originUrl; | ||
|
||
if (originRecord) { | ||
originCache.set(record.id, { record: originRecord, url: originUrl }); | ||
} | ||
} | ||
} catch (error) { | ||
this.handleError('Failed to update origin URL:', error); | ||
} | ||
}, | ||
|
||
// Check if the field has an origin | ||
hasOriginField() { | ||
return this.props.name === 'origin' && VALID_MODELS.includes(this.props.record.resModel) && this.props.record.data.origin; | ||
}, | ||
|
||
// Fetch the form view action | ||
async getRecordFormViewAction(record) { | ||
try { | ||
return await rpc.query({ | ||
model: record.model, | ||
method: "get_formview_action", | ||
args: [[record.id]], | ||
}); | ||
} catch (error) { | ||
this.handleError('Error fetching form view action:', error); | ||
return null; | ||
} | ||
}, | ||
|
||
// Handle link click event | ||
async onLinkClick(event) { | ||
event.preventDefault(); | ||
event.stopPropagation(); | ||
|
||
if (this.props.originRecord) { | ||
const action = await this.getRecordFormViewAction(this.props.originRecord); | ||
this.actionService.doAction(action); | ||
} | ||
}, | ||
|
||
// Check if a module is installed, with caching | ||
async isModuleInstalled(moduleName) { | ||
try { | ||
const result = await rpc.query({ | ||
model: "ir.module.module", | ||
method: "search_read", | ||
args: [[["name", "=", moduleName], ["state", "=", "installed"]]], | ||
}); | ||
return result.length > 0; | ||
} catch (error) { | ||
this.handleError(`Error checking if module ${moduleName} is installed:`, error); | ||
return false; | ||
} | ||
}, | ||
|
||
// Fetch documents based on origin field | ||
async fetchDocumentsByOrigin(modelName, moduleName, record) { | ||
try { | ||
if (!(await this.isModuleInstalled(moduleName))) { | ||
return false; | ||
} | ||
|
||
if (!(await accessVerifier.isModelReadable(modelName))) { | ||
return false; | ||
} | ||
|
||
const data = await rpc.query({ | ||
model: modelName, | ||
method: "search_read", | ||
args: [[["name", "=", record.data.origin]], ["name"]], | ||
}); | ||
|
||
return data.length ? { ...data[0], model: modelName } : false; | ||
|
||
} catch (error) { | ||
this.handleError(`Error fetching documents for model ${modelName}:`, error); | ||
return false; | ||
} | ||
}, | ||
|
||
// Compute origin URL by checking various models | ||
async computeOriginUrl(record) { | ||
try { | ||
return ( | ||
await this.fetchDocumentsByOrigin("purchase.order", "purchase", record) || | ||
await this.fetchDocumentsByOrigin("sale.order", "sale", record) || | ||
await this.fetchDocumentsByOrigin("mrp.production", "mrp", record) || | ||
null | ||
); | ||
} catch (error) { | ||
this.handleError('Error computing origin URL:', error); | ||
return null; | ||
} | ||
}, | ||
|
||
// Error handling helper | ||
handleError(message, error) { | ||
console.error(message, error); | ||
this.props.originUrl = null; | ||
this.props.originRecord = null; | ||
} | ||
}); | ||
|
||
// Extend CharField props | ||
CharField.props = { | ||
...CharField.props, | ||
hasOrigin: { type: Boolean, optional: true }, | ||
originUrl: { type: String, optional: true }, | ||
originRecord: { type: Object, optional: true }, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<templates xml:space="preserve"> | ||
<t t-inherit="web.CharField" owl="1" t-inherit-mode="extension" > | ||
<xpath expr="//span[@t-esc='formattedValue']" position="replace"> | ||
<t t-if="props.hasOrigin and props.originUrl"> | ||
<a t-attf-href="{{props.originUrl}}" t-on-click.prevent="onLinkClick"> | ||
<span t-esc="formattedValue" /> | ||
</a> | ||
</t> | ||
<t t-else=""> | ||
<span t-esc="formattedValue" /> | ||
</t> | ||
</xpath> | ||
</t> | ||
</templates> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<templates xml:space="preserve"> | ||
<t t-inherit="web.ListRenderer.RecordRow" owl="1" t-inherit-mode="extension" > | ||
<xpath expr="//t[@t-if='!isInvisible']" position="replace"> | ||
<t t-if="!isInvisible"> | ||
<t t-if="column.name === 'origin' and ['stock.picking', 'stock.move', 'stock.move.line'].includes(record.resModel)"> | ||
<Field name="column.name" record="record" type="column.widget" class="getFieldClass(column)" fieldInfo="props.archInfo.fieldNodes[column.name]" setDirty="(isDirty) => this.setDirty(isDirty)" readonly="props.activeActions?.edit === false and !record.isNew"/> | ||
</t> | ||
<t t-elif="canUseFormatter(column, record)" t-out="getFormattedValue(column, record)"/> | ||
<Field t-else="" name="column.name" record="record" type="column.widget" class="getFieldClass(column)" fieldInfo="props.archInfo.fieldNodes[column.name]" setDirty="(isDirty) => this.setDirty(isDirty)" readonly="props.activeActions?.edit === false and !record.isNew"/> | ||
</t> | ||
</xpath> | ||
</t> | ||
</templates> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
<?xml version='1.0' encoding='UTF-8'?> | ||
<odoo> | ||
|
||
<record id="view_move_line_tree" model="ir.ui.view"> | ||
<field name="name">Stock Move Line List: Add origin</field> | ||
<field name="model">stock.move.line</field> | ||
<field name="type">tree</field> | ||
<field name="inherit_id" ref="stock.view_move_line_tree"/> | ||
<field name="arch" type="xml"> | ||
<field name="reference" position="after"> | ||
<field name="origin" widget="origin"/> | ||
</field> | ||
</field> | ||
</record> | ||
|
||
</odoo> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
<?xml version='1.0' encoding='UTF-8'?> | ||
<odoo> | ||
|
||
<record id="view_move_tree" model="ir.ui.view"> | ||
<field name="name">Stock Move List: Add origin</field> | ||
<field name="model">stock.move</field> | ||
<field name="type">tree</field> | ||
<field name="inherit_id" ref="stock.view_move_tree"/> | ||
<field name="arch" type="xml"> | ||
<field name="reference" position="after"> | ||
<field name="origin" widget="origin"/> | ||
</field> | ||
</field> | ||
</record> | ||
|
||
</odoo> |