Browse Source

Oct 16: [ADD] Initial commit 'tender_management_sales'

pull/345/merge
Cybrosys Technologies 6 months ago
parent
commit
817c90e3c3
  1. 48
      tender_management_sales/README.rst
  2. 23
      tender_management_sales/__init__.py
  3. 54
      tender_management_sales/__manifest__.py
  4. 13
      tender_management_sales/data/sale_tender_data.xml
  5. 6
      tender_management_sales/doc/RELEASE_NOTES.md
  6. 23
      tender_management_sales/models/__init__.py
  7. 296
      tender_management_sales/models/sale_order.py
  8. 182
      tender_management_sales/models/tender_sales.py
  9. 6
      tender_management_sales/security/ir.model.access.csv
  10. BIN
      tender_management_sales/static/description/assets/icons/check.png
  11. BIN
      tender_management_sales/static/description/assets/icons/chevron.png
  12. BIN
      tender_management_sales/static/description/assets/icons/cogs.png
  13. BIN
      tender_management_sales/static/description/assets/icons/consultation.png
  14. BIN
      tender_management_sales/static/description/assets/icons/ecom-black.png
  15. BIN
      tender_management_sales/static/description/assets/icons/education-black.png
  16. BIN
      tender_management_sales/static/description/assets/icons/hotel-black.png
  17. BIN
      tender_management_sales/static/description/assets/icons/license.png
  18. BIN
      tender_management_sales/static/description/assets/icons/lifebuoy.png
  19. BIN
      tender_management_sales/static/description/assets/icons/manufacturing-black.png
  20. BIN
      tender_management_sales/static/description/assets/icons/pos-black.png
  21. BIN
      tender_management_sales/static/description/assets/icons/puzzle.png
  22. BIN
      tender_management_sales/static/description/assets/icons/restaurant-black.png
  23. BIN
      tender_management_sales/static/description/assets/icons/service-black.png
  24. BIN
      tender_management_sales/static/description/assets/icons/trading-black.png
  25. BIN
      tender_management_sales/static/description/assets/icons/training.png
  26. BIN
      tender_management_sales/static/description/assets/icons/update.png
  27. BIN
      tender_management_sales/static/description/assets/icons/user.png
  28. BIN
      tender_management_sales/static/description/assets/icons/wrench.png
  29. BIN
      tender_management_sales/static/description/assets/misc/Cybrosys_new.png
  30. BIN
      tender_management_sales/static/description/assets/misc/categories.png
  31. BIN
      tender_management_sales/static/description/assets/misc/check-box.png
  32. BIN
      tender_management_sales/static/description/assets/misc/compass.png
  33. BIN
      tender_management_sales/static/description/assets/misc/corporate.png
  34. BIN
      tender_management_sales/static/description/assets/misc/customer-support.png
  35. BIN
      tender_management_sales/static/description/assets/misc/cybrosys-logo.png
  36. BIN
      tender_management_sales/static/description/assets/misc/features.png
  37. BIN
      tender_management_sales/static/description/assets/misc/logo.png
  38. BIN
      tender_management_sales/static/description/assets/misc/pictures.png
  39. BIN
      tender_management_sales/static/description/assets/misc/pie-chart.png
  40. BIN
      tender_management_sales/static/description/assets/misc/right-arrow.png
  41. BIN
      tender_management_sales/static/description/assets/misc/star.png
  42. BIN
      tender_management_sales/static/description/assets/misc/support.png
  43. BIN
      tender_management_sales/static/description/assets/misc/whatsapp.png
  44. BIN
      tender_management_sales/static/description/assets/modules/1.png
  45. BIN
      tender_management_sales/static/description/assets/modules/2.png
  46. BIN
      tender_management_sales/static/description/assets/modules/3.png
  47. BIN
      tender_management_sales/static/description/assets/modules/4.png
  48. BIN
      tender_management_sales/static/description/assets/modules/5.png
  49. BIN
      tender_management_sales/static/description/assets/modules/6.png
  50. BIN
      tender_management_sales/static/description/assets/screenshots.zip
  51. BIN
      tender_management_sales/static/description/assets/screenshots/1.png
  52. BIN
      tender_management_sales/static/description/assets/screenshots/2.png
  53. BIN
      tender_management_sales/static/description/assets/screenshots/3.png
  54. BIN
      tender_management_sales/static/description/assets/screenshots/4.png
  55. BIN
      tender_management_sales/static/description/assets/screenshots/5.png
  56. BIN
      tender_management_sales/static/description/assets/screenshots/6.png
  57. BIN
      tender_management_sales/static/description/assets/screenshots/7.png
  58. BIN
      tender_management_sales/static/description/assets/screenshots/8.png
  59. BIN
      tender_management_sales/static/description/assets/screenshots/hero.gif
  60. BIN
      tender_management_sales/static/description/banner.png
  61. BIN
      tender_management_sales/static/description/cybro_logo.png
  62. BIN
      tender_management_sales/static/description/icon.png
  63. 683
      tender_management_sales/static/description/index.html
  64. 50
      tender_management_sales/static/src/views/list/sale_order_line_compare_list_renderer.js
  65. 11
      tender_management_sales/static/src/views/list/sale_order_line_compare_list_view.js
  66. 46
      tender_management_sales/static/src/widgets/sale_order_alternatives_widget.js
  67. 3
      tender_management_sales/static/src/widgets/sale_order_alternatives_widget.scss
  68. 11
      tender_management_sales/static/src/widgets/sale_order_alternatives_widget.xml
  69. 96
      tender_management_sales/views/sale_order_views.xml
  70. 186
      tender_management_sales/views/tender_sales_views.xml
  71. 22
      tender_management_sales/wizard/__init__.py
  72. 71
      tender_management_sales/wizard/tender_sales_create_alternative.py
  73. 27
      tender_management_sales/wizard/tender_sales_create_alternative.xml

48
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 <https://cybrosys.com/>`__
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 <https://cybrosys.com/>`__
Further information
===================
HTML Description: `<static/description/index.html>`__

23
tender_management_sales/__init__.py

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
###############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# 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 <http://www.gnu.org/licenses/>.
#
###############################################################################
from . import models
from . import wizard

54
tender_management_sales/__manifest__.py

@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-
###############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# 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 <http://www.gnu.org/licenses/>.
#
###############################################################################
{
'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,
}

13
tender_management_sales/data/sale_tender_data.xml

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Agreement sample data -->
<data noupdate="1">
<record id="seq_sale_tender" model="ir.sequence">
<field name="name">Sale Tender</field>
<field name="code">sale.tender.order</field>
<field name="prefix">ST</field>
<field name="padding">5</field>
<field name="company_id" eval="False"/>
</record>
</data>
</odoo>

6
tender_management_sales/doc/RELEASE_NOTES.md

@ -0,0 +1,6 @@
## Module <tender_management_sales>
#### 02.09.2024
#### Version 16.0.1.0.0
#### ADD
- Initial Commit for Tender Management Sales

23
tender_management_sales/models/__init__.py

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
###############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# 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 <http://www.gnu.org/licenses/>.
#
###############################################################################
from . import sale_order
from . import tender_sales

296
tender_management_sales/models/sale_order.py

@ -0,0 +1,296 @@
# -*- coding: utf-8 -*-
###############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# 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 <http://www.gnu.org/licenses/>.
#
###############################################################################
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,
}
}

182
tender_management_sales/models/tender_sales.py

@ -0,0 +1,182 @@
# -*- coding: utf-8 -*-
###############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# 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 <http://www.gnu.org/licenses/>.
#
###############################################################################
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

6
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
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_sale_tender sale.tender model_sale_tender base.group_user 1 1 1 1
3 access_sale_tender_type sale.tender.type model_sale_tender_type base.group_user 1 1 1 1
4 access_sale_tender_line sale.tender.line model_sale_tender_line base.group_user 1 1 1 1
5 access_sale_order_group sale.order.group model_sale_order_group base.group_user 1 1 1 1
6 access_sale_tender_create_alternative sale.tender.create.alternative model_sale_tender_create_alternative base.group_user 1 1 1 1

BIN
tender_management_sales/static/description/assets/icons/check.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
tender_management_sales/static/description/assets/icons/chevron.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

BIN
tender_management_sales/static/description/assets/icons/cogs.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
tender_management_sales/static/description/assets/icons/consultation.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
tender_management_sales/static/description/assets/icons/ecom-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 B

BIN
tender_management_sales/static/description/assets/icons/education-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 B

BIN
tender_management_sales/static/description/assets/icons/hotel-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 B

BIN
tender_management_sales/static/description/assets/icons/license.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
tender_management_sales/static/description/assets/icons/lifebuoy.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
tender_management_sales/static/description/assets/icons/manufacturing-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

BIN
tender_management_sales/static/description/assets/icons/pos-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 878 B

BIN
tender_management_sales/static/description/assets/icons/puzzle.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 B

BIN
tender_management_sales/static/description/assets/icons/restaurant-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 905 B

BIN
tender_management_sales/static/description/assets/icons/service-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 B

BIN
tender_management_sales/static/description/assets/icons/trading-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

BIN
tender_management_sales/static/description/assets/icons/training.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

BIN
tender_management_sales/static/description/assets/icons/update.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
tender_management_sales/static/description/assets/icons/user.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 B

BIN
tender_management_sales/static/description/assets/icons/wrench.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
tender_management_sales/static/description/assets/misc/Cybrosys_new.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

BIN
tender_management_sales/static/description/assets/misc/categories.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
tender_management_sales/static/description/assets/misc/check-box.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
tender_management_sales/static/description/assets/misc/compass.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
tender_management_sales/static/description/assets/misc/corporate.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
tender_management_sales/static/description/assets/misc/customer-support.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
tender_management_sales/static/description/assets/misc/cybrosys-logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
tender_management_sales/static/description/assets/misc/features.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 589 B

BIN
tender_management_sales/static/description/assets/misc/logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
tender_management_sales/static/description/assets/misc/pictures.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
tender_management_sales/static/description/assets/misc/pie-chart.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
tender_management_sales/static/description/assets/misc/right-arrow.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 967 B

BIN
tender_management_sales/static/description/assets/misc/star.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
tender_management_sales/static/description/assets/misc/support.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
tender_management_sales/static/description/assets/misc/whatsapp.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
tender_management_sales/static/description/assets/modules/1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

BIN
tender_management_sales/static/description/assets/modules/2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

BIN
tender_management_sales/static/description/assets/modules/3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

BIN
tender_management_sales/static/description/assets/modules/4.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

BIN
tender_management_sales/static/description/assets/modules/5.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

BIN
tender_management_sales/static/description/assets/modules/6.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

BIN
tender_management_sales/static/description/assets/screenshots.zip

Binary file not shown.

BIN
tender_management_sales/static/description/assets/screenshots/1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

BIN
tender_management_sales/static/description/assets/screenshots/2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 411 KiB

BIN
tender_management_sales/static/description/assets/screenshots/3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

BIN
tender_management_sales/static/description/assets/screenshots/4.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

BIN
tender_management_sales/static/description/assets/screenshots/5.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

BIN
tender_management_sales/static/description/assets/screenshots/6.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

BIN
tender_management_sales/static/description/assets/screenshots/7.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

BIN
tender_management_sales/static/description/assets/screenshots/8.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

BIN
tender_management_sales/static/description/assets/screenshots/hero.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 307 KiB

BIN
tender_management_sales/static/description/banner.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

BIN
tender_management_sales/static/description/cybro_logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
tender_management_sales/static/description/icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

683
tender_management_sales/static/description/index.html

@ -0,0 +1,683 @@
<div style="background-color: #714B67; height: 810px; width: 100%; padding: 15px; position: relative;">
<!-- TITLE BAR -->
<div class="d-flex align-items-center justify-content-between"
style="border-bottom: 1px solid #875A7B; padding: 15px; display: flex; justify-content: space-between; align-items: center;">
<img src="assets/misc/cybrosys-logo.png" width="42" height="42"
style="width: 42px; height: 42px;"/>
<div>
<div
style="color: #7C7BAD; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;"
class="mr-2">
<i class="fa fa-check mr-1"></i>Community
</div>
<div
style="color: #875A7B; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;"
class="mr-2">
<i class="fa fa-check mr-1"></i>Enterprise
</div>
</div>
</div>
<!-- END OF TITLE BAR -->
<div class="container">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-12">
<!-- APP HERO -->
<h1 style="color: #FFFFFF; font-weight: bolder; font-size: 50px; text-align: center; margin-top: 50px;">
Tender Management Sales</h1>
<p style="color:#FFFFFF; padding: 8px 15px; text-align: center; font-size: 24px;">
Tender Management Sales for managing agreements in sale orders </p>
<!-- END OF APP HERO -->
<img src="assets/screenshots/hero.gif" class="img-responsive"
style="width: 100%; margin-left: auto; margin-right: auto;"/>
</div>
</div>
</div>
</div>
<!-- NAVIGATION SECTION -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px; margin-top: 300px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/compass.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Explore This
Module</h2>
</div>
<div class="row my-4" style="font-family: 'Montserrat', sans-serif;">
<div class="col-sm-12 col-md-6 my-3">
<a href="#overview">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Overview</span>
<span style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">Learn
more about this
module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36" height="36"/>
</div>
</a>
</div>
<div class="col-sm-12 col-md-6 my-3">
<a href="#features">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Features</span>
<span style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">View
features of this
module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36" height="36"/>
</div>
</a>
</div>
<div class="col-sm-12 col-md-6 my-3">
<a href="#screenshots">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Screenshots</span>
<span style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">View
screenshots for this
module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36" height="36"/>
</div>
</a>
</div>
</div>
<!-- END OF NAVIGATION SECTION -->
<!-- OVERVIEW SECTION -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;" id="overview">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/pie-chart.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Overview
</h2>
</div>
<div class="row"
style="font-family: 'Montserrat', sans-serif; font-weight: 400; font-size: 14px; line-height: 200%;">
<div class="col-sm-12 py-4">
This module allows to manage different tenders in odoo along with
option for comparing different sale order lines and choose best one.
</div>
</div>
<!-- END OF OVERVIEW SECTION -->
<!-- FEATURES SECTION -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;" id="features">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/features.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Features
</h2>
</div>
<div class="row"
style="font-family: 'Montserrat', sans-serif; font-weight: 400; font-size: 14px; line-height: 200%;">
<div class="col-sm-12 col-md-6">
<div class="d-flex align-items-center"
style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Add different agreements for sale order.
</span>
</div>
<div class="d-flex align-items-center"
style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Compare different sale order lines.
</span>
</div>
<div class="d-flex align-items-center"
style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Choose the best among the order lines.</span>
</div>
</div>
</div>
<!-- END OF FEATURES SECTION -->
<!-- SCREENSHOTS SECTION -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;"
id="screenshots">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/pictures.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Screenshots
</h2>
</div>
<div class="row">
<div class="col-sm-12">
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
The menu to create sale agreements will be available from here.
</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
The menu to create sale agreements will be available from here.</p>
<img src="assets/screenshots/2.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Agreement Form.
</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
In the agreements form we can create the agreement
types
and choose other options as we needed.</p>
<img src="assets/screenshots/3.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Agreement Form
</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
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.</p>
<img src="assets/screenshots/4.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Sale order.
</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
For the sale orders created from the agreement form the agreement will be
automatically
updated in the sale order form.</p>
<img src="assets/screenshots/5.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Create alternatives.
</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
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.</p>
<img src="assets/screenshots/6.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Compare Lines
</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
Once the alternative orders are created the option to compare the order
lines from the sale order will be available.</p>
<img src="assets/screenshots/7.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Compare Lines View
</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
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.</p>
<img src="assets/screenshots/8.png" class="img-thumbnail">
</div>
</div>
</div>
<!-- END OF SCREENSHOTS SECTION -->
<!-- RELATED PRODUCTS -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/categories.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Related
Products
</h2>
</div>
<div class="row">
<div class="col-sm-12">
<div id="demo1" class="row carousel slide" data-ride="carousel">
<!-- The slideshow -->
<div class="carousel-inner" style="padding: 30px;">
<div class="carousel-item" style="min-height: 198.656px;">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/dynamic_accounts_report/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/1.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/custom_gantt_view/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/2.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/project_custom_gantt/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/3.png">
</div>
</a>
</div>
</div>
<div class="carousel-item active"
style="min-height: 198.656px;">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/account_reports_xlsx/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/4.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/base_accounting_kit/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/5.gif">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/hr_payroll_community/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/6.png">
</div>
</a>
</div>
</div>
</div>
<!-- Left and right controls -->
<a class="carousel-control-prev" href="#demo1" data-slide="prev"
style="width:35px; color:#000"> <span
class="carousel-control-prev-icon"><i
class="fa fa-chevron-left"
style="font-size:24px"></i></span>
</a> <a class="carousel-control-next" href="#demo1"
data-slide="next" style="width:35px; color:#000">
<span class="carousel-control-next-icon"><i
class="fa fa-chevron-right"
style="font-size:24px"></i></span>
</a>
</div>
</div>
</div>
<!-- END OF RELATED PRODUCTS -->
<!-- OUR SERVICES -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/star.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Our Services
</h2>
</div>
<div class="container my-5">
<div class="row">
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #1dd1a1 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/cogs.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Customization</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #ff6b6b !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/wrench.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Implementation</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #6462CD !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/lifebuoy.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Support</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #ffa801 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/user.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Hire
Odoo
Developer</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #54a0ff !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/puzzle.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Integration</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #6d7680 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/update.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Migration</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #786fa6 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/consultation.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Consultancy</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #f8a5c2 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/training.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Implementation</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #e6be26 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/license.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Licensing Consultancy</h6>
</div>
</div>
</div>
<!-- END OF END OF OUR SERVICES -->
<!-- OUR INDUSTRIES -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/corporate.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Our
Industries
</h2>
</div>
<div class="container my-5">
<div class="row">
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/trading-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Trading
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Easily procure
and
sell your products</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/pos-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
POS
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Easy
configuration
and convivial experience</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/education-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Education
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
A platform for
educational management</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/manufacturing-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Manufacturing
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Plan, track and
schedule your operations</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/ecom-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
E-commerce &amp; Website
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Mobile
friendly,
awe-inspiring product pages</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/service-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Service Management
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Keep track of
services and invoice</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/restaurant-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Restaurant
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Run your bar or
restaurant methodically</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/hotel-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Hotel Management
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
An
all-inclusive
hotel management application</p>
</div>
</div>
</div>
</div>
<!-- END OF END OF OUR INDUSTRIES -->
<!-- SUPPORT -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/customer-support.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Support
</h2>
</div>
<div class="container mt-5">
<div class="row">
<div class="col-sm-12 col-md-6">
<div style="background-color: #F6F8F9; padding: 30px; display: flex; align-items: center;">
<div class="mr-4 d-flex justify-content-center align-items-center"
style="background-color: #714B67; display: inline-block; height: 70px; width: 70px; display: flex; align-items: center; justify-content: center;">
<img src="assets/misc/support.png" height="48" width="48"
style="width: 42px; height: 42px;"/>
</div>
<div>
<h4>Need Help?</h4>
<p style="line-height: 100%;">Got questions or need help?
Get in touch.</p>
<a href="mailto:odoo@cybrosys.com">
<p style="font-weight: 400; font-size: 28px; line-height: 80%; color: #714B67;">
odoo@cybrosys.com</p>
</a>
</div>
</div>
</div>
<div class="col-sm-12 col-md-6">
<div style="background-color: #F6F8F9; padding: 30px; display: flex; align-items: center;">
<div class="mr-4 d-flex justify-content-center align-items-center"
style="background-color: #2AC44D; display: inline-block; height: 70px; width: 70px; display: flex; align-items: center; justify-content: center;">
<img src="assets/misc/whatsapp.png" height="52" width="52"
style="width: 52px; height: 52px;"/>
</div>
<div>
<h4>WhatsApp</h4>
<p style="line-height: 100%;">Say hi to us on WhatsApp!</p>
<a href="https://api.whatsapp.com/send?phone=918606827707">
<p style="font-weight: 400; font-size: 28px; line-height: 80%; color: #714B67;">
+91 86068
27707</p>
</a>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12 my-5 d-flex justify-content-center align-items-center">
<img src="assets/misc/logo.png" width="144" height="31"
style="width:144px; height: 31px; margin-top: 40px;"/>
</div>
</div>
</div>
<!-- END OF SUPPORT -->

50
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(" "));
}
}

11
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);

46
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);

3
tender_management_sales/static/src/widgets/sale_order_alternatives_widget.scss

@ -0,0 +1,3 @@
.o_field_many2many_alt_sos {
width: 100%;
}

11
tender_management_sales/static/src/widgets/sale_order_alternatives_widget.xml

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<!-- To not unlink a so from itself -->
<t t-name="tender_sales.AltSOsListRenderer.RecordRow" t-inherit="web.ListRenderer.RecordRow" t-inherit-mode="primary" owl="1">
<xpath expr="//t[@t-if='displayOptionalFields or hasX2ManyAction']" position="attributes">
<attribute name="t-if">(displayOptionalFields or hasX2ManyAction) and !isCurrentRecord(record)</attribute>
</xpath>
</t>
</templates>

96
tender_management_sales/views/sale_order_views.xml

@ -0,0 +1,96 @@
<?xml version="1.0"?>
<odoo>
<!-- view for sale order Form Inherit-->
<record id="sale_order_form_inherit" model="ir.ui.view">
<field name="name">sale.order.form.view.inherit</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="arch" type="xml">
<data>
<xpath expr="//field[@name='partner_id']" position='after'>
<field name="tender_id"
attrs="{'readonly': [('state','!=','draft')]}"
domain="[('state', 'in', ('in_progress', 'open', 'ongoing')), ('customer_id', 'in', (partner_id,
False)), ('company_id', '=', company_id)]"
options="{'no_create': True}"/>
</xpath>
<xpath expr="//page[@name='customer_signature']"
position="after">
<page string="Alternatives" name="alternative_so">
<group>
<group>
<p colspan="2">Create alternatives.
</p>
</group>
<group>
<p colspan="2">
<button name="action_create_alternative"
type="object"
class="btn-link d-block"
string="Create Alternative"
icon="fa-copy"/>
<button name="action_compare_alternative_lines"
type="object"
class="btn-link d-block"
string="Compare Product Lines"
icon="fa-bar-chart"
attrs="{'invisible': [('alternative_so_ids', '=', [])]}"/>
</p>
</group>
</group>
<field name="alternative_so_ids"
attrs="{'readonly': [('id', '=', False)]}"
widget="many2many_alt_sos"
context="{}"
domain="[('state', 'in', ('draft', 'sent'))]">
<tree string="Alternative Quotation Order"
decoration-muted="state in ['cancel', 'sale', 'done']"
decoration-bf="id == parent.id">
<control>
<create string="Link to Existing Quotations"/>
</control>
<field name="partner_id"/>
<field name="name" string="Reference"/>
<field name="amount_total"/>
<field name="state"/>
</tree>
</field>
</page>
</xpath>
</data>
</field>
</record>
<!-- view for sale order line compare-->
<record id="sale_order_line_compare_tree" model="ir.ui.view">
<field name="name">sale.order.line.compare.tree</field>
<field name="model">sale.order.line</field>
<field name="priority">1000</field>
<field name="arch" type="xml">
<tree string="Sale Order Lines"
decoration-muted="state in ['cancel', 'purchase', 'done']"
create="0" delete="0" edit="0" expand="1" js_class="sale_order_line_compare">
<header>
<button name="action_clear_quantities"
string="Clear Selected" type="object"
class="o_clear_qty_buttons"/>
</header>
<field name="product_id" readonly="1"/>
<field name="order_id" string="Reference" readonly="1"/>
<field name="state"/>
<field name="name" readonly="1"/>
<field name="product_uom_qty"/>
<field name="product_uom" groups="uom.group_uom"/>
<field name="price_unit"/>
<field name="price_subtotal" string="Total"/>
<field name="currency_id"/>
<button name="action_choose" string="Choose" type="object"
class="o_clear_qty_buttons" icon="fa-bullseye"
attrs="{'invisible': [('product_uom_qty', '&lt;=', 0.0)]}"/>
<button name="action_clear_quantities" string="Clear"
type="object" class="o_clear_qty_buttons"
icon="fa-times"
attrs="{'invisible': ['|', ('product_uom_qty', '&lt;=', 0.0), ('state', 'in', ['cancel', 'sale', 'done'])]}"/>
</tree>
</field>
</record>
</odoo>

186
tender_management_sales/views/tender_sales_views.xml

@ -0,0 +1,186 @@
<?xml version="1.0"?>
<odoo>
<data>
<!-- action to view sale order list-from tender form-->
<record id="action_sale_tender_list" model="ir.actions.act_window">
<field name="name">Quotations</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">sale.order</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('tender_id','=',active_id)]</field>
<field name="context">{
"default_tender_id":active_id,
}
</field>
</record>
<!-- action to view sale order from tender form-->
<record id="sale_tender_action_so" model="ir.actions.act_window">
<field name="name">Quotation</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">sale.order</field>
<field name="view_mode">form,tree</field>
<field name="domain">[('tender_id','=',active_id)]</field>
<field name="context">{
"default_tender_id":active_id,
}
</field>
</record>
<!-- sale tender form-->
<record id="view_sale_tender_form" model="ir.ui.view">
<field name="name">sale.tender.form</field>
<field name="model">sale.tender</field>
<field name="arch" type="xml">
<form string="Sale Agreements">
<field name="company_id" invisible="1"/>
<field name="currency_id" invisible="1"/>
<header>
<button name="%(sale_tender_action_so)d"
type="action"
string="New Quotation"
context="{'default_currency_id': currency_id, 'default_user_id': user_id}"
attrs="{'invisible': [('state', '!=', 'open')]}"/>
<button name="%(sale_tender_action_so)d"
type="action"
string="New Quotation" class="btn-primary"
context="{'default_currency_id': currency_id, 'default_user_id': user_id}"
attrs="{'invisible': [('state', 'not in', ('in_progress', 'ongoing'))]}"/>
<button name="action_in_progress" states="draft"
string="Confirm" type="object"
class="btn-primary"/>
<button name="action_cancel"
states="draft,in_progress,ongoing"
string="Cancel" type="object"/>
<field name="state" widget="statusbar"
statusbar_visible="draft,in_progress,open,done"/>
</header>
<sheet>
<div class="oe_button_box" name="button_box">
<button name="%(action_sale_tender_list)d"
type="action" class="oe_stat_button"
icon="fa-list-alt"
attrs="{'invisible': [('state', '=', 'draft')]}"
context="{'default_currency_id': currency_id}">
<field name="order_count" widget="statinfo"
string="Quotations/Orders"/>
</button>
</div>
<div class="oe_title">
<label for="name" class="oe_inline"/>
<h1>
<field name="name"/>
</h1>
</div>
<group>
<group>
<field name="user_id"
attrs="{'readonly': [('state','not in',('draft','in_progress','open'))]}"
domain="[('share', '=', False)]"/>
<field name="type_id"
attrs="{'readonly': [('state','!=','draft')]}"/>
<field name="customer_id"
context="{'res_partner_search_mode': 'customer'}"
attrs="{'readonly': [('state', 'in', ['ongoing','done'])]}"/>
<field name="currency_id"/>
</group>
<group>
<field name="date_end"
attrs="{'readonly': [('state','not in',('draft','in_progress','open','ongoing'))]}"/>
<field name="ordering_date"
attrs="{'readonly': [('state','not in',('draft','in_progress','open','ongoing'))]}"/>
<field name="schedule_date"
attrs="{'readonly': [('state','not in',('draft','in_progress','open','ongoing'))]}"/>
<field name="company_id"
options="{'no_create': True}"
attrs="{'readonly': [('state','not in',('draft'))]}"/>
</group>
</group>
<notebook>
<page string="Products" name="products">
<field name="line_ids">
<tree string="Products" editable="bottom">
<field name="product_id"
domain="[('purchase_ok', '=', True), '|', ('company_id', '=', False), ('company_id', '=', parent.company_id)]"/>
<field name="product_description_variants"
attrs="{'invisible': [('product_description_variants', '=', '')], 'readonly': [('parent.state', '!=', 'draft')]}"/>
<field name="product_qty"/>
<field name="product_uom_category_id"
invisible="1"/>
<field name="product_uom_id"
string="UoM"
groups="uom.group_uom"
optional="show"
attrs="{'required': [('product_id', '!=', False)]}"/>
<field name="schedule_date"
optional="hide"/>
<field name="analytic_distribution"
widget="analytic_distribution"
optional="hide"
groups="analytic.group_analytic_accounting"
options="{'product_field': 'product_id', 'business_domain': 'purchase_order'}"/>
<field name="price_unit"/>
</tree>
<form string="Products">
<group>
<field name="product_id"
domain="[('sale_ok', '=', True), '|', ('company_id', '=', False), ('company_id', '=', parent.company_id)]"/>
<field name="product_qty"/>
<field name="product_uom_category_id"
invisible="1"/>
<field name="product_uom_id"
groups="uom.group_uom"/>
<field name="schedule_date"/>
<field name="analytic_distribution"
widget="analytic_distribution"
groups="analytic.group_analytic_accounting"
options="{'product_field': 'product_id', 'business_domain': 'sale_order'}"/>
<field name="company_id"
groups="base.group_multi_company"
options="{'no_create': True}"/>
</group>
</form>
</field>
<separator string="Terms and Conditions"/>
<field name="description"
class="oe-bordered-editor"
attrs="{'readonly': [('state','not in',('draft','in_progress','open'))]}"/>
</page>
</notebook>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids"/>
<field name="activity_ids"/>
<field name="message_ids"/>
</div>
</form>
</field>
</record>
<!-- tree view-->
<record id="view_sale_tender_tree" model="ir.ui.view">
<field name="name">sale.tender.tree</field>
<field name="model">sale.tender</field>
<field name="arch" type="xml">
<tree string="Sale Agreements" sample="1">
<field name="name" decoration-bf="1"/>
</tree>
</field>
</record>
<!-- action for the tender-->
<record id="sale_tender_action" model="ir.actions.act_window">
<field name="name">Sale Tenders</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">sale.tender</field>
<field name="view_mode">tree,form</field>
<field name="context">{}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Start a new Sale agreement
</p>
</field>
</record>
<!-- menu item for the tender -->
<menuitem id="sale_tender_menu" sequence="10" parent="sale.sale_order_menu"
action="sale_tender_action"/>
</data>
</odoo>

22
tender_management_sales/wizard/__init__.py

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
###############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# 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 <http://www.gnu.org/licenses/>.
#
###############################################################################
from . import tender_sales_create_alternative

71
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(<https://www.cybrosys.com>)
# 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 <http://www.gnu.org/licenses/>.
#
###############################################################################
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

27
tender_management_sales/wizard/tender_sales_create_alternative.xml

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!-- Alternative create Form-->
<record id="sale_tender_create_alternative_form" model="ir.ui.view">
<field name="name">Create Alternative</field>
<field name="model">sale.tender.create.alternative</field>
<field name="arch" type="xml">
<form string="Create Alternative">
<group>
<field name="origin_so_id" invisible="1"/>
<group>
<field name="partner_id"/>
</group>
<group>
<field name="copy_products"/>
</group>
</group>
<footer>
<button name="action_create_alternative" string="Create Alternative" data-hotkey="q" type="object" colspan="1" class="btn-primary"/>
<button string="Cancel" data-hotkey="x" special="cancel" colspan="1" class="btn-secondary"/>
</footer>
</form>
</field>
</record>
</data>
</odoo>
Loading…
Cancel
Save