mirror of
https://github.com/OCA/stock-logistics-warehouse.git
synced 2025-01-21 14:27:28 +02:00
[IMP] sale_stock_on_hand_popup: open in a popup
This commit is contained in:
@@ -7,7 +7,7 @@ Sale Stock On Hand Popup
|
||||
!! This file is generated by oca-gen-addon-readme !!
|
||||
!! changes will be overwritten. !!
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! source digest: sha256:8afb561c639c15549500e32ef695b6653bda17d45ad957f6cc908e525343b79c
|
||||
!! source digest: sha256:be440b588a162856106f68611bf86c8d8e0c1a27641a9ebb7b2fedcfc0d5b905
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
from . import models
|
||||
from . import wizards
|
||||
|
||||
@@ -7,8 +7,15 @@
|
||||
"version": "14.0.1.0.1",
|
||||
"license": "AGPL-3",
|
||||
"depends": ["sale_stock", "stock_available"],
|
||||
"data": ["views/sale_order_views.xml"],
|
||||
"qweb": ["static/src/xml/sale_stock.xml"],
|
||||
"data": [
|
||||
"security/ir.model.access.csv",
|
||||
"security/security.xml",
|
||||
"views/assets.xml",
|
||||
"views/res_config_settings_views.xml",
|
||||
"views/sale_order_views.xml",
|
||||
"wizards/product_quant_wizard_views.xml",
|
||||
],
|
||||
"qweb": ["static/src/xml/stock_on_hand_widget.xml"],
|
||||
"installable": True,
|
||||
"application": False,
|
||||
}
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
from . import product
|
||||
from . import product_product
|
||||
from . import res_config_settings
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
from odoo import _, models
|
||||
|
||||
|
||||
class Product(models.Model):
|
||||
_inherit = "product.product"
|
||||
|
||||
def action_open_quants_show_products(self):
|
||||
res = self.action_open_quants()
|
||||
|
||||
res.update(
|
||||
{
|
||||
"name": _("Stock Lines"),
|
||||
"context": {
|
||||
**res.get("context", {}),
|
||||
"single_product": False,
|
||||
"edit": False,
|
||||
},
|
||||
}
|
||||
)
|
||||
return res
|
||||
20
sale_stock_on_hand_popup/models/product_product.py
Normal file
20
sale_stock_on_hand_popup/models/product_product.py
Normal file
@@ -0,0 +1,20 @@
|
||||
from odoo import models
|
||||
|
||||
|
||||
class Product(models.Model):
|
||||
_inherit = "product.product"
|
||||
|
||||
def action_open_quants_show_products(self):
|
||||
self.ensure_one()
|
||||
return {
|
||||
"name": self.display_name,
|
||||
"view_type": "form",
|
||||
"view_mode": "form",
|
||||
"res_model": "product.quant.wizard",
|
||||
"type": "ir.actions.act_window",
|
||||
"target": "new",
|
||||
"context": {
|
||||
**self.env.context,
|
||||
"default_product_id": self.id,
|
||||
},
|
||||
}
|
||||
11
sale_stock_on_hand_popup/models/res_config_settings.py
Normal file
11
sale_stock_on_hand_popup/models/res_config_settings.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ResConfigSettings(models.TransientModel):
|
||||
_inherit = "res.config.settings"
|
||||
|
||||
group_show_transit_location_stock_wizard = fields.Boolean(
|
||||
"Display also transit location lines in sale line stock popup.",
|
||||
implied_group="sale_stock_on_hand_popup.group_show_transit_location_stock_wizard",
|
||||
default=False,
|
||||
)
|
||||
2
sale_stock_on_hand_popup/security/ir.model.access.csv
Normal file
2
sale_stock_on_hand_popup/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_product_quant_wizard,access_product_quant_wizard,model_product_quant_wizard,base.group_user,1,1,1,1
|
||||
|
9
sale_stock_on_hand_popup/security/security.xml
Normal file
9
sale_stock_on_hand_popup/security/security.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<record id="group_show_transit_location_stock_wizard" model="res.groups">
|
||||
<field
|
||||
name="name"
|
||||
>Display transit location lines in sale line stock popup</field>
|
||||
<field name="category_id" ref="base.module_category_hidden" />
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -367,7 +367,7 @@ ul.auto-toc {
|
||||
!! This file is generated by oca-gen-addon-readme !!
|
||||
!! changes will be overwritten. !!
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! source digest: sha256:8afb561c639c15549500e32ef695b6653bda17d45ad957f6cc908e525343b79c
|
||||
!! source digest: sha256:be440b588a162856106f68611bf86c8d8e0c1a27641a9ebb7b2fedcfc0d5b905
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
|
||||
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/stock-logistics-warehouse/tree/14.0/sale_stock_on_hand_popup"><img alt="OCA/stock-logistics-warehouse" src="https://img.shields.io/badge/github-OCA%2Fstock--logistics--warehouse-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/stock-logistics-warehouse-14-0/stock-logistics-warehouse-14-0-sale_stock_on_hand_popup"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/stock-logistics-warehouse&target_branch=14.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
|
||||
<p>This module allows user to check from sale order line all inventory lines related to that product.</p>
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
odoo.define("sale_stock_on_hand_popup.QtyAtDateWidget", function (require) {
|
||||
"use strict";
|
||||
|
||||
const QtyAtDateWidget = require("sale_stock.QtyAtDateWidget");
|
||||
|
||||
QtyAtDateWidget.include({
|
||||
async _openStock(ev) {
|
||||
ev.stopPropagation();
|
||||
|
||||
return this.trigger_up("button_clicked", {
|
||||
attrs: {
|
||||
name: "action_open_quants_show_products",
|
||||
type: "object",
|
||||
},
|
||||
record: this.data.product_id,
|
||||
});
|
||||
},
|
||||
|
||||
_getContent() {
|
||||
const $content = this._super.apply(this, arguments);
|
||||
if ($content) {
|
||||
$content.on("click", ".action_open_stock", this._openStock.bind(this));
|
||||
}
|
||||
return $content;
|
||||
},
|
||||
});
|
||||
|
||||
return QtyAtDateWidget;
|
||||
});
|
||||
@@ -0,0 +1,47 @@
|
||||
odoo.define("sale_stock_on_hand_popup.StockOnHandWidget", function (require) {
|
||||
"use strict";
|
||||
|
||||
var Widget = require("web.Widget");
|
||||
var widget_registry = require("web.widget_registry");
|
||||
|
||||
var StockOnHandWidget = Widget.extend({
|
||||
template: "sale_stock_on_hand_popup.qtyOnHand",
|
||||
events: _.extend({}, Widget.prototype.events, {
|
||||
"click .fa-arrow-right": "_onClickButton",
|
||||
}),
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @param {Widget|null} parent
|
||||
* @param {Object} params
|
||||
*/
|
||||
init: function (parent, params) {
|
||||
this.data = params.data;
|
||||
this.fields = params.fields;
|
||||
this._super(parent);
|
||||
},
|
||||
|
||||
updateState: function (state) {
|
||||
var candidate = state.data[this.getParent().currentRow];
|
||||
if (candidate) {
|
||||
this.data = candidate.data;
|
||||
this.renderElement();
|
||||
}
|
||||
},
|
||||
|
||||
_onClickButton: async function (ev) {
|
||||
ev.stopPropagation();
|
||||
var action = await this._rpc({
|
||||
model: "product.product",
|
||||
method: "action_open_quants_show_products",
|
||||
args: [[this.data.product_id.data.id]],
|
||||
});
|
||||
action.views = [[false, "form"]];
|
||||
return this.do_action(action);
|
||||
},
|
||||
});
|
||||
|
||||
widget_registry.add("stock_on_hand_widget", StockOnHandWidget);
|
||||
|
||||
return StockOnHandWidget;
|
||||
});
|
||||
@@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<templates>
|
||||
<t
|
||||
t-name="sale_stock_available_info_popup.QtyDetailPopOver"
|
||||
t-inherit="sale_stock.QtyDetailPopOver"
|
||||
t-inherit-mode="extension"
|
||||
owl="1"
|
||||
>
|
||||
<xpath expr="//button" position="before">
|
||||
<button
|
||||
t-if="!data.is_mto"
|
||||
class="text-left btn btn-link action_open_stock"
|
||||
type="button"
|
||||
>
|
||||
<i class="fa fa-fw o_button_icon fa-arrow-right" />
|
||||
View Stock
|
||||
</button>
|
||||
</xpath>
|
||||
</t>
|
||||
</templates>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<templates>
|
||||
<div t-name="sale_stock_on_hand_popup.qtyOnHand">
|
||||
<div t-att-class="!widget.data.display_qty_widget ? 'invisible' : ''">
|
||||
<a tabindex="0" t-attf-class="fa fa-arrow-right" />
|
||||
</div>
|
||||
</div>
|
||||
</templates>
|
||||
@@ -5,20 +5,32 @@ class TestSaleStockOnHandPopup(common.SavepointCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.Product = cls.env["product.product"]
|
||||
|
||||
cls.product_1 = cls.env.ref("product.product_product_1")
|
||||
cls.product_2 = cls.env.ref("product.product_product_2")
|
||||
cls.product_1 = cls.env.ref("product.product_product_6")
|
||||
cls.product_2 = cls.env.ref("product.product_product_7")
|
||||
|
||||
def test_action_open_quants_show_products(self):
|
||||
action_data = self.product_1.action_open_quants_show_products()
|
||||
|
||||
self.assertNotEqual(
|
||||
action_data,
|
||||
self.product_1.action_open_quants(),
|
||||
)
|
||||
self.assertEqual("Stock Lines", action_data.get("name"))
|
||||
self.assertEqual(self.product_1.display_name, action_data.get("name"))
|
||||
|
||||
context = action_data.get("context")
|
||||
self.assertFalse(context.get("single_product", True))
|
||||
self.assertFalse(context.get("edit", True))
|
||||
self.assertEqual(self.product_1.id, context.get("default_product_id"))
|
||||
|
||||
def test_get_stock_quant(self):
|
||||
wiz_prod_1 = self.env["product.quant.wizard"].create(
|
||||
{
|
||||
"product_id": self.product_1.id,
|
||||
}
|
||||
)
|
||||
wiz_prod_2 = self.env["product.quant.wizard"].create(
|
||||
{
|
||||
"product_id": self.product_2.id,
|
||||
}
|
||||
)
|
||||
(wiz_prod_1 | wiz_prod_2)._compute_stock_quant_ids()
|
||||
|
||||
self.assertNotEqual(wiz_prod_1.stock_quant_ids, wiz_prod_2.stock_quant_ids)
|
||||
self.assertNotEqual(
|
||||
wiz_prod_1.stock_quant_ids, wiz_prod_1.product_id.stock_quant_ids
|
||||
)
|
||||
|
||||
15
sale_stock_on_hand_popup/views/assets.xml
Normal file
15
sale_stock_on_hand_popup/views/assets.xml
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" ?>
|
||||
<odoo>
|
||||
<template
|
||||
id="assets_backend"
|
||||
name="sale stock assets"
|
||||
inherit_id="web.assets_backend"
|
||||
>
|
||||
<xpath expr="." position="inside">
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="/sale_stock_on_hand_popup/static/src/js/stock_on_hand_widget.js"
|
||||
/>
|
||||
</xpath>
|
||||
</template>
|
||||
</odoo>
|
||||
23
sale_stock_on_hand_popup/views/res_config_settings_views.xml
Normal file
23
sale_stock_on_hand_popup/views/res_config_settings_views.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<record id="view_stock_configuration" model="ir.ui.view">
|
||||
<field name="name">Stock settings: Display transit location lines</field>
|
||||
<field name="model">res.config.settings</field>
|
||||
<field name="inherit_id" ref="stock.res_config_settings_view_form" />
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//div[@data-key='stock']" position="inside">
|
||||
<h2 id="stock_on_hand_info">Sale Stock on Hand</h2>
|
||||
<div class="row mt16 o_settings_container">
|
||||
<div class="col-xs-12 col-md-6 o_setting_box">
|
||||
<div class="o_setting_left_pane">
|
||||
<field name="group_show_transit_location_stock_wizard" />
|
||||
</div>
|
||||
<div class="o_setting_right_pane">
|
||||
<label for="group_show_transit_location_stock_wizard" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -1,15 +1,24 @@
|
||||
<?xml version="1.0" ?>
|
||||
<odoo>
|
||||
<template
|
||||
id="sale_order_line_view_list"
|
||||
name="sale.order.line.view.list"
|
||||
inherit_id="web.assets_backend"
|
||||
>
|
||||
<xpath expr="." position="inside">
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="/sale_stock_on_hand_popup/static/src/js/qty_at_date_widget.js"
|
||||
/>
|
||||
</xpath>
|
||||
</template>
|
||||
<record id="view_order_form_inherit_sale_stock_qty" model="ir.ui.view">
|
||||
<field name="model">sale.order</field>
|
||||
<field
|
||||
name="inherit_id"
|
||||
ref="sale_stock.view_order_form_inherit_sale_stock_qty"
|
||||
/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath
|
||||
expr="//field[@name='order_line']/form/group/group/div[@name='ordered_qty']/widget[@name='qty_at_date_widget']"
|
||||
position="after"
|
||||
>
|
||||
<widget name="stock_on_hand_widget" width="0.1px" />
|
||||
</xpath>
|
||||
<xpath
|
||||
expr="//field[@name='order_line']/tree/widget[@name='qty_at_date_widget']"
|
||||
position="after"
|
||||
>
|
||||
<widget name="stock_on_hand_widget" width="20px" />
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
||||
1
sale_stock_on_hand_popup/wizards/__init__.py
Normal file
1
sale_stock_on_hand_popup/wizards/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import product_quant_wizard
|
||||
22
sale_stock_on_hand_popup/wizards/product_quant_wizard.py
Normal file
22
sale_stock_on_hand_popup/wizards/product_quant_wizard.py
Normal file
@@ -0,0 +1,22 @@
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class ProductQuantWizard(models.TransientModel):
|
||||
_name = "product.quant.wizard"
|
||||
_description = "Product Quant Wizard"
|
||||
|
||||
product_id = fields.Many2one("product.product")
|
||||
stock_quant_ids = fields.Many2many(
|
||||
"stock.quant", compute="_compute_stock_quant_ids"
|
||||
)
|
||||
|
||||
@api.depends("product_id")
|
||||
def _compute_stock_quant_ids(self):
|
||||
for rec in self:
|
||||
rec.stock_quant_ids = rec.product_id.stock_quant_ids.filtered(
|
||||
lambda x: x.location_id.usage in ["internal", "transit"]
|
||||
if self.env.user.has_group(
|
||||
"sale_stock_on_hand_popup.group_show_transit_location_stock_wizard"
|
||||
)
|
||||
else x.location_id.usage == "internal"
|
||||
)
|
||||
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<record id="product_quant_wizard_view_form" model="ir.ui.view">
|
||||
<field name="name">product.quant.wizard.form</field>
|
||||
<field name="model">product.quant.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<field name="product_id" invisible="1" />
|
||||
<field name="stock_quant_ids" readonly="1">
|
||||
<tree>
|
||||
<field name="product_id" optional="hide" />
|
||||
<field name="location_id" optional="show" />
|
||||
<field
|
||||
name="lot_id"
|
||||
groups="stock.group_production_lot"
|
||||
optional="show"
|
||||
/>
|
||||
<field
|
||||
name="package_id"
|
||||
groups="stock.group_tracking_lot"
|
||||
optional="show"
|
||||
/>
|
||||
<field
|
||||
name="owner_id"
|
||||
groups="stock.group_tracking_owner"
|
||||
optional="show"
|
||||
/>
|
||||
<field name="available_quantity" optional="show" />
|
||||
<field name="quantity" optional="show" />
|
||||
<field
|
||||
name="product_uom_id"
|
||||
groups="uom.group_uom"
|
||||
optional="show"
|
||||
/>
|
||||
<field
|
||||
name='company_id'
|
||||
groups="base.group_multi_company"
|
||||
optional="show"
|
||||
/>
|
||||
</tree>
|
||||
</field>
|
||||
<footer>
|
||||
<button string="Close" class="btn-secondary" special="cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user