diff --git a/tender_management_sales/README.rst b/tender_management_sales/README.rst new file mode 100644 index 000000000..2f12cd6c8 --- /dev/null +++ b/tender_management_sales/README.rst @@ -0,0 +1,48 @@ +.. image:: https://img.shields.io/badge/license-AGPL--3-blue.svg + :target: https://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +Tender Management Sales +======================= +This module allows to manage different tenders in odoo along with option for comparing different sale order lines and +choose best one. + +License +------- +General Public License, Version 3 (AGPL v3). +(https://www.odoo.com/documentation/user/16.0/legal/licenses/licenses.html) + +Configuration +============= +No additional configuration required + +Company +------- +* `Cybrosys Techno Solutions `__ + +Credits +------- +Developers: Nikhil M @cybrosys, + +Contacts +-------- +* Mail Contact : odoo@cybrosys.com +* Website : https://cybrosys.com + +Bug Tracker +----------- +Bugs are tracked on GitHub Issues. In case of trouble, please check there if +your issue has already been reported. + +Maintainer +========== +.. image:: https://cybrosys.com/images/logo.png + :target: https://cybrosys.com + +This module is maintained by Cybrosys Technologies. + +For support and more information, please visit `Our Website `__ + +Further information +=================== +HTML Description: ``__ diff --git a/tender_management_sales/__init__.py b/tender_management_sales/__init__.py new file mode 100644 index 000000000..a46aad785 --- /dev/null +++ b/tender_management_sales/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Nikhil M (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +############################################################################### +from . import models +from . import wizard diff --git a/tender_management_sales/__manifest__.py b/tender_management_sales/__manifest__.py new file mode 100644 index 000000000..1cbf03bbc --- /dev/null +++ b/tender_management_sales/__manifest__.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Nikhil M (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +############################################################################### +{ + 'name': 'Tender Management Sales', + 'version': "16.0.1.0.0", + 'summary': 'Tender Management in Sales and Option to Compare Orders', + 'description': """Tender Management in Sales and Option to Compare Orders""", + 'category': 'Sale', + 'author': 'Cybrosys Techno solutions', + 'company': 'Cybrosys Techno Solutions', + 'maintainer': 'Cybrosys Techno Solutions', + 'website': 'https://www.cybrosys.com', + 'depends': ['sale_management'], + 'data': [ + 'security/ir.model.access.csv', + 'data/sale_tender_data.xml', + 'views/tender_sales_views.xml', + 'views/sale_order_views.xml', + 'wizard/tender_sales_create_alternative.xml', + ], + 'assets': { + 'web.assets_backend': [ + 'tender_management_sales/static/src/widgets/sale_order_alternatives_widget.js', + 'tender_management_sales/static/src/widgets/sale_order_alternatives_widget.scss', + 'tender_management_sales/static/src/widgets/sale_order_alternatives_widget.xml', + 'tender_management_sales/static/src/views/list/sale_order_line_compare_list_renderer.js', + 'tender_management_sales/static/src/views/list/sale_order_line_compare_list_view.js', + ], + }, + 'license': 'AGPL-3', + 'images': ['static/description/banner.png'], + 'installable': True, + 'auto_install': False, + 'application': False, +} diff --git a/tender_management_sales/data/sale_tender_data.xml b/tender_management_sales/data/sale_tender_data.xml new file mode 100644 index 000000000..b93ff42bb --- /dev/null +++ b/tender_management_sales/data/sale_tender_data.xml @@ -0,0 +1,13 @@ + + + + + + Sale Tender + sale.tender.order + ST + 5 + + + + diff --git a/tender_management_sales/doc/RELEASE_NOTES.md b/tender_management_sales/doc/RELEASE_NOTES.md new file mode 100644 index 000000000..9fd4914b5 --- /dev/null +++ b/tender_management_sales/doc/RELEASE_NOTES.md @@ -0,0 +1,6 @@ +## Module + +#### 02.09.2024 +#### Version 16.0.1.0.0 +#### ADD +- Initial Commit for Tender Management Sales diff --git a/tender_management_sales/models/__init__.py b/tender_management_sales/models/__init__.py new file mode 100644 index 000000000..48c5c2cdf --- /dev/null +++ b/tender_management_sales/models/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Nikhil M (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +############################################################################### +from . import sale_order +from . import tender_sales diff --git a/tender_management_sales/models/sale_order.py b/tender_management_sales/models/sale_order.py new file mode 100644 index 000000000..7a8d5d428 --- /dev/null +++ b/tender_management_sales/models/sale_order.py @@ -0,0 +1,296 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Nikhil M (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +############################################################################### +from odoo import api, fields, models, _, Command +from collections import defaultdict + + +class SaleOrderGroup(models.Model): + """Creating a model to group all the orders for tender management.""" + _name = 'sale.order.group' + _description = "Technical model to group Orders for tender management." + + order_ids = fields.One2many('sale.order', 'sale_group_id',help='Sale orders') + + def write(self, vals): + """Remove records where the length of the order_ids is less than + or equal to 1""" + res = super().write(vals) + self.filtered(lambda g: len(g.order_ids) <= 1).unlink() + return res + + +class SaleOrder(models.Model): + _inherit = 'sale.order' + + tender_id = fields.Many2one('sale.tender', + string='Sale Agreement', + copy=False, help='Tender being used in order') + sale_group_id = fields.Many2one('sale.order.group', + help='Sale Group') + alternative_so_ids = fields.One2many( + 'sale.order', related='sale_group_id.order_ids', readonly=False, + domain="[('id', '!=', id), ('state', 'in', ['draft', 'sent'])]", + string="Alternative SOs", check_company=True, + help="Other potential sale orders for selling products") + + @api.onchange('sale_order_template_id') + def _onchange_sale_order_template_id(self): + """ + This method is triggered when the 'sale_order_template_id' field is changed. + It overrides the default behavior to check for the presence of a 'tender_id' field: + """ + # Call the parent class method using super() + if self.tender_id: + if self.sale_order_template_id: + super(SaleOrder, self)._onchange_sale_order_template_id() + else: + super(SaleOrder, self)._onchange_sale_order_template_id() + + def write(self, vals): + """Overriding the write function to add the cases in case of tender + is added.""" + if vals.get('sale_group_id', False): + orig_sale_group = self.sale_group_id + result = super(SaleOrder,self).write(vals) + if vals.get('alternative_so_ids', False): + if not self.sale_group_id and len(self.alternative_so_ids + self) > len(self): + # create/merge a new group + self.env['sale.order.group'].create({'order_ids': [Command.set(self.ids + self.alternative_so_ids.ids)]}) + elif self.sale_group_id and len(self.alternative_so_ids + self) <= 1: + # write in purchase group isn't called so we have to manually + # unlink obsolete groups here + self.sale_group_id.unlink() + if vals.get('sale_group_id', False): + additional_groups = orig_sale_group - self.sale_group_id + if additional_groups: + additional_sos = (additional_groups.order_ids - self.saled_group_id.order_ids) + additional_groups.unlink() + if additional_sos: + self.sale_group_id.order_ids |= additional_sos + + return result + + @api.model_create_multi + def create(self, vals_list): + """Overriding the Create function to update vals in case of tender id.""" + orders = super().create(vals_list) + if self.env.context.get('origin_so_id'): + origin_so_id = self.env['sale.order'].browse( + self.env.context.get('origin_so_id')) + if origin_so_id.sale_group_id: + origin_so_id.sale_group_id.order_ids |= orders + else: + self.env['sale.order.group'].create({'order_ids': [Command.set(origin_so_id.ids + orders.ids)]}) + return orders + + def action_confirm(self): + """Updated the state of other related orders and the agreement state on confirming the order.""" + res = super(SaleOrder, self).action_confirm() + for so in self: + if not so.tender_id: + continue + if so.tender_id.type_id.exclusive == 'exclusive': + others_so = so.tender_id.mapped('sale_order_ids').filtered(lambda r: r.id != so.id) + others_so.action_cancel() + if so.state not in ['draft', 'sent']: + so.tender_id.action_done() + return res + + @api.onchange('tender_id') + def _onchange_tender_id(self): + """Function to update all the values from the tender from agreement to the sale order.""" + if not self.tender_id: + return + if self.sale_order_template_id: + self.sale_order_template_id = False + data = [fields.Command.clear()] + self.sale_order_option_ids = data + self.order_line = data + + self = self.with_company(self.company_id) + tender = self.tender_id + if self.partner_id: + partner = self.partner_id + else: + partner = tender.customer_id + + FiscalPosition = self.env['account.fiscal.position'] + fpos = FiscalPosition.with_company( + self.company_id)._get_fiscal_position(partner) + self.partner_id = partner.id + self.company_id = tender.company_id.id + self.currency_id = tender.currency_id.id + if not self.origin or tender.name not in self.origin.split(', '): + if self.origin: + if tender.name: + self.origin = self.origin + ', ' + tender.name + else: + self.origin = tender.name + self.note = tender.description + self.date_order = fields.Datetime.now() + + if tender.type_id.line_copy != 'copy': + return + + # Create SO lines if necessary + order_lines = [] + for line in tender.line_ids: + # Compute name + product_lang = line.product_id.with_context( + lang=partner.lang or self.env.user.lang, + partner_id=partner.id + ) + name = product_lang.display_name + if product_lang.description_purchase: + name += '\n' + product_lang.description_purchase + + # Compute taxes + taxes_ids = fpos.map_tax(line.product_id.supplier_taxes_id.filtered(lambda tax: tax.company_id == tender.company_id)).ids + # Compute quantity and price_unit + if line.product_uom_id != line.product_id.uom_id: + product_qty = line.product_uom_id._compute_quantity(line.product_qty, line.product_id.uom_id) + price_unit = line.product_uom_id._compute_price(line.price_unit, line.product_id.uom_id) + else: + product_qty = line.product_qty + price_unit = line.price_unit + + if tender.type_id.quantity_copy != 'copy': + product_qty = 0 + + # Create SO line + order_line_values = line._prepare_sale_order_line( + name=name, product_qty=product_qty, price_unit=price_unit, + taxes_ids=taxes_ids) + order_lines.append((0, 0, order_line_values)) + self.order_line = order_lines + + def action_compare_alternative_lines(self): + """" Function to return to the view of line compare tree.""" + ctx = dict( + self.env.context, + search_default_product=True, + sale_order_id=self.id, + ) + view_id = self.env.ref('tender_management_sales.sale_order_line_compare_tree').id + return { + 'name': _('Compare Order Lines'), + 'type': 'ir.actions.act_window', + 'view_mode': 'list', + 'res_model': 'sale.order.line', + 'views': [(view_id, "list")], + 'domain': [('order_id', 'in', (self | self.alternative_so_ids).ids), ('display_type', '=', False)], + 'context': ctx, + } + + def action_create_alternative(self): + """Function to create alternative orders.""" + ctx = dict(**self.env.context, default_origin_so_id=self.id) + return { + 'name': _('Create alternative'), + 'type': 'ir.actions.act_window', + 'view_mode': 'form', + 'res_model': 'sale.tender.create.alternative', + 'view_id': self.env.ref('tender_management_sales.sale_tender_create_alternative_form').id, + 'target': 'new', + 'context': ctx, + } + + def get_tender_best_lines(self): + """" Function to get the best order lines from grouped orders.""" + product_to_best_price_line = defaultdict(lambda: self.env['sale.order.line']) + product_to_best_price_unit = defaultdict(lambda: self.env['sale.order.line']) + so_alternatives = self | self.alternative_so_ids + + multiple_currencies = False + if len(so_alternatives.currency_id) > 1: + multiple_currencies = True + + for line in so_alternatives.order_line: + if not line.product_uom_qty or not line.price_subtotal or line.state in ['cancel', 'purchase', 'done']: + continue + + if not product_to_best_price_line[line.product_id]: + product_to_best_price_line[line.product_id] = line + product_to_best_price_unit[line.product_id] = line + else: + price_subtotal = line.price_subtotal + price_unit = line.price_unit + current_price_subtotal = product_to_best_price_line[line.product_id][0].price_subtotal + current_price_unit = product_to_best_price_unit[line.product_id][0].price_unit + if multiple_currencies: + price_subtotal /= line.order_id.currency_rate + price_unit /= line.order_id.currency_rate + current_price_subtotal /= product_to_best_price_line[line.product_id][0].order_id.currency_rate + current_price_unit /= product_to_best_price_unit[line.product_id][0].order_id.currency_rate + if current_price_subtotal < price_subtotal: + product_to_best_price_line[line.product_id] = line + elif current_price_subtotal == price_subtotal: + product_to_best_price_line[line.product_id] |= line + + if current_price_unit < price_unit: + product_to_best_price_unit[line.product_id] = line + elif current_price_unit == price_unit: + product_to_best_price_unit[line.product_id] |= line + + best_price_ids = set() + best_price_unit_ids = set() + for lines in product_to_best_price_line.values(): + best_price_ids.update(lines.ids) + for lines in product_to_best_price_unit.values(): + best_price_unit_ids.update(lines.ids) + return list(best_price_ids), list(best_price_unit_ids) + + +class SaleOrderLine(models.Model): + _inherit = 'sale.order.line' + + def action_clear_quantities(self): + """" Function to clear quantities from the current line.""" + zeroed_lines = self.filtered(lambda l: l.state not in ['cancel', 'sale', 'done']) + zeroed_lines.write({'product_uom_qty': 0}) + if len(self) > len(zeroed_lines): + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'title': _("Some not cleared"), + 'message': _("Some quantities were not cleared because their status is not a Draft."), + 'sticky': False, + } + } + return False + + def action_choose(self): + """" Function to choose a line among different order lines so that other lines quantities will update to null.""" + order_lines = (self.order_id | self.order_id.alternative_so_ids).mapped('order_line') + order_lines = order_lines.filtered(lambda l: l.product_uom_qty and l.product_id.id in self.product_id.ids and l.id not in self.ids) + if order_lines: + return order_lines.action_clear_quantities() + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'title': _("Nothing to clear"), + 'message': _("There are no quantities to clear."), + 'sticky': False, + } + } diff --git a/tender_management_sales/models/tender_sales.py b/tender_management_sales/models/tender_sales.py new file mode 100644 index 000000000..e7d9f01f7 --- /dev/null +++ b/tender_management_sales/models/tender_sales.py @@ -0,0 +1,182 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Nikhil M (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +############################################################################### +from odoo import api, fields, models, _ +from odoo.exceptions import UserError + +SALE_TENDER_STATES = [ + ('draft', 'Draft'), + ('ongoing', 'Ongoing'), + ('in_progress', 'Confirmed'), + ('open', 'Bid Selection'), + ('done', 'Closed'), + ('cancel', 'Cancelled') +] + + +class SaleTenderType(models.Model): + """Creating a model to store the tender type.""" + + _name = "sale.tender.type" + _description = "Sale Tender Type" + + name = fields.Char(string='Agreement Type', required=True, translate=True,help="Name") + exclusive = fields.Selection([ + ('exclusive', 'Select only one Quotation (exclusive)'), ('multiple', 'Select multiple Quotation (non-exclusive)')], + string='Agreement Selection Type', required=True, default='multiple', + help="""Select only one Quotation (exclusive): when a sale order is confirmed, cancel the remaining sale order.\n + Select multiple Quotation (non-exclusive): allows multiple sale orders. On confirmation of a sale order it does not cancel the remaining orders""") + quantity_copy = fields.Selection([ + ('copy', 'Use quantities of agreement'), ('none', 'Set quantities manually')], + string='Quantities', required=True, default='none',help="To copy quantity") + line_copy = fields.Selection([ + ('copy', 'Use lines of agreement'), ('none', 'Do not create Quotations lines automatically')], + string='Lines', required=True, default='copy',help="To copy line") + + +class SaleTender(models.Model): + """Creating a model to record all the sale tender agreements.""" + _name = "sale.tender" + _description = "Sale Tender" + _order = 'id desc' + _inherit = ['mail.thread', 'mail.activity.mixin'] + + @api.depends('sale_order_ids') + def _compute_orders_number(self): + """Function to compute the number of associated orders for the agreement.""" + for tender in self: + tender.order_count = len(tender.sale_order_ids) + + def action_in_progress(self): + """Function to activate the current agreement.""" + self.ensure_one() + if not self.line_ids: + raise UserError(_("You cannot confirm agreement '%s' because there is no product line.", self.name)) + for tender_line in self.line_ids: + if tender_line.price_unit <= 0.0: + raise UserError(_('You cannot confirm the Tender without price.')) + if tender_line.product_qty <= 0.0: + raise UserError(_('You cannot confirm the Tender order without quantity.')) + self.write({'state': 'ongoing'}) + # Set the sequence number regarding the tender type + if self.name == 'New': + self.name = self.env['ir.sequence'].next_by_code('sale.tender.order') + + def action_cancel(self): + """Function to cancel the current agreement.""" + self.write({'state': 'cancel'}) + + def action_done(self): + """ + Generate all sale order based on selected lines, should only be called on one agreement at a time + """ + if any(sale_order.state in ['draft', 'sent'] for sale_order in self.mapped('sale_order_ids')): + raise UserError(_('You have to cancel or validate every Order before closing the sale tender.')) + self.write({'state': 'done'}) + + name = fields.Char('Reference', required=True, copy=False, default='New',readonly=True,help="Name") + + order_count = fields.Integer(compute='_compute_orders_number', + string='Number of Orders',help="Count of orders") + customer_id = fields.Many2one('res.partner', string="Customer", + domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]",help="Customer Choosen") + type_id = fields.Many2one('sale.tender.type', + string="Agreement Type", required=True,help="Type") + ordering_date = fields.Date(string="Ordering Date", tracking=True,help="Order Date") + date_end = fields.Datetime(string='Agreement Deadline', tracking=True,help="End Date") + schedule_date = fields.Date(string='Delivery Date', index=True, + help="The expected and scheduled delivery date where all the products are received", + tracking=True) + user_id = fields.Many2one( + 'res.users', string='Sales Representative', + default=lambda self: self.env.user, check_company=True,help="Username") + description = fields.Html(help="Description") + company_id = fields.Many2one('res.company', string='Company', required=True, + default=lambda self: self.env.company,help="Company") + sale_order_ids = fields.One2many('sale.order', 'tender_id', + string='Sale Orders', + states={'done': [('readonly', True)]},help="Sale orders") + line_ids = fields.One2many('sale.tender.line', 'tender_id', + string='Products to Sell', + states={'done': [('readonly', True)]}, copy=True,help="Tender Lines") + + state = fields.Selection(SALE_TENDER_STATES, + 'Status', tracking=True, required=True, + copy=False, default='draft',help="Status") + + currency_id = fields.Many2one('res.currency', 'Currency', required=True, + default=lambda + self: self.env.company.currency_id.id,help="Currency") + + +class SaleTender_idLine(models.Model): + """Creating the model to store the lines in the tender.""" + _name = "sale.tender.line" + _inherit = 'analytic.mixin' + _description = "Sale Tender Line" + _rec_name = 'product_id' + + @api.onchange('product_id') + def _onchange_product_id(self): + """Function to update the line price.""" + self.price_unit = self.product_id.list_price + self.product_qty = 1 + + @api.model_create_multi + def create(self, vals_list): + """Overriding the create function to update the uom value and also add restrictions.""" + for vals in vals_list: + if not vals.get('product_uom_id'): + vals['product_uom_id'] = self.env["product.product"].browse( + vals.get('product_id')).uom_id.id + lines = super().create(vals_list) + for line, vals in zip(lines, vals_list): + if line.tender_id.state not in ['draft', 'cancel','done'] and line.tender_id.type_id.is_quantity_copy == 'none': + if vals['price_unit'] <= 0.0: + raise UserError( + _('You cannot confirm the blanket order without price.')) + return lines + + product_id = fields.Many2one('product.product', string='Product', domain=[('sale_ok', '=', True)], required=True,help="Product") + product_uom_id = fields.Many2one('uom.uom', string='Product Unit of Measure', domain="[('category_id', '=', product_uom_category_id)]",help="Uom") + product_uom_category_id = fields.Many2one(related='product_id.uom_id.category_id',help="Uom Category") + product_qty = fields.Float(string='Quantity', digits='Product Unit of Measure',help="Quantity") + product_description_variants = fields.Char('Custom Description',help="Variants Description") + price_unit = fields.Float(string='Unit Price', digits='Product Price',help="Price Unit") + tender_id = fields.Many2one('sale.tender', required=True, string='Sale Agreement', ondelete='cascade',help="Tender") + company_id = fields.Many2one('res.company', related='tender_id.company_id', string='Company', store=True, readonly=True,help="Company") + schedule_date = fields.Date(string='Scheduled Date',help="Scheduled Date") + + def _prepare_sale_order_line(self, name, product_qty=0.0, price_unit=0.0, taxes_ids=False): + """Function to prepare the required values for sale order lines.""" + self.ensure_one() + if self.product_description_variants: + name += '\n' + self.product_description_variants + res = { + 'name': name, + 'product_id': self.product_id.id, + 'product_uom': self.product_uom_id.id, + 'product_uom_qty': product_qty, + 'price_unit': price_unit, + 'tax_id': [(6, 0, taxes_ids)], + 'analytic_distribution': self.analytic_distribution, + } + return res diff --git a/tender_management_sales/security/ir.model.access.csv b/tender_management_sales/security/ir.model.access.csv new file mode 100644 index 000000000..7d6fe1c93 --- /dev/null +++ b/tender_management_sales/security/ir.model.access.csv @@ -0,0 +1,6 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_sale_tender,sale.tender,model_sale_tender,base.group_user,1,1,1,1 +access_sale_tender_type,sale.tender.type,model_sale_tender_type,base.group_user,1,1,1,1 +access_sale_tender_line,sale.tender.line,model_sale_tender_line,base.group_user,1,1,1,1 +access_sale_order_group,sale.order.group,model_sale_order_group,base.group_user,1,1,1,1 +access_sale_tender_create_alternative,sale.tender.create.alternative,model_sale_tender_create_alternative,base.group_user,1,1,1,1 diff --git a/tender_management_sales/static/description/assets/icons/check.png b/tender_management_sales/static/description/assets/icons/check.png new file mode 100644 index 000000000..c8e85f51d Binary files /dev/null and b/tender_management_sales/static/description/assets/icons/check.png differ diff --git a/tender_management_sales/static/description/assets/icons/chevron.png b/tender_management_sales/static/description/assets/icons/chevron.png new file mode 100644 index 000000000..2089293d6 Binary files /dev/null and b/tender_management_sales/static/description/assets/icons/chevron.png differ diff --git a/tender_management_sales/static/description/assets/icons/cogs.png b/tender_management_sales/static/description/assets/icons/cogs.png new file mode 100644 index 000000000..95d0bad62 Binary files /dev/null and b/tender_management_sales/static/description/assets/icons/cogs.png differ diff --git a/tender_management_sales/static/description/assets/icons/consultation.png b/tender_management_sales/static/description/assets/icons/consultation.png new file mode 100644 index 000000000..8319d4baa Binary files /dev/null and b/tender_management_sales/static/description/assets/icons/consultation.png differ diff --git a/tender_management_sales/static/description/assets/icons/ecom-black.png b/tender_management_sales/static/description/assets/icons/ecom-black.png new file mode 100644 index 000000000..a9385ff13 Binary files /dev/null and b/tender_management_sales/static/description/assets/icons/ecom-black.png differ diff --git a/tender_management_sales/static/description/assets/icons/education-black.png b/tender_management_sales/static/description/assets/icons/education-black.png new file mode 100644 index 000000000..3eb09b27b Binary files /dev/null and b/tender_management_sales/static/description/assets/icons/education-black.png differ diff --git a/tender_management_sales/static/description/assets/icons/hotel-black.png b/tender_management_sales/static/description/assets/icons/hotel-black.png new file mode 100644 index 000000000..130f613be Binary files /dev/null and b/tender_management_sales/static/description/assets/icons/hotel-black.png differ diff --git a/tender_management_sales/static/description/assets/icons/license.png b/tender_management_sales/static/description/assets/icons/license.png new file mode 100644 index 000000000..a5869797e Binary files /dev/null and b/tender_management_sales/static/description/assets/icons/license.png differ diff --git a/tender_management_sales/static/description/assets/icons/lifebuoy.png b/tender_management_sales/static/description/assets/icons/lifebuoy.png new file mode 100644 index 000000000..658d56ccc Binary files /dev/null and b/tender_management_sales/static/description/assets/icons/lifebuoy.png differ diff --git a/tender_management_sales/static/description/assets/icons/manufacturing-black.png b/tender_management_sales/static/description/assets/icons/manufacturing-black.png new file mode 100644 index 000000000..697eb0e9f Binary files /dev/null and b/tender_management_sales/static/description/assets/icons/manufacturing-black.png differ diff --git a/tender_management_sales/static/description/assets/icons/pos-black.png b/tender_management_sales/static/description/assets/icons/pos-black.png new file mode 100644 index 000000000..97c0f90c1 Binary files /dev/null and b/tender_management_sales/static/description/assets/icons/pos-black.png differ diff --git a/tender_management_sales/static/description/assets/icons/puzzle.png b/tender_management_sales/static/description/assets/icons/puzzle.png new file mode 100644 index 000000000..65cf854e7 Binary files /dev/null and b/tender_management_sales/static/description/assets/icons/puzzle.png differ diff --git a/tender_management_sales/static/description/assets/icons/restaurant-black.png b/tender_management_sales/static/description/assets/icons/restaurant-black.png new file mode 100644 index 000000000..4a35eb939 Binary files /dev/null and b/tender_management_sales/static/description/assets/icons/restaurant-black.png differ diff --git a/tender_management_sales/static/description/assets/icons/service-black.png b/tender_management_sales/static/description/assets/icons/service-black.png new file mode 100644 index 000000000..301ab51cb Binary files /dev/null and b/tender_management_sales/static/description/assets/icons/service-black.png differ diff --git a/tender_management_sales/static/description/assets/icons/trading-black.png b/tender_management_sales/static/description/assets/icons/trading-black.png new file mode 100644 index 000000000..9398ba2f1 Binary files /dev/null and b/tender_management_sales/static/description/assets/icons/trading-black.png differ diff --git a/tender_management_sales/static/description/assets/icons/training.png b/tender_management_sales/static/description/assets/icons/training.png new file mode 100644 index 000000000..884ca024d Binary files /dev/null and b/tender_management_sales/static/description/assets/icons/training.png differ diff --git a/tender_management_sales/static/description/assets/icons/update.png b/tender_management_sales/static/description/assets/icons/update.png new file mode 100644 index 000000000..ecbc5a01a Binary files /dev/null and b/tender_management_sales/static/description/assets/icons/update.png differ diff --git a/tender_management_sales/static/description/assets/icons/user.png b/tender_management_sales/static/description/assets/icons/user.png new file mode 100644 index 000000000..6ffb23d9f Binary files /dev/null and b/tender_management_sales/static/description/assets/icons/user.png differ diff --git a/tender_management_sales/static/description/assets/icons/wrench.png b/tender_management_sales/static/description/assets/icons/wrench.png new file mode 100644 index 000000000..6c04dea0f Binary files /dev/null and b/tender_management_sales/static/description/assets/icons/wrench.png differ diff --git a/tender_management_sales/static/description/assets/misc/Cybrosys_new.png b/tender_management_sales/static/description/assets/misc/Cybrosys_new.png new file mode 100644 index 000000000..da4058087 Binary files /dev/null and b/tender_management_sales/static/description/assets/misc/Cybrosys_new.png differ diff --git a/tender_management_sales/static/description/assets/misc/categories.png b/tender_management_sales/static/description/assets/misc/categories.png new file mode 100644 index 000000000..bedf1e0b1 Binary files /dev/null and b/tender_management_sales/static/description/assets/misc/categories.png differ diff --git a/tender_management_sales/static/description/assets/misc/check-box.png b/tender_management_sales/static/description/assets/misc/check-box.png new file mode 100644 index 000000000..42caf24b9 Binary files /dev/null and b/tender_management_sales/static/description/assets/misc/check-box.png differ diff --git a/tender_management_sales/static/description/assets/misc/compass.png b/tender_management_sales/static/description/assets/misc/compass.png new file mode 100644 index 000000000..d5fed8faa Binary files /dev/null and b/tender_management_sales/static/description/assets/misc/compass.png differ diff --git a/tender_management_sales/static/description/assets/misc/corporate.png b/tender_management_sales/static/description/assets/misc/corporate.png new file mode 100644 index 000000000..2eb13edbf Binary files /dev/null and b/tender_management_sales/static/description/assets/misc/corporate.png differ diff --git a/tender_management_sales/static/description/assets/misc/customer-support.png b/tender_management_sales/static/description/assets/misc/customer-support.png new file mode 100644 index 000000000..79efc72ed Binary files /dev/null and b/tender_management_sales/static/description/assets/misc/customer-support.png differ diff --git a/tender_management_sales/static/description/assets/misc/cybrosys-logo.png b/tender_management_sales/static/description/assets/misc/cybrosys-logo.png new file mode 100644 index 000000000..cc3cc0ccf Binary files /dev/null and b/tender_management_sales/static/description/assets/misc/cybrosys-logo.png differ diff --git a/tender_management_sales/static/description/assets/misc/features.png b/tender_management_sales/static/description/assets/misc/features.png new file mode 100644 index 000000000..b41769f77 Binary files /dev/null and b/tender_management_sales/static/description/assets/misc/features.png differ diff --git a/tender_management_sales/static/description/assets/misc/logo.png b/tender_management_sales/static/description/assets/misc/logo.png new file mode 100644 index 000000000..478462d3e Binary files /dev/null and b/tender_management_sales/static/description/assets/misc/logo.png differ diff --git a/tender_management_sales/static/description/assets/misc/pictures.png b/tender_management_sales/static/description/assets/misc/pictures.png new file mode 100644 index 000000000..56d255fe9 Binary files /dev/null and b/tender_management_sales/static/description/assets/misc/pictures.png differ diff --git a/tender_management_sales/static/description/assets/misc/pie-chart.png b/tender_management_sales/static/description/assets/misc/pie-chart.png new file mode 100644 index 000000000..426e05244 Binary files /dev/null and b/tender_management_sales/static/description/assets/misc/pie-chart.png differ diff --git a/tender_management_sales/static/description/assets/misc/right-arrow.png b/tender_management_sales/static/description/assets/misc/right-arrow.png new file mode 100644 index 000000000..730984a06 Binary files /dev/null and b/tender_management_sales/static/description/assets/misc/right-arrow.png differ diff --git a/tender_management_sales/static/description/assets/misc/star.png b/tender_management_sales/static/description/assets/misc/star.png new file mode 100644 index 000000000..2eb9ab29f Binary files /dev/null and b/tender_management_sales/static/description/assets/misc/star.png differ diff --git a/tender_management_sales/static/description/assets/misc/support.png b/tender_management_sales/static/description/assets/misc/support.png new file mode 100644 index 000000000..4f18b8b82 Binary files /dev/null and b/tender_management_sales/static/description/assets/misc/support.png differ diff --git a/tender_management_sales/static/description/assets/misc/whatsapp.png b/tender_management_sales/static/description/assets/misc/whatsapp.png new file mode 100644 index 000000000..d513a5356 Binary files /dev/null and b/tender_management_sales/static/description/assets/misc/whatsapp.png differ diff --git a/tender_management_sales/static/description/assets/modules/1.png b/tender_management_sales/static/description/assets/modules/1.png new file mode 100644 index 000000000..af96cc10a Binary files /dev/null and b/tender_management_sales/static/description/assets/modules/1.png differ diff --git a/tender_management_sales/static/description/assets/modules/2.png b/tender_management_sales/static/description/assets/modules/2.png new file mode 100644 index 000000000..489f44e86 Binary files /dev/null and b/tender_management_sales/static/description/assets/modules/2.png differ diff --git a/tender_management_sales/static/description/assets/modules/3.png b/tender_management_sales/static/description/assets/modules/3.png new file mode 100644 index 000000000..2c8fbb83f Binary files /dev/null and b/tender_management_sales/static/description/assets/modules/3.png differ diff --git a/tender_management_sales/static/description/assets/modules/4.png b/tender_management_sales/static/description/assets/modules/4.png new file mode 100644 index 000000000..a29119785 Binary files /dev/null and b/tender_management_sales/static/description/assets/modules/4.png differ diff --git a/tender_management_sales/static/description/assets/modules/5.png b/tender_management_sales/static/description/assets/modules/5.png new file mode 100644 index 000000000..6d637752d Binary files /dev/null and b/tender_management_sales/static/description/assets/modules/5.png differ diff --git a/tender_management_sales/static/description/assets/modules/6.png b/tender_management_sales/static/description/assets/modules/6.png new file mode 100644 index 000000000..a44d454aa Binary files /dev/null and b/tender_management_sales/static/description/assets/modules/6.png differ diff --git a/tender_management_sales/static/description/assets/screenshots.zip b/tender_management_sales/static/description/assets/screenshots.zip new file mode 100644 index 000000000..7b0ebf4bc Binary files /dev/null and b/tender_management_sales/static/description/assets/screenshots.zip differ diff --git a/tender_management_sales/static/description/assets/screenshots/1.png b/tender_management_sales/static/description/assets/screenshots/1.png new file mode 100644 index 000000000..b1cd7ef6b Binary files /dev/null and b/tender_management_sales/static/description/assets/screenshots/1.png differ diff --git a/tender_management_sales/static/description/assets/screenshots/2.png b/tender_management_sales/static/description/assets/screenshots/2.png new file mode 100644 index 000000000..5da2e2761 Binary files /dev/null and b/tender_management_sales/static/description/assets/screenshots/2.png differ diff --git a/tender_management_sales/static/description/assets/screenshots/3.png b/tender_management_sales/static/description/assets/screenshots/3.png new file mode 100644 index 000000000..b88e922c7 Binary files /dev/null and b/tender_management_sales/static/description/assets/screenshots/3.png differ diff --git a/tender_management_sales/static/description/assets/screenshots/4.png b/tender_management_sales/static/description/assets/screenshots/4.png new file mode 100644 index 000000000..419594b7a Binary files /dev/null and b/tender_management_sales/static/description/assets/screenshots/4.png differ diff --git a/tender_management_sales/static/description/assets/screenshots/5.png b/tender_management_sales/static/description/assets/screenshots/5.png new file mode 100644 index 000000000..917c46413 Binary files /dev/null and b/tender_management_sales/static/description/assets/screenshots/5.png differ diff --git a/tender_management_sales/static/description/assets/screenshots/6.png b/tender_management_sales/static/description/assets/screenshots/6.png new file mode 100644 index 000000000..3a51fedb3 Binary files /dev/null and b/tender_management_sales/static/description/assets/screenshots/6.png differ diff --git a/tender_management_sales/static/description/assets/screenshots/7.png b/tender_management_sales/static/description/assets/screenshots/7.png new file mode 100644 index 000000000..010b0b388 Binary files /dev/null and b/tender_management_sales/static/description/assets/screenshots/7.png differ diff --git a/tender_management_sales/static/description/assets/screenshots/8.png b/tender_management_sales/static/description/assets/screenshots/8.png new file mode 100644 index 000000000..962212798 Binary files /dev/null and b/tender_management_sales/static/description/assets/screenshots/8.png differ diff --git a/tender_management_sales/static/description/assets/screenshots/hero.gif b/tender_management_sales/static/description/assets/screenshots/hero.gif new file mode 100644 index 000000000..45c1a1a48 Binary files /dev/null and b/tender_management_sales/static/description/assets/screenshots/hero.gif differ diff --git a/tender_management_sales/static/description/banner.png b/tender_management_sales/static/description/banner.png new file mode 100644 index 000000000..0d89c9935 Binary files /dev/null and b/tender_management_sales/static/description/banner.png differ diff --git a/tender_management_sales/static/description/cybro_logo.png b/tender_management_sales/static/description/cybro_logo.png new file mode 100644 index 000000000..bb309114c Binary files /dev/null and b/tender_management_sales/static/description/cybro_logo.png differ diff --git a/tender_management_sales/static/description/icon.png b/tender_management_sales/static/description/icon.png new file mode 100644 index 000000000..361370a65 Binary files /dev/null and b/tender_management_sales/static/description/icon.png differ diff --git a/tender_management_sales/static/description/index.html b/tender_management_sales/static/description/index.html new file mode 100644 index 000000000..a0e1bc25d --- /dev/null +++ b/tender_management_sales/static/description/index.html @@ -0,0 +1,683 @@ +
+ +
+ +
+
+ Community +
+
+ Enterprise +
+
+
+ +
+
+
+ +

+ Tender Management Sales

+

+ Tender Management Sales for managing agreements in sale orders

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

+ Explore This + Module

+
+ + + + +
+
+ +
+

+ Overview +

+
+
+
+ This module allows to manage different tenders in odoo along with + option for comparing different sale order lines and choose best one. +
+
+ + + +
+
+ +
+

+ Features +

+
+
+
+
+ + Add different agreements for sale order. + +
+
+ + Compare different sale order lines. + +
+
+ + Choose the best among the order lines. +
+ +
+
+ + + +
+
+ +
+

+ Screenshots +

+
+
+
+ +
+

+ The menu to create sale agreements will be available from here. +

+

+ The menu to create sale agreements will be available from here.

+ +
+ +
+

+ Agreement Form. +

+

+ In the agreements form we can create the agreement + types + and choose other options as we needed.

+ +
+ +
+

+ Agreement Form +

+

+ Once the agreement type is selected we can add lines and other details from here. + After that we can create different sale orders from the form and all the created + orders + can be accessed from the smart tab.

+ +
+ +
+

+ Sale order. +

+

+ For the sale orders created from the agreement form the agreement will be + automatically + updated in the sale order form.

+ +
+ +
+

+ Create alternatives. +

+

+ This module allows to create alternative sale orders from the alternatives tab in + the sale order tab. The option to use the copy of the current sale order will also + be available.

+ +
+ +
+

+ Compare Lines +

+

+ Once the alternative orders are created the option to compare the order + lines from the sale order will be available.

+ +
+
+

+ Compare Lines View +

+

+ On clicking the compare lines the view to compare the lines will be available. + Here the lines with the best unit price and total will be highlighted and + can choose/ clear the lines.

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

+ Related + Products +

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

+ Our Services +

+
+ +
+
+
+
+ +
+
+ Odoo + Customization
+
+ +
+
+ +
+
+ Odoo + Implementation
+
+ +
+
+ +
+
+ Odoo + Support
+
+ + +
+
+ +
+
+ Hire + Odoo + Developer
+
+ +
+
+ +
+
+ Odoo + Integration
+
+ +
+
+ +
+
+ Odoo + Migration
+
+ + +
+
+ +
+
+ Odoo + Consultancy
+
+ +
+
+ +
+
+ Odoo + Implementation
+
+ +
+
+ +
+
+ Odoo + Licensing Consultancy
+
+
+ +
+ + + + + +
+
+ +
+

+ Our + Industries +

+
+ +
+
+
+
+ +
+ Trading +
+

+ Easily procure + and + sell your products

+
+
+ +
+
+ +
+ POS +
+

+ Easy + configuration + and convivial experience

+
+
+ +
+
+ +
+ Education +
+

+ A platform for + educational management

+
+
+ +
+
+ +
+ Manufacturing +
+

+ Plan, track and + schedule your operations

+
+
+ +
+
+ +
+ E-commerce & Website +
+

+ Mobile + friendly, + awe-inspiring product pages

+
+
+ +
+
+ +
+ Service Management +
+

+ Keep track of + services and invoice

+
+
+ +
+
+ +
+ Restaurant +
+

+ Run your bar or + restaurant methodically

+
+
+ +
+
+ +
+ Hotel Management +
+

+ An + all-inclusive + hotel management application

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

+ Support +

+
+
+
+
+
+
+ +
+
+

Need Help?

+

Got questions or need help? + Get in touch.

+ +

+ odoo@cybrosys.com

+
+
+
+
+
+
+
+ +
+
+

WhatsApp

+

Say hi to us on WhatsApp!

+ +

+ +91 86068 + 27707

+
+
+
+
+
+
+
+ +
+
+
+ \ No newline at end of file diff --git a/tender_management_sales/static/src/views/list/sale_order_line_compare_list_renderer.js b/tender_management_sales/static/src/views/list/sale_order_line_compare_list_renderer.js new file mode 100644 index 000000000..50bc099c6 --- /dev/null +++ b/tender_management_sales/static/src/views/list/sale_order_line_compare_list_renderer.js @@ -0,0 +1,50 @@ +/** @odoo-module */ + +import { ListRenderer } from "@web/views/list/list_renderer"; + +const { onWillStart, useState, useSubEnv } = owl; + +export class SaleOrderLineCompareListRenderer extends ListRenderer { +// extending the list renderer + setup() { + super.setup(); + this.bestFields = useState({ + best_price_ids: [], + best_price_unit_ids: [], + }); + onWillStart(async () => { + await this.updateBestFields(); + }); + const defaultOnClickViewButton = this.env.onClickViewButton; + useSubEnv({ + onClickViewButton: async (params) => { + await defaultOnClickViewButton(params); + await this.updateBestFields(); + } + }); + } + + async updateBestFields() { + //to update the lines having best price and unit price + [this.bestFields.best_price_ids, + this.bestFields.best_price_unit_ids] = await this.props.list.model.orm.call( + "sale.order", + "get_tender_best_lines", + [this.props.list.context.sale_order_id || this.props.list.context.active_id], + { context: this.props.list.context } + ); + } + + getCellClass(column, record) { + //to highlight the lines having best price and unit price + let classNames = super.getCellClass(...arguments); + const customClassNames = []; + if (column.name === "price_subtotal" && this.bestFields.best_price_ids.includes(record.resId)) { + customClassNames.push("text-success"); + } + if (column.name === "price_unit" && this.bestFields.best_price_unit_ids.includes(record.resId)) { + customClassNames.push("text-success"); + } + return classNames.concat(" ", customClassNames.join(" ")); + } +} diff --git a/tender_management_sales/static/src/views/list/sale_order_line_compare_list_view.js b/tender_management_sales/static/src/views/list/sale_order_line_compare_list_view.js new file mode 100644 index 000000000..2960a1c22 --- /dev/null +++ b/tender_management_sales/static/src/views/list/sale_order_line_compare_list_view.js @@ -0,0 +1,11 @@ +/** @odoo-module **/ + +import { listView } from '@web/views/list/list_view'; +import { registry } from "@web/core/registry"; +import { SaleOrderLineCompareListRenderer } from "./sale_order_line_compare_list_renderer"; +export const saleOrderLineCompareListView = { + ...listView, + Renderer: SaleOrderLineCompareListRenderer, +}; +// extending the list renderer +registry.category("views").add("sale_order_line_compare", saleOrderLineCompareListView); diff --git a/tender_management_sales/static/src/widgets/sale_order_alternatives_widget.js b/tender_management_sales/static/src/widgets/sale_order_alternatives_widget.js new file mode 100644 index 000000000..b61a57d00 --- /dev/null +++ b/tender_management_sales/static/src/widgets/sale_order_alternatives_widget.js @@ -0,0 +1,46 @@ +/** @odoo-module */ + +import { registry } from "@web/core/registry"; +import { useService } from "@web/core/utils/hooks"; +import { X2ManyField } from "@web/views/fields/x2many/x2many_field"; +import { ListRenderer } from "@web/views/list/list_renderer"; + + +export class FieldMany2ManyAltSosRenderer extends ListRenderer { + isCurrentRecord(record) { + return record.data.id === this.env.model.root.data.id; + } +} + +FieldMany2ManyAltSosRenderer.recordRowTemplate = "tender_sales.AltSOsListRenderer.RecordRow"; + +export class FieldMany2ManyAltSOs extends X2ManyField { + setup() { + this.orm = useService("orm"); + this.action = useService("action"); + // TODO: this is a terrible hack, make this a proper extension of many2many if/when possible + this.props.record.activeFields[this.props.name].widget = "many2many"; + super.setup(); + } + + /** + * Override to: avoid reopening currently open record + * open record in same window w/breadcrumb extended + * @override + */ + async openRecord(record) { + if (record.data.id !== this.props.record.data.id) { + const action = await this.orm.call(record.resModel, "get_formview_action", [[record.data.id]], { + context: this.props.context, + }); + await this.action.doAction(action); + } + } +} + +FieldMany2ManyAltSOs.components = { + ...X2ManyField.components, + ListRenderer: FieldMany2ManyAltSosRenderer, +}; + +registry.category("fields").add("many2many_alt_sos", FieldMany2ManyAltSOs); diff --git a/tender_management_sales/static/src/widgets/sale_order_alternatives_widget.scss b/tender_management_sales/static/src/widgets/sale_order_alternatives_widget.scss new file mode 100644 index 000000000..82196edf4 --- /dev/null +++ b/tender_management_sales/static/src/widgets/sale_order_alternatives_widget.scss @@ -0,0 +1,3 @@ +.o_field_many2many_alt_sos { + width: 100%; +} diff --git a/tender_management_sales/static/src/widgets/sale_order_alternatives_widget.xml b/tender_management_sales/static/src/widgets/sale_order_alternatives_widget.xml new file mode 100644 index 000000000..f793db378 --- /dev/null +++ b/tender_management_sales/static/src/widgets/sale_order_alternatives_widget.xml @@ -0,0 +1,11 @@ + + + + + + + (displayOptionalFields or hasX2ManyAction) and !isCurrentRecord(record) + + + + diff --git a/tender_management_sales/views/sale_order_views.xml b/tender_management_sales/views/sale_order_views.xml new file mode 100644 index 000000000..2627f9ef7 --- /dev/null +++ b/tender_management_sales/views/sale_order_views.xml @@ -0,0 +1,96 @@ + + + + + sale.order.form.view.inherit + sale.order + + + + + + + + + + +

Create alternatives. +

+
+ +

+ + +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+
+ + + sale.tender.tree + sale.tender + + + + + + + + + Sale Tenders + ir.actions.act_window + sale.tender + tree,form + {} + +

+ Start a new Sale agreement +

+
+
+ + + + +
diff --git a/tender_management_sales/wizard/__init__.py b/tender_management_sales/wizard/__init__.py new file mode 100644 index 000000000..ecd344521 --- /dev/null +++ b/tender_management_sales/wizard/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Nikhil M (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +############################################################################### +from . import tender_sales_create_alternative diff --git a/tender_management_sales/wizard/tender_sales_create_alternative.py b/tender_management_sales/wizard/tender_sales_create_alternative.py new file mode 100644 index 000000000..e97dd5a3d --- /dev/null +++ b/tender_management_sales/wizard/tender_sales_create_alternative.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Nikhil M (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +############################################################################### +from odoo import fields, models, Command + + +class SaleTenderCreateAlternative(models.TransientModel): + """"Creating module for wizard from alternative create confirmation""" + _name = 'sale.tender.create.alternative' + _description = 'Wizard to preset values for alternative PO' + + origin_so_id = fields.Many2one( + 'sale.order', help="The original PO that this alternative PO is being created for." + ) + partner_id = fields.Many2one( + 'res.partner', string='Customer', required=True, + help="Choose a customer for alternative sO") + + copy_products = fields.Boolean( + "Copy Products", default=True, + help="If this is checked, the product quantities of the original sO will be copied") + + def action_create_alternative(self): + """"Function to create alternative orders.""" + vals = self._get_alternative_values() + alt_so = self.env['sale.order'].with_context(origin_so_id=self.origin_so_id.id, default_tender_id=False).create(vals) + return { + 'type': 'ir.actions.act_window', + 'view_mode': 'form', + 'res_model': 'sale.order', + 'res_id': alt_so.id, + 'context': { + 'active_id': alt_so.id, + }, + } + + def _get_alternative_values(self): + """"function to return alternative values.""" + vals = { + 'date_order': self.origin_so_id.date_order, + 'partner_id': self.partner_id.id, + 'user_id': self.origin_so_id.user_id.id, + 'origin': self.origin_so_id.origin, + } + if self.copy_products and self.origin_so_id: + vals['order_line'] = [Command.create({ + 'product_id': line.product_id.id, + 'product_uom_qty': line.product_uom_qty, + 'product_uom': line.product_uom.id, + 'display_type': line.display_type, + 'name': line.name, + }) for line in self.origin_so_id.order_line] + return vals diff --git a/tender_management_sales/wizard/tender_sales_create_alternative.xml b/tender_management_sales/wizard/tender_sales_create_alternative.xml new file mode 100644 index 000000000..e174cc6ff --- /dev/null +++ b/tender_management_sales/wizard/tender_sales_create_alternative.xml @@ -0,0 +1,27 @@ + + + + + + Create Alternative + sale.tender.create.alternative + +
+ + + + + + + + + + +
+
+
+
+