-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Karthi] | BAH-4133 | Added. Customer Return new module has been added (
#189)
- Loading branch information
1 parent
e41dfeb
commit b01a024
Showing
11 changed files
with
440 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# -*- coding: utf-8 -*- | ||
|
||
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,22 @@ | ||
# -*- coding: utf-8 -*- | ||
{ | ||
'name': "Bahmni Customer Sales Return", | ||
'summary': """Customized Bahmni Customer Sales Return module""", | ||
'description': """ To support a simplified return flow, a user form needs to be designed wherein the customer can be selected and the product items can be entered. """, | ||
'author': "Karthikeyan S", | ||
'website': "https://www.bahmni.org", | ||
'category': 'Sales', | ||
"license": "LGPL-3", | ||
'version': '0.1', | ||
# any module necessary for this one to work correctly | ||
'depends': ['base','mail','product',"bahmni_sale"], | ||
|
||
# always loaded | ||
'data': [ | ||
'security/ir.model.access.csv', | ||
'data/ir_sequence_data.xml', | ||
'views/bahmni_customer_return_views.xml', | ||
'views/res_config_inherit.xml', | ||
], | ||
|
||
} |
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,12 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<odoo noupdate="1"> | ||
|
||
<record id="seq_bahmni_customer_return" model="ir.sequence"> | ||
<field name="name">Bahmni Customer Sales Return</field> | ||
<field name="code">bahmni.customer.return.sequence</field> | ||
<field name="prefix">RE</field> | ||
<field name="padding">5</field> | ||
<field name="company_id" eval="False"/> | ||
</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,5 @@ | ||
# -*- coding: utf-8 -*- | ||
|
||
from . import bahmni_customer_return | ||
from . import bahmni_customer_return_line | ||
from . import res_config_settings |
167 changes: 167 additions & 0 deletions
167
bahmni_customer_return/models/bahmni_customer_return.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,167 @@ | ||
# -*- coding: utf-8 -*- | ||
|
||
import time | ||
from datetime import timedelta, datetime | ||
from odoo import models, fields, api, _ | ||
from odoo.exceptions import UserError | ||
|
||
RES_USERS = 'res.users' | ||
TIME_FORMAT = '%Y-%m-%d %H:%M:%S' | ||
|
||
CUSTOM_STATUS = [ | ||
('draft', 'Draft'), | ||
('confirm', 'Confirmed')] | ||
|
||
ENTRY_MODE = [('manual','Manual'), | ||
('auto', 'Auto')] | ||
|
||
class BahmniCustomerReturn(models.Model): | ||
_name = 'bahmni.customer.return' | ||
_description = 'Customer Sales Return' | ||
_inherit = ['mail.thread', 'mail.activity.mixin', 'avatar.mixin'] | ||
_order = 'entry_date desc' | ||
|
||
|
||
name = fields.Char(string="Return No") | ||
entry_date = fields.Datetime('Entry Date',default=fields.Datetime.now) | ||
location_id = fields.Many2one('stock.location', 'Return Location',domain=[('active', '=', True),('usage', '=', 'internal')]) | ||
customer_id = fields.Many2one('res.partner', 'Customer',domain=[('active', '=', True),('customer_rank', '>', 0)]) | ||
|
||
status = fields.Selection(selection=CUSTOM_STATUS, string="Status", copy=False, default="draft", readonly=True, store=True, tracking=True) | ||
remarks = fields.Text(string="Remarks", copy=False) | ||
company_id = fields.Many2one('res.company', copy=False, default=lambda self: self.env.company, ondelete='restrict', readonly=True, required=True) | ||
currency_id = fields.Many2one('res.currency', string="Currency", copy=False, default=lambda self: self.env.company.currency_id.id, ondelete='restrict', readonly=True, tracking=True) | ||
|
||
tot_amt = fields.Float(string="Return Amount", store=True, compute='_compute_all_line') | ||
product_ids = fields.Many2many('product.product','customer_returns_products','return_id','product_id','Products',domain=[('active', '=', True),('type','=','product')]) | ||
|
||
|
||
active = fields.Boolean(string="Visible", default=True) | ||
entry_mode = fields.Selection(selection=ENTRY_MODE, string="Entry Mode", copy=False, default="manual", tracking=True, readonly=True) | ||
crt_date = fields.Datetime(string="Creation Date", copy=False, default=fields.Datetime.now, readonly=True) | ||
user_id = fields.Many2one(RES_USERS, string="Created By", copy=False, default=lambda self: self.env.user.id, ondelete='restrict', readonly=True) | ||
confirm_date = fields.Datetime(string="Comfirmed Date", copy=False, readonly=True) | ||
confirm_user_id = fields.Many2one(RES_USERS, string="Comfirmed By", copy=False, ondelete='restrict', readonly=True) | ||
update_date = fields.Datetime(string="Last Updated Date", copy=False, readonly=True) | ||
update_user_id = fields.Many2one(RES_USERS, string="Last Updated By", copy=False, ondelete='restrict', readonly=True) | ||
|
||
|
||
line_ids = fields.One2many('bahmni.customer.return.line', 'header_id', string="Return Details", copy=True) | ||
|
||
@api.onchange('product_ids') | ||
def onchange_product_ids(self): | ||
if self.product_ids: | ||
now = datetime.now() | ||
threshold_days = int(self.env['ir.config_parameter'].sudo().get_param('bahmni_auto_customer_return.no_of_days_threshold')) | ||
date_threshold = now - timedelta(days=threshold_days) | ||
|
||
# Get the currently selected product IDs | ||
selected_product_ids = self.product_ids.ids | ||
|
||
# Get product IDs already present in the lines | ||
existing_product_ids = self.line_ids.mapped('product_id.id') | ||
|
||
# Determine newly added product IDs | ||
new_product_ids = list(set(selected_product_ids) - set(existing_product_ids)) | ||
|
||
# Fetch sale order lines for the newly added products | ||
sale_order_lines = self.env['sale.order.line'].search([ | ||
('order_partner_id', '=', self.customer_id.id), | ||
('product_id', 'in', new_product_ids), | ||
('order_id.date_order', '>=', date_threshold) | ||
]) | ||
|
||
# Get products without matching sale orders | ||
products_without_sales = self.env['product.product'].browse(new_product_ids).filtered( | ||
lambda product: product.id not in sale_order_lines.mapped('product_id.id') | ||
) | ||
|
||
if products_without_sales: | ||
# Generate error message for products without sales | ||
product_names = ', '.join(products_without_sales.mapped('name')) | ||
raise UserError(f"{product_names} have no sale orders in the last {threshold_days} days") | ||
|
||
# Remove lines for products no longer selected | ||
self.line_ids = self.line_ids.filtered(lambda line: line.product_id.id in selected_product_ids) | ||
|
||
# Add new lines for products not already in `line_ids` | ||
for line in sale_order_lines: | ||
if line.product_id.id not in existing_product_ids: | ||
self.line_ids = [(0, 0, { | ||
'header_id': self.id, | ||
'product_id': line.product_id.id, | ||
'order_qty': line.product_uom_qty, | ||
'uom_id': line.product_uom.id, | ||
'lot_id': line.lot_id.id if line.lot_id else False, | ||
'expiry_date': line.expiry_date, | ||
'unit_price': line.price_unit, | ||
'sale_date': line.order_id.date_order, | ||
'sale_order_ref': line.order_id.name, | ||
'sale_order_id': line.order_id.id, | ||
'sale_order_line_id': line.id, | ||
})] | ||
else: | ||
# If no products are selected, clear all lines | ||
self.line_ids = [(5, 0, 0)] | ||
|
||
|
||
@api.depends('line_ids') | ||
def _compute_all_line(self): | ||
for data in self: | ||
data.tot_amt = sum(line.sub_total for line in data.line_ids) | ||
|
||
|
||
def display_warnings(self, warning_msg, kw): | ||
if warning_msg: | ||
formatted_messages = "\n".join(warning_msg) | ||
if not kw.get('mode_of_call'): | ||
raise UserError(_(formatted_messages)) | ||
else: | ||
return [formatted_messages] | ||
else: | ||
return False | ||
|
||
def validate_detail_lines(self, detail_line, warning_msg): | ||
if detail_line.qty <= 0: | ||
warning_msg.append(f"({detail_line.product_id.name}) return quantity should be greater than zero") | ||
if detail_line.unit_price <= 0: | ||
warning_msg.append(f"({detail_line.product_id.name}) unit price should be greater than zero") | ||
if detail_line.qty > detail_line.order_qty: | ||
warning_msg.append(f"({detail_line.description}) quantity cannot be greater than the ordered quantity") | ||
|
||
def validate_line_items(self, warning_msg): | ||
if not self.line_ids: | ||
warning_msg.append("System not allow to confirm with empty line details") | ||
else: | ||
for detail_line in self.line_ids: | ||
self.validate_detail_lines(detail_line, warning_msg) | ||
|
||
def validations(self, **kw): | ||
warning_msg = [] | ||
if self.status in ('draft'): | ||
self.validate_line_items(warning_msg) | ||
|
||
return self.display_warnings(warning_msg, kw) | ||
|
||
|
||
def entry_confirm(self): | ||
if self.status in ('draft'): | ||
self.validations() | ||
self.name = self.env['ir.sequence'].next_by_code('bahmni.customer.return.sequence') or 'New' | ||
self.write({'status': 'confirm', | ||
'confirm_user_id': self.env.user.id, | ||
'confirm_date': time.strftime(TIME_FORMAT) | ||
}) | ||
return True | ||
|
||
def unlink(self): | ||
for rec in self: | ||
if rec.status != 'draft': | ||
raise UserError(_("You can't delete confirmed entries")) | ||
models.Model.unlink(rec) | ||
return True | ||
|
||
def write(self, vals): | ||
vals.update({'update_date': time.strftime(TIME_FORMAT), | ||
'update_user_id': self.env.user.id}) | ||
return super(BahmniCustomerReturn, self).write(vals) |
35 changes: 35 additions & 0 deletions
35
bahmni_customer_return/models/bahmni_customer_return_line.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,35 @@ | ||
# -*- coding: utf-8 -*- | ||
import time | ||
from datetime import timedelta, datetime | ||
from odoo import models, fields, api, _ | ||
from odoo.exceptions import UserError | ||
|
||
from odoo.exceptions import UserError | ||
|
||
class BahmniCustomerReturnLine(models.Model): | ||
_name = 'bahmni.customer.return.line' | ||
_description = 'Return Details' | ||
_order = 'id asc' | ||
|
||
header_id = fields.Many2one('bahmni.customer.return', string="Header Ref", index=True, required=True, ondelete='cascade') | ||
product_id = fields.Many2one('product.product', 'Product Name',domain=[('active', '=', True),('type','=','product')]) | ||
qty = fields.Float(string="Return Qty") | ||
order_qty = fields.Float(string="Sale Order Qty") | ||
uom_id = fields.Many2one('uom.uom', string="UOM", ondelete='restrict') | ||
lot_id = fields.Many2one('stock.lot', string="Batch No") | ||
expiry_date = fields.Datetime(string="Expiry Date") | ||
unit_price = fields.Float(string="Unit Price") | ||
sub_total = fields.Float(string="Sub Total") | ||
sale_date = fields.Date('Sale Date') | ||
sale_order_ref = fields.Char(string="Sale Order Ref") | ||
sale_order_id = fields.Many2one('sale.order', string="Sale Order") | ||
sale_order_line_id = fields.Many2one('sale.order.line', string="Sale Order Line") | ||
company_id = fields.Many2one('res.company', copy=False, default=lambda self: self.env.company, ondelete='restrict', readonly=True, required=True) | ||
|
||
|
||
@api.onchange('qty') | ||
def onchange_qty(self): | ||
if self.qty: | ||
if self.qty > self.order_qty: | ||
raise UserError(_("Return quantity cannot be greater than ordered quantity.")) | ||
self.sub_total = self.qty * self.unit_price |
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,23 @@ | ||
from odoo import models, fields, api | ||
|
||
|
||
class ResConfigSettings(models.TransientModel): | ||
_inherit = "res.config.settings" | ||
|
||
allowed_days = fields.Integer(string="Maximum days limit for customer return", | ||
config_parameter="bahmni_auto_customer_return.no_of_days_threshold") | ||
|
||
def set_values(self): | ||
res = super(ResConfigSettings, self).set_values() | ||
self.env['ir.config_parameter'].sudo().set_param('bahmni_auto_customer_return.no_of_days_threshold', | ||
self.allowed_days) | ||
return res | ||
|
||
@api.model | ||
def get_values(self): | ||
res = super(ResConfigSettings, self).get_values() | ||
ICPSudo = self.env['ir.config_parameter'].sudo() | ||
res.update( | ||
allowed_days=ICPSudo.get_param('bahmni_auto_customer_return.no_of_days_threshold'), | ||
) | ||
return res |
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 @@ | ||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink | ||
access_bahmni_customer_return,Customer Return,model_bahmni_customer_return,base.group_user,1,1,1,1 | ||
access_bahmni_customer_return_line,Customer Return Line,model_bahmni_customer_return_line,base.group_user,1,1,1,1 |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.