From b01a024b525872112f2234ac9a71728f175c308a Mon Sep 17 00:00:00 2001 From: Karthikeyan Date: Mon, 9 Dec 2024 18:00:02 +0530 Subject: [PATCH] [Karthi] | BAH-4133 | Added. Customer Return new module has been added (#189) --- bahmni_customer_return/__init__.py | 3 + bahmni_customer_return/__manifest__.py | 22 +++ .../data/ir_sequence_data.xml | 12 ++ bahmni_customer_return/models/__init__.py | 5 + .../models/bahmni_customer_return.py | 167 ++++++++++++++++++ .../models/bahmni_customer_return_line.py | 35 ++++ .../models/res_config_settings.py | 23 +++ .../security/ir.model.access.csv | 3 + .../static/description/icon.png | Bin 0 -> 11820 bytes .../views/bahmni_customer_return_views.xml | 143 +++++++++++++++ .../views/res_config_inherit.xml | 27 +++ 11 files changed, 440 insertions(+) create mode 100644 bahmni_customer_return/__init__.py create mode 100644 bahmni_customer_return/__manifest__.py create mode 100644 bahmni_customer_return/data/ir_sequence_data.xml create mode 100644 bahmni_customer_return/models/__init__.py create mode 100644 bahmni_customer_return/models/bahmni_customer_return.py create mode 100644 bahmni_customer_return/models/bahmni_customer_return_line.py create mode 100644 bahmni_customer_return/models/res_config_settings.py create mode 100644 bahmni_customer_return/security/ir.model.access.csv create mode 100644 bahmni_customer_return/static/description/icon.png create mode 100644 bahmni_customer_return/views/bahmni_customer_return_views.xml create mode 100644 bahmni_customer_return/views/res_config_inherit.xml diff --git a/bahmni_customer_return/__init__.py b/bahmni_customer_return/__init__.py new file mode 100644 index 0000000..cde864b --- /dev/null +++ b/bahmni_customer_return/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import models diff --git a/bahmni_customer_return/__manifest__.py b/bahmni_customer_return/__manifest__.py new file mode 100644 index 0000000..589271a --- /dev/null +++ b/bahmni_customer_return/__manifest__.py @@ -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', + ], + +} diff --git a/bahmni_customer_return/data/ir_sequence_data.xml b/bahmni_customer_return/data/ir_sequence_data.xml new file mode 100644 index 0000000..b1bb506 --- /dev/null +++ b/bahmni_customer_return/data/ir_sequence_data.xml @@ -0,0 +1,12 @@ + + + + + Bahmni Customer Sales Return + bahmni.customer.return.sequence + RE + 5 + + + + diff --git a/bahmni_customer_return/models/__init__.py b/bahmni_customer_return/models/__init__.py new file mode 100644 index 0000000..55289ca --- /dev/null +++ b/bahmni_customer_return/models/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- + +from . import bahmni_customer_return +from . import bahmni_customer_return_line +from . import res_config_settings diff --git a/bahmni_customer_return/models/bahmni_customer_return.py b/bahmni_customer_return/models/bahmni_customer_return.py new file mode 100644 index 0000000..48928cd --- /dev/null +++ b/bahmni_customer_return/models/bahmni_customer_return.py @@ -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) diff --git a/bahmni_customer_return/models/bahmni_customer_return_line.py b/bahmni_customer_return/models/bahmni_customer_return_line.py new file mode 100644 index 0000000..565084f --- /dev/null +++ b/bahmni_customer_return/models/bahmni_customer_return_line.py @@ -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 diff --git a/bahmni_customer_return/models/res_config_settings.py b/bahmni_customer_return/models/res_config_settings.py new file mode 100644 index 0000000..7fb09e6 --- /dev/null +++ b/bahmni_customer_return/models/res_config_settings.py @@ -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 diff --git a/bahmni_customer_return/security/ir.model.access.csv b/bahmni_customer_return/security/ir.model.access.csv new file mode 100644 index 0000000..02e4f8a --- /dev/null +++ b/bahmni_customer_return/security/ir.model.access.csv @@ -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 diff --git a/bahmni_customer_return/static/description/icon.png b/bahmni_customer_return/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..564152d35f269f82bfc0967d86b0724c33ccc02d GIT binary patch literal 11820 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 S^Z!1+0WuPb;&q}%!T$&P%P`yk literal 0 HcmV?d00001 diff --git a/bahmni_customer_return/views/bahmni_customer_return_views.xml b/bahmni_customer_return/views/bahmni_customer_return_views.xml new file mode 100644 index 0000000..dffef77 --- /dev/null +++ b/bahmni_customer_return/views/bahmni_customer_return_views.xml @@ -0,0 +1,143 @@ + + + + + + bahmni.customer.return.form + bahmni.customer.return + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + + + +
+ +
+
+
+
+
+ + + + bahmni.customer.return.tree + bahmni.customer.return + + + + + + + + + + + + + + + + + + + bahmni.customer.return.search + bahmni.customer.return + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Customer Return + bahmni.customer.return + tree,form + + + {} + +

No records found. Let's create one!

+
+
+ + + + +
+
diff --git a/bahmni_customer_return/views/res_config_inherit.xml b/bahmni_customer_return/views/res_config_inherit.xml new file mode 100644 index 0000000..7a7113d --- /dev/null +++ b/bahmni_customer_return/views/res_config_inherit.xml @@ -0,0 +1,27 @@ + + + + res.config.settings.view.form.inherit.bahmni.customer.returns + res.config.settings + + + + +
+

Customer Return Configurations

+
+
+ +
+
+
+
+
+
+
+
+