Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ADD] revised_promise_date: added revised promise date with history … #661

Draft
wants to merge 1 commit into
base: 18.0
Choose a base branch
from
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 revised_promise_date/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
11 changes: 11 additions & 0 deletions revised_promise_date/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
'name':'Revised Promise Date' ,
'version' : '1.0',
'author' : "Lucky Prajapati" ,
'category' : 'Sale/Inventory',
'depends' : ["sale_management",'stock','sale_stock'] ,
'data' : ["security/ir.model.access.csv","views/sale_order_views.xml","views/stock_picking_views.xml"],
'installable' : True ,
'application' : True ,
'license' : 'LGPL-3'
}
3 changes: 3 additions & 0 deletions revised_promise_date/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from . import sale_order
from . import promise_date_record
from . import stock_picking
12 changes: 12 additions & 0 deletions revised_promise_date/models/promise_date_record.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from odoo import models , fields

class PromiseDateRecord(models.Model):
_name='promise.date.record'
_description="Store records of the promise date"

sale_order_id = fields.Many2one('sale.order', string="Sale Order", ondelete='cascade')
changed_by = fields.Many2one('res.users', string="Changed By", default=lambda self: self.env.user)
changed_on = fields.Date(string="Changed On", default=fields.Datetime.now)
from_date = fields.Date(string="Previous Revised Promise Date")
to_date = fields.Date(string="New Revised Promise Date")

82 changes: 82 additions & 0 deletions revised_promise_date/models/sale_order.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
from odoo import models, fields, api
from odoo.exceptions import ValidationError

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

original_promise_date = fields.Date()
revised_promise_date = fields.Date(tracking=True)
promise_date_history_ids = fields.One2many('promise.date.record', 'sale_order_id', string="Promise Date History")

@api.onchange('original_promise_date')
def _onchange_original_promise_date(self):
"""Changes the commitment(delivery) date on changes of original promise date when order is in quatation state"""
self.commitment_date = self.original_promise_date

def action_confirm(self):
for order in self:
"""Raise error if original promise date is not set"""
if not order.original_promise_date:
raise ValidationError("You cannot confirm this quotation without setting the Original Promise Date.")

"""Stores the first change in revised promise date None to set date"""
self.env['promise.date.record'].create({
'sale_order_id': order.id,
'changed_by': self.env.user.id,
'from_date': None,
'to_date': order.original_promise_date,
})

"""Changes the commitment(delivery) date when first time original promise date is set"""
order.commitment_date = order.original_promise_date
message = f"Revised Promise Date changed from {None} to {order.original_promise_date} by {self.env.user.name}"
order.message_post(body=message)

return super(SaleOrder, self).action_confirm()

def write(self,vals):
for record in self :
"""Raise error on changing the original promise date after the confirmation of sale order"""
if 'original_promise_date' in vals and record.state == 'sale':
raise ValidationError("You cannot modify the Original Promise Date once the order is confirmed.")

"""Store the value of revised promise date before saving the record to the database"""
old_date = record.revised_promise_date

result = super(SaleOrder,self).write(vals)

"""Store the new revised promise date and save that record to the promise.date.record model"""
for record in self:
new_date = record.revised_promise_date
if old_date != new_date :
record.commitment_date = new_date
if record.id :
self.env['promise.date.record'].create({
'sale_order_id':record.id,
'changed_by':self.env.user.id,
'from_date':old_date,
'to_date':new_date,
})
message = f"Revised Promise Date changed from {old_date or 'Empty'} to {new_date} by {self.env.user.name}"
record.message_post(body=message)

return result

def create(self, vals):
"""Raise error on not setting original promise date"""
if not vals.get('original_promise_date') :
raise ValidationError("Set the Original Promise Date")

""" Raise error on the set of original promise date lower than the order date"""
date_order_value = fields.Date.to_date(vals.get('date_order')) if vals.get('date_order') else None
original_promise_date_value = fields.Date.to_date(vals.get('original_promise_date')) if vals.get('original_promise_date') else None

if date_order_value and original_promise_date_value and date_order_value > original_promise_date_value:
raise ValidationError("The Original Promise date must be greater than the order date")

"""Set the revised promise date on the first creation of the sale order"""
if not vals.get('revised_promise_date') and vals.get('original_promise_date'):
vals['revised_promise_date'] = vals['original_promise_date']

return super(SaleOrder, self).create(vals)

20 changes: 20 additions & 0 deletions revised_promise_date/models/stock_picking.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from odoo import models, fields ,api

class StockPicking(models.Model):
_inherit = "stock.picking"

original_promise_date = fields.Date("Original Promise Date" , compute='_compute_original_promise_date')
sale_order_date = fields.Datetime(related="sale_id.commitment_date", string="Sale Order Date", store=True)
sale_order_date_only = fields.Date(string="Sale Order Date Only",compute='_compute_order_date_only',store=True)

@api.depends('sale_id.original_promise_date','date_deadline')
def _compute_original_promise_date(self):
"""Set the original promise date of stock.picking model with the value of sale.order model's original promise date"""
for record in self :
record.original_promise_date = record.sale_id.original_promise_date

@api.depends('sale_order_date')
def _compute_order_date_only(self):
"""Converts the date_deadline field from datetime to date"""
for record in self:
record.sale_order_date_only = record.sale_order_date.date() if record.sale_order_date else False
2 changes: 2 additions & 0 deletions revised_promise_date/security/ir.model.access.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink
access_promise_date_record,access_promise_date_record,model_promise_date_record,base.group_user,1,1,1,1
1 change: 1 addition & 0 deletions revised_promise_date/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import test_sale_order
73 changes: 73 additions & 0 deletions revised_promise_date/tests/test_sale_order.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import logging
from odoo.tests.common import TransactionCase
from odoo.exceptions import ValidationError

_logger = logging.getLogger(__name__)

class TestSaleOrder(TransactionCase):

def setUp(self):
"""Set up test records before running test cases."""
super(TestSaleOrder, self).setUp()
self.partner = self.env['res.partner'].create({
'name': 'Test Customer'
})
self.sale_order = self.env['sale.order'].create({
'partner_id': self.partner.id,
'original_promise_date': '2024-03-15',
'revised_promise_date': '2024-03-15',
})
_logger.info("\n✅ Setup: Sale Order Created Successfully")

def test_sale_order_creation(self):
"""Test if a Sale Order is created successfully."""
self.assertTrue(self.sale_order, "Sale Order should be created.")
self.assertEqual(str(self.sale_order.original_promise_date), '2024-03-15')
_logger.info("\n✅ Test Passed: Sale Order Creation")

def test_original_promise_date_required(self):
"""Test that a Sale Order cannot be confirmed without an Original Promise Date."""
self.sale_order.original_promise_date = False
with self.assertRaises(ValidationError):
self.sale_order.action_confirm()
_logger.info("\n✅ Test Passed: Original Promise Date Required for Confirmation")

def test_original_promise_date_readonly_after_confirmation(self):
"""Test that Original Promise Date cannot be changed after order is confirmed."""
self.sale_order.action_confirm()
with self.assertRaises(ValidationError):
self.sale_order.write({'original_promise_date': '2024-03-20'})
_logger.info("\n✅ Test Passed: Original Promise Date Cannot be Modified After Confirmation")

def test_revised_promise_date_defaults(self):
"""Test that `revised_promise_date` defaults to `original_promise_date` if empty."""
sale_order = self.env['sale.order'].create({
'partner_id': self.partner.id,
'original_promise_date': '2024-04-01',
'revised_promise_date': None,
})
self.assertEqual(str(sale_order.revised_promise_date), '2024-04-01',
"Revised Promise Date should default to Original Promise Date")
_logger.info("\n✅ Test Passed: Revised Promise Date Defaults to Original Promise Date")

def test_revised_promise_date_change_logs_history(self):
"""Test if changing `revised_promise_date` logs it in the history table."""
old_date = self.sale_order.revised_promise_date
new_date = '2024-03-20'
self.sale_order.write({'revised_promise_date': new_date})
history_record = self.env['promise.date.record'].search([
('sale_order_id', '=', self.sale_order.id)
], order="id desc", limit=1)
self.assertEqual(str(history_record.from_date), str(old_date))
self.assertEqual(str(history_record.to_date), new_date)
_logger.info("\n✅ Test Passed: Revised Promise Date Change Logged in History")

def test_promise_date_record_creation(self):
"""Test that a promise date record is created when revised_promise_date changes."""
self.sale_order.write({'revised_promise_date': '2024-03-25'})
history_record = self.env['promise.date.record'].search([
('sale_order_id', '=', self.sale_order.id)
], order="id desc", limit=1)
self.assertTrue(history_record, "A promise date record should be created.")
self.assertEqual(str(history_record.to_date), '2024-03-25')
_logger.info("\n✅ Test Passed: Promise Date Record Created")
28 changes: 28 additions & 0 deletions revised_promise_date/views/sale_order_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<odoo>
<record id="sale_order_form_view_inherit" model="ir.ui.view">
<field name="name">sale.order.form.inherit.revised.date</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="original_promise_date" string="Original Promise Date" />
<field name="revised_promise_date" string="Revised Promise Date" invisible="state != 'sale'" />
</xpath>
<xpath expr="//field[@name='commitment_date']" position="attributes">
<attribute name="readonly">True</attribute>
</xpath>
<xpath expr="//page" position="after">
<page string="Promise Date History" name="promise_date_history">
<field name="promise_date_history_ids" nolabel="1">
<list>
<field name="changed_on"/>
<field name="changed_by"/>
<field name="from_date"/>
<field name="to_date"/>
</list>
</field>
</page>
</xpath>
</field>
</record>
</odoo>
16 changes: 16 additions & 0 deletions revised_promise_date/views/stock_picking_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<odoo>
<record id="stock_picking_form_view" model='ir.ui.view'>
<field name='name'>stock.picking.form.view.inherit.revised.date</field>
<field name='model'>stock.picking</field>
<field name='inherit_id' ref='stock.view_picking_form'/>
<field name='arch' type='xml'>
<xpath expr="//field[@name='date_deadline']" position='before'>
<field name="original_promise_date" readonly='1'/>
</xpath>
<xpath expr="//field[@name='date_deadline']" position="attributes">
<attribute name="string">Revised Promise Date</attribute>
<attribute name="decoration-danger">sale_order_date_only != original_promise_date</attribute>
</xpath>
</field>
</record>
</odoo>