[IMP] sale_stock_available_info_popup: black, isort, prettier

This commit is contained in:
Víctor Martínez
2021-02-19 09:12:18 +01:00
parent c10c038e39
commit f3fc0c2b16
7 changed files with 164 additions and 115 deletions

View File

@@ -3,21 +3,14 @@
{
"name": "Sale Stock Available Info Popup",
"summary": "Adds an 'Available to promise' quantity to the popover shown "
"in sale order line that display stock info of the product",
"in sale order line that display stock info of the product",
"author": "Tecnativa, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/stock-logistics-warehouse",
"category": "Warehouse Management",
"version": "12.0.1.0.1",
"license": "AGPL-3",
"depends": [
"sale_stock_info_popup",
"stock_available",
],
"data": [
"views/sale_order_views.xml",
],
"qweb": [
"static/src/xml/qty_at_date.xml",
],
"depends": ["sale_stock_info_popup", "stock_available",],
"data": ["views/sale_order_views.xml",],
"qweb": ["static/src/xml/qty_at_date.xml",],
"installable": True,
}

View File

@@ -7,22 +7,24 @@ from odoo import api, fields, models
class SaleOrderLine(models.Model):
_inherit = 'sale.order.line'
_inherit = "sale.order.line"
immediately_usable_qty_today = fields.Float(
compute='_compute_immediately_usable_qty_today')
compute="_compute_immediately_usable_qty_today"
)
@api.depends('product_id', 'product_uom_qty')
@api.depends("product_id", "product_uom_qty")
def _compute_immediately_usable_qty_today(self):
qty_processed_per_product = defaultdict(lambda: 0)
remaining = self.env['sale.order.line']
remaining = self.env["sale.order.line"]
for line in self.sorted(key=lambda r: r.sequence):
if not line.display_qty_widget:
remaining |= line
continue
product = line.product_id
qty_processed = qty_processed_per_product[product.id]
line.immediately_usable_qty_today = \
line.immediately_usable_qty_today = (
product.immediately_usable_qty - qty_processed
)
qty_processed_per_product[product.id] += line.product_uom_qty
remaining.write({"immediately_usable_qty_today": False})

View File

@@ -1,18 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2020 Tecnativa - Ernesto Tejeda
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
<templates>
<div t-extend="sale_stock.qtyAtDate">
<t t-jquery="t[t-if^='widget.data.virtual_available_at_date']" t-operation="attributes">
<attribute name="t-if">widget.data.immediately_usable_qty_today &lt; widget.data.qty_to_deliver and !widget.data.is_mto</attribute>
<t
t-jquery="t[t-if^='widget.data.virtual_available_at_date']"
t-operation="attributes"
>
<attribute
name="t-if"
>widget.data.immediately_usable_qty_today &lt; widget.data.qty_to_deliver and !widget.data.is_mto</attribute>
</t>
</div>
<div t-extend="sale_stock.QtyDetailPopOver">
<t t-jquery="t[t-if*='!data.is_mto']" t-operation="append">
<tr>
<td><strong>Available to promise</strong></td>
<td><t t-esc='data.immediately_usable_qty_today'/>
<t t-esc='data.product_uom.data.display_name'/></td>
<td>
<strong>Available to promise</strong>
</td>
<td>
<t t-esc='data.immediately_usable_qty_today' />
<t t-esc='data.product_uom.data.display_name' />
</td>
</tr>
</t>
</div>

View File

@@ -5,113 +5,148 @@ from odoo.tests.common import SavepointCase
class SaleStockAvailableInfoPopup(SavepointCase):
@classmethod
def setUpClass(cls):
super(SaleStockAvailableInfoPopup, cls).setUpClass()
user_group_stock_user = cls.env.ref('stock.group_stock_user')
cls.user_stock_user = cls.env['res.users'].create({
'name': 'Pauline Poivraisselle',
'login': 'pauline',
'email': 'p.p@example.com',
'notification_type': 'inbox',
'groups_id': [(6, 0, [user_group_stock_user.id])]})
cls.product = cls.env['product.product'].create({
'name': 'Storable product',
'type': 'product',
})
cls.stock_location = cls.env.ref('stock.stock_location_stock')
cls.customers_location = cls.env.ref('stock.stock_location_customers')
cls.suppliers_location = cls.env.ref('stock.stock_location_suppliers')
cls.env['stock.quant'].create({
'product_id': cls.product.id,
'location_id': cls.stock_location.id,
'quantity': 40.0})
cls.picking_out = cls.env['stock.picking'].create({
'picking_type_id': cls.env.ref('stock.picking_type_out').id,
'location_id': cls.stock_location.id,
'location_dest_id': cls.customers_location.id})
cls.env['stock.move'].create({
'name': 'a move',
'product_id': cls.product.id,
'product_uom_qty': 3.0,
'product_uom': cls.product.uom_id.id,
'picking_id': cls.picking_out.id,
'location_id': cls.stock_location.id,
'location_dest_id': cls.customers_location.id})
cls.picking_in = cls.env['stock.picking'].create({
'picking_type_id': cls.env.ref('stock.picking_type_in').id,
'location_id': cls.suppliers_location.id,
'location_dest_id': cls.stock_location.id})
cls.env['stock.move'].create({
'restrict_partner_id': cls.user_stock_user.partner_id.id,
'name': 'another move',
'product_id': cls.product.id,
'product_uom_qty': 5.0,
'product_uom': cls.product.uom_id.id,
'picking_id': cls.picking_in.id,
'location_id': cls.suppliers_location.id,
'location_dest_id': cls.stock_location.id})
user_group_stock_user = cls.env.ref("stock.group_stock_user")
cls.user_stock_user = cls.env["res.users"].create(
{
"name": "Pauline Poivraisselle",
"login": "pauline",
"email": "p.p@example.com",
"notification_type": "inbox",
"groups_id": [(6, 0, [user_group_stock_user.id])],
}
)
cls.product = cls.env["product.product"].create(
{"name": "Storable product", "type": "product",}
)
cls.stock_location = cls.env.ref("stock.stock_location_stock")
cls.customers_location = cls.env.ref("stock.stock_location_customers")
cls.suppliers_location = cls.env.ref("stock.stock_location_suppliers")
cls.env["stock.quant"].create(
{
"product_id": cls.product.id,
"location_id": cls.stock_location.id,
"quantity": 40.0,
}
)
cls.picking_out = cls.env["stock.picking"].create(
{
"picking_type_id": cls.env.ref("stock.picking_type_out").id,
"location_id": cls.stock_location.id,
"location_dest_id": cls.customers_location.id,
}
)
cls.env["stock.move"].create(
{
"name": "a move",
"product_id": cls.product.id,
"product_uom_qty": 3.0,
"product_uom": cls.product.uom_id.id,
"picking_id": cls.picking_out.id,
"location_id": cls.stock_location.id,
"location_dest_id": cls.customers_location.id,
}
)
cls.picking_in = cls.env["stock.picking"].create(
{
"picking_type_id": cls.env.ref("stock.picking_type_in").id,
"location_id": cls.suppliers_location.id,
"location_dest_id": cls.stock_location.id,
}
)
cls.env["stock.move"].create(
{
"restrict_partner_id": cls.user_stock_user.partner_id.id,
"name": "another move",
"product_id": cls.product.id,
"product_uom_qty": 5.0,
"product_uom": cls.product.uom_id.id,
"picking_id": cls.picking_in.id,
"location_id": cls.suppliers_location.id,
"location_dest_id": cls.stock_location.id,
}
)
def test_immediately_usable_qty_today(self):
self.picking_out.action_confirm()
self.picking_in.action_assign()
so = self.env['sale.order'].create({
'partner_id': self.env.ref('base.res_partner_1').id,
'order_line': [
(0, 0, {
'name': self.product.name,
'product_id': self.product.id,
'product_uom_qty': 1,
'product_uom': self.product.uom_id.id,
'price_unit': self.product.list_price
}),
],
})
so = self.env["sale.order"].create(
{
"partner_id": self.env.ref("base.res_partner_1").id,
"order_line": [
(
0,
0,
{
"name": self.product.name,
"product_id": self.product.id,
"product_uom_qty": 1,
"product_uom": self.product.uom_id.id,
"price_unit": self.product.list_price,
},
),
],
}
)
line = so.order_line
self.assertEqual(
line.immediately_usable_qty_today,
self.product.immediately_usable_qty,
line.immediately_usable_qty_today, self.product.immediately_usable_qty,
)
def test_immediately_usable_qty_today_similar_solines(self):
"""Create a sale order containing three times the same product. The
quantity available should be different for the 3 lines.
"""
so = self.env['sale.order'].create({
'partner_id': self.env.ref('base.res_partner_1').id,
'order_line': [
(0, 0, {
'sequence': 1,
'name': self.product.name,
'product_id': self.product.id,
'product_uom_qty': 5,
'product_uom': self.product.uom_id.id,
'price_unit': self.product.list_price
}),
(0, 0, {
'sequence': 2,
'name': self.product.name,
'product_id': self.product.id,
'product_uom_qty': 5,
'product_uom': self.product.uom_id.id,
'price_unit': self.product.list_price
}),
(0, 0, {
'sequence': 3,
'name': self.product.name,
'product_id': self.product.id,
'product_uom_qty': 5,
'product_uom': self.product.uom_id.id,
'price_unit': self.product.list_price
}),
],
})
so = self.env["sale.order"].create(
{
"partner_id": self.env.ref("base.res_partner_1").id,
"order_line": [
(
0,
0,
{
"sequence": 1,
"name": self.product.name,
"product_id": self.product.id,
"product_uom_qty": 5,
"product_uom": self.product.uom_id.id,
"price_unit": self.product.list_price,
},
),
(
0,
0,
{
"sequence": 2,
"name": self.product.name,
"product_id": self.product.id,
"product_uom_qty": 5,
"product_uom": self.product.uom_id.id,
"price_unit": self.product.list_price,
},
),
(
0,
0,
{
"sequence": 3,
"name": self.product.name,
"product_id": self.product.id,
"product_uom_qty": 5,
"product_uom": self.product.uom_id.id,
"price_unit": self.product.list_price,
},
),
],
}
)
self.assertEqual(
so.order_line.mapped('immediately_usable_qty_today'),
so.order_line.mapped("immediately_usable_qty_today"),
[
self.product.immediately_usable_qty,
self.product.immediately_usable_qty - 5,
self.product.immediately_usable_qty - 10,
]
],
)

View File

@@ -1,14 +1,17 @@
<?xml version="1.0"?>
<?xml version="1.0" ?>
<!-- Copyright 2020 Tecnativa - Ernesto Tejeda
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo>
<record id="view_order_form" model="ir.ui.view">
<field name="name">sale.order.line.tree.inherit</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="inherit_id" ref="sale.view_order_form" />
<field name="arch" type="xml">
<xpath expr="//page/field[@name='order_line']/tree/field[@name='product_uom_qty']" position="after">
<field name="immediately_usable_qty_today" invisible="1"/>
<xpath
expr="//page/field[@name='order_line']/tree/field[@name='product_uom_qty']"
position="after"
>
<field name="immediately_usable_qty_today" invisible="1" />
</xpath>
</field>
</record>

View File

@@ -0,0 +1 @@
../../../../sale_stock_available_info_popup

View File

@@ -0,0 +1,6 @@
import setuptools
setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)