Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions sale_order_zero_stock_blockage/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
18 changes: 18 additions & 0 deletions sale_order_zero_stock_blockage/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "Sale Order Zero Stock Blockage",
"description": """
Zero Stock Blockage is module to prevent order to confirm if product is out of stock.

But if manager wants then he can aprove that order.
""",
"version": "1.0",
"depends": ['sale_management', 'stock'],
"author": "danal",
"category": "Category",
"license": "LGPL-3",
"data": [
"views/sale_order_view.xml",
],
"installable": True,
'application': False,
}
3 changes: 3 additions & 0 deletions sale_order_zero_stock_blockage/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.

from . import sale_order
39 changes: 39 additions & 0 deletions sale_order_zero_stock_blockage/models/sale_order.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
from odoo.exceptions import UserError

from odoo import fields, models, api


class SaleOrder(models.Model):
_inherit = 'sale.order'

zero_stock_approval = fields.Boolean(
string="Approval",
help="Order Approval by manager,\nif order has insufficient stock then this approval is required by manager.",
copy=False,
)

@api.model
def fields_get(self, allfields=None, attributes=None):
res = super().fields_get(allfields, attributes)
if not self.env.user.has_group("sales_team.group_sale_manager"):
if "zero_stock_approval" in res:
res["zero_stock_approval"]["readonly"] = True
return res

def action_confirm(self):
for record in self:
if not record.order_line:
raise UserError("You cannot confirm a Quotation without any products.")
if record.zero_stock_approval:
return super().action_confirm()
for line in record.order_line:
if (
line.product_id.qty_available < line.product_uom_qty
and line.product_id.type == "consu"
and not record.zero_stock_approval
and not self.env.user.has_group("sales_team.group_sale_manager")
):
raise UserError(
"Cannot confirm this Sale Order due to insufficient stock.\n\nPlease get approval or adjust the quantities."
)
return super().action_confirm()
3 changes: 3 additions & 0 deletions sale_order_zero_stock_blockage/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.

from . import test_sale_blockage
60 changes: 60 additions & 0 deletions sale_order_zero_stock_blockage/tests/test_sale_blockage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from odoo.tests.common import TransactionCase
from odoo.exceptions import UserError


class TestSaleZeroStockBlockage(TransactionCase):

@classmethod
def setUpClass(self):
super().setUpClass()

self.sale_user = self.env['res.users'].create({
'name': 'Salesman Test User',
'login': 'sales_test_user',
'email': 'sales_test@example.com',
'group_ids': [(4, self.env.ref('sales_team.group_sale_salesman').id)],
})

self.partner = self.sale_user.partner_id

self.product_no_stock = self.env['product.product'].create({
'name': 'Zero Stock Product',
'type': 'consu',
'list_price': 100.0,
})

self.sale_order = self.env['sale.order'].with_user(self.sale_user).create({
'partner_id': self.partner.id,
'order_line': [(0, 0, {
'product_id': self.product_no_stock.id,
'product_uom_qty': 1.0,
'price_unit': 100.0,
})],
})

def test_block_confirm_no_stock(self):
""" Test that confirming a sale order with zero stock raises an error """
self.assertEqual(self.product_no_stock.qty_available, 0, "Initial stock should be 0")
with self.assertRaises(UserError):
self.sale_order.action_confirm()

def test_allow_confirm_no_stock(self):
""" Test that confirming a sale order with zero stock will not raise an error if `zero_stock_approval` is True """
self.assertEqual(self.product_no_stock.qty_available, 0, "Initial stock should be 0")
self.sale_order.zero_stock_approval = True
self.assertEqual(self.sale_order.zero_stock_approval, True, "Cannot comfirm order of insufficent product")
self.sale_order.action_confirm()

def test_allow_confirm_with_stock(self):
""" Test that adding stock allows the order to be confirmed """
stock_location = self.env.ref('stock.stock_location_stock')
self.product_no_stock.is_storable = True
self.env['stock.quant'].create({
'product_id': self.product_no_stock.id,
'location_id': stock_location.id,
'inventory_quantity': 10.0,
}).action_apply_inventory()

self.assertEqual(self.product_no_stock.qty_available, 10.0, "Stock should be updated to 10")
self.sale_order.action_confirm()
self.assertEqual(self.sale_order.state, 'sale', "Order should be in 'sale' state after confirmation")
13 changes: 13 additions & 0 deletions sale_order_zero_stock_blockage/views/sale_order_view.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="sale_order_view_inherit" model="ir.ui.view">
<field name="name">sale.order.view.inherit</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='payment_term_id']" position="after">
<field name="zero_stock_approval"/>
</xpath>
</field>
</record>
</odoo>