| @ -0,0 +1,24 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ################################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | #    Copyright (C) 2017-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | ||||
|  | #    Author: fasluca(<https://www.cybrosys.com>) | ||||
|  | # | ||||
|  | #    This program is free software: you can modify | ||||
|  | #    it under the terms of the GNU Affero General Public License (AGPL) as | ||||
|  | #    published by the Free Software Foundation, either version 3 of the | ||||
|  | #    License, or (at your option) any later version. | ||||
|  | # | ||||
|  | #    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 for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU Affero General Public License | ||||
|  | #    along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ################################################################################### | ||||
|  | from . import models | ||||
|  | from . import reports | ||||
|  | 
 | ||||
| @ -0,0 +1,56 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ################################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | #    Copyright (C) 2018-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | ||||
|  | #    Author: fasluca(<https://www.cybrosys.com>) | ||||
|  | # | ||||
|  | #    This program is free software: you can modify | ||||
|  | #    it under the terms of the GNU Affero General Public License (AGPL) as | ||||
|  | #    published by the Free Software Foundation, either version 3 of the | ||||
|  | #    License, or (at your option) any later version. | ||||
|  | # | ||||
|  | #    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 for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU Affero General Public License | ||||
|  | #    along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ################################################################################### | ||||
|  | 
 | ||||
|  | { | ||||
|  |     'name': 'Sale Discount on Total Amount', | ||||
|  |     'version': '12.0.1.0.0', | ||||
|  |     'category': 'Sales Management', | ||||
|  |     'summary': "Discount on Total in Sale and Invoice With Discount Limit and Approval", | ||||
|  |     'author': 'Cybrosys Techno Solutions', | ||||
|  |     'company': 'Cybrosys Techno Solutions', | ||||
|  |     'website': 'http://www.cybrosys.com', | ||||
|  |     'description': """ | ||||
|  | 
 | ||||
|  | Sale Discount for Total Amount | ||||
|  | ======================= | ||||
|  | Module to manage discount on total amount in Sale. | ||||
|  |         as an specific amount or percentage | ||||
|  | """, | ||||
|  |     'depends': ['sale', | ||||
|  |                 'account' | ||||
|  |                 ], | ||||
|  |     'data': [ | ||||
|  |         'views/sale_view.xml', | ||||
|  |         'views/account_invoice_view.xml', | ||||
|  |         'views/invoice_report.xml', | ||||
|  |         'views/sale_order_report.xml', | ||||
|  |         'views/res_config_view.xml', | ||||
|  | 
 | ||||
|  |     ], | ||||
|  |     'demo': [ | ||||
|  |     ], | ||||
|  |     'images': ['static/description/banner.jpg'], | ||||
|  |     'license': 'AGPL-3', | ||||
|  |     'application': True, | ||||
|  |     'installable': True, | ||||
|  |     'auto_install': False, | ||||
|  | } | ||||
| @ -0,0 +1,25 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ################################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | #    Copyright (C) 2017-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | ||||
|  | #    Author: fasluca(<https://www.cybrosys.com>) | ||||
|  | # | ||||
|  | #    This program is free software: you can modify | ||||
|  | #    it under the terms of the GNU Affero General Public License (AGPL) as | ||||
|  | #    published by the Free Software Foundation, either version 3 of the | ||||
|  | #    License, or (at your option) any later version. | ||||
|  | # | ||||
|  | #    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 for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU Affero General Public License | ||||
|  | #    along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ################################################################################### | ||||
|  | from . import sale | ||||
|  | from . import account_invoice | ||||
|  | from . import discount_approval | ||||
|  | 
 | ||||
| @ -0,0 +1,102 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ################################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | #    Copyright (C) 2017-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | ||||
|  | #    Author: fasluca(<https://www.cybrosys.com>) | ||||
|  | # | ||||
|  | #    This program is free software: you can modify | ||||
|  | #    it under the terms of the GNU Affero General Public License (AGPL) as | ||||
|  | #    published by the Free Software Foundation, either version 3 of the | ||||
|  | #    License, or (at your option) any later version. | ||||
|  | # | ||||
|  | #    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 for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU Affero General Public License | ||||
|  | #    along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ################################################################################### | ||||
|  | 
 | ||||
|  | from odoo import api, fields, models | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class AccountInvoice(models.Model): | ||||
|  |     _inherit = "account.invoice" | ||||
|  | 
 | ||||
|  |     @api.one | ||||
|  |     @api.depends('invoice_line_ids.price_subtotal', 'tax_line_ids.amount', 'tax_line_ids.amount_rounding', | ||||
|  |                  'currency_id', 'company_id', 'date_invoice', 'type') | ||||
|  |     def _compute_amount(self): | ||||
|  |         self.amount_untaxed = sum(line.price_subtotal for line in self.invoice_line_ids) | ||||
|  |         self.amount_tax = sum(line.amount_total for line in self.tax_line_ids) | ||||
|  |         self.amount_total = self.amount_untaxed + self.amount_tax | ||||
|  |         self.amount_discount = sum((line.quantity * line.price_unit * line.discount)/100 for line in self.invoice_line_ids) | ||||
|  |         amount_total_company_signed = self.amount_total | ||||
|  |         amount_untaxed_signed = self.amount_untaxed | ||||
|  |         if self.currency_id and self.currency_id != self.company_id.currency_id: | ||||
|  |             currency_id = self.currency_id.with_context(date=self.date_invoice) | ||||
|  |             amount_total_company_signed = currency_id.compute(self.amount_total, self.company_id.currency_id) | ||||
|  |             amount_untaxed_signed = currency_id.compute(self.amount_untaxed, self.company_id.currency_id) | ||||
|  |         sign = self.type in ['in_refund', 'out_refund'] and -1 or 1 | ||||
|  |         self.amount_total_company_signed = amount_total_company_signed * sign | ||||
|  |         self.amount_total_signed = self.amount_total * sign | ||||
|  |         self.amount_untaxed_signed = amount_untaxed_signed * sign | ||||
|  | 
 | ||||
|  |     discount_type = fields.Selection([('percent', 'Percentage'), ('amount', 'Amount')], string='Discount Type', | ||||
|  |                                      readonly=True, states={'draft': [('readonly', False)]}, default='percent') | ||||
|  |     discount_rate = fields.Float('Discount Amount', digits=(16, 2), readonly=True, states={'draft': [('readonly', False)]}) | ||||
|  |     amount_discount = fields.Monetary(string='Discount', store=True, readonly=True, compute='_compute_amount', | ||||
|  |                                       track_visibility='always') | ||||
|  | 
 | ||||
|  |     @api.onchange('discount_type', 'discount_rate', 'invoice_line_ids') | ||||
|  |     def supply_rate(self): | ||||
|  |         for inv in self: | ||||
|  |             if inv.discount_type == 'percent': | ||||
|  |                 for line in inv.invoice_line_ids: | ||||
|  |                     line.discount = inv.discount_rate | ||||
|  |             else: | ||||
|  |                 total = discount = 0.0 | ||||
|  |                 for line in inv.invoice_line_ids: | ||||
|  |                     total += (line.quantity * line.price_unit) | ||||
|  |                 if inv.discount_rate != 0: | ||||
|  |                     discount = (inv.discount_rate / total) * 100 | ||||
|  |                 else: | ||||
|  |                     discount = inv.discount_rate | ||||
|  |                 for line in inv.invoice_line_ids: | ||||
|  |                     line.discount = discount | ||||
|  | 
 | ||||
|  |     @api.multi | ||||
|  |     def compute_invoice_totals(self, company_currency, invoice_move_lines): | ||||
|  |         total = 0 | ||||
|  |         total_currency = 0 | ||||
|  |         for line in invoice_move_lines: | ||||
|  |             if self.currency_id != company_currency: | ||||
|  |                 currency = self.currency_id.with_context(date=self.date or self.date_invoice or fields.Date.context_today(self)) | ||||
|  |                 line['currency_id'] = currency.id | ||||
|  |                 line['amount_currency'] = currency.round(line['price']) | ||||
|  |                 line['price'] = currency.compute(line['price'], company_currency) | ||||
|  |             else: | ||||
|  |                 line['currency_id'] = False | ||||
|  |                 line['amount_currency'] = False | ||||
|  |                 line['price'] = line['price'] | ||||
|  |             if self.type in ('out_invoice', 'in_refund'): | ||||
|  |                 total += line['price'] | ||||
|  |                 total_currency += line['amount_currency'] or line['price'] | ||||
|  |                 line['price'] = - line['price'] | ||||
|  |             else: | ||||
|  |                 total -= line['price'] | ||||
|  |                 total_currency -= line['amount_currency'] or line['price'] | ||||
|  |         return total, total_currency, invoice_move_lines | ||||
|  | 
 | ||||
|  |     @api.multi | ||||
|  |     def button_dummy(self): | ||||
|  |         self.supply_rate() | ||||
|  |         return True | ||||
|  | 
 | ||||
|  | class AccountInvoiceLine(models.Model): | ||||
|  |     _inherit = "account.invoice.line" | ||||
|  | 
 | ||||
|  |     discount = fields.Float(string='Discount (%)', digits=(16, 20), default=0.0) | ||||
| @ -0,0 +1,113 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ################################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | #    Copyright (C) 2017-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | ||||
|  | #    Author: fasluca(<https://www.cybrosys.com>) | ||||
|  | # | ||||
|  | #    This program is free software: you can modify | ||||
|  | #    it under the terms of the GNU Affero General Public License (AGPL) as | ||||
|  | #    published by the Free Software Foundation, either version 3 of the | ||||
|  | #    License, or (at your option) any later version. | ||||
|  | # | ||||
|  | #    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 for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU Affero General Public License | ||||
|  | #    along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ################################################################################### | ||||
|  | 
 | ||||
|  | from odoo import api, fields, models | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class sale_discount(models.Model): | ||||
|  |     _inherit = 'sale.order' | ||||
|  | 
 | ||||
|  |     state = fields.Selection([ | ||||
|  |         ('draft', 'Quotation'), | ||||
|  |         ('sent', 'Quotation Sent'), | ||||
|  |         ('waiting', 'Waiting Approval'), | ||||
|  |         ('sale', 'Sales Order'), | ||||
|  |         ('done', 'Locked'), | ||||
|  |         ('cancel', 'Cancelled'), | ||||
|  |         ], string='Status', readonly=True, copy=False, index=True, track_visibility='onchange', default='draft') | ||||
|  | 
 | ||||
|  |     @api.multi | ||||
|  |     def action_confirm(self): | ||||
|  |         discnt = 0.0 | ||||
|  |         no_line = 0.0 | ||||
|  |         for order in self: | ||||
|  |             if self.company_id.so_double_validation == 'two_step': | ||||
|  |                 for line in order.order_line: | ||||
|  |                     no_line += 1 | ||||
|  |                     discnt += line.discount | ||||
|  |                 discnt = (discnt / no_line) | ||||
|  |                 if order.company_id.so_double_validation_limit and discnt > order.company_id.so_double_validation_limit: | ||||
|  |                     order.state = 'waiting' | ||||
|  |                     return True | ||||
|  |             order._action_confirm() | ||||
|  |             if order.env['ir.config_parameter'].sudo().get_param('sale.auto_done_setting'): | ||||
|  |                 order.action_done() | ||||
|  |         return True | ||||
|  | 
 | ||||
|  |     @api.multi | ||||
|  |     def action_approve(self): | ||||
|  |         self._action_confirm() | ||||
|  |         if self.env['ir.config_parameter'].sudo().get_param('sale.auto_done_setting'): | ||||
|  |             self.action_done() | ||||
|  |         return True | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class Company(models.Model): | ||||
|  |     _inherit = 'res.company' | ||||
|  | 
 | ||||
|  |     so_double_validation = fields.Selection([ | ||||
|  |         ('one_step', 'Confirm sale orders in one step'), | ||||
|  |         ('two_step', 'Get 2 levels of approvals to confirm a sale order') | ||||
|  |     ], string="Levels of Approvals", default='one_step', | ||||
|  |         help="Provide a double validation mechanism for sales discount") | ||||
|  | 
 | ||||
|  |     so_double_validation_limit = fields.Float(string="Percentage of Discount that requires double validation'", | ||||
|  |                                   help="Minimum discount percentage for which a double validation is required") | ||||
|  | 
 | ||||
|  | 
 | ||||
|  |     # @api.multi | ||||
|  |     # def set_default_discount(self): | ||||
|  |     #     if self.discount_approval and self.discount_approval != self.company_id.discount_approval: | ||||
|  |     #         self.company_id.write({'discount_approval': self.discount_approval}) | ||||
|  |     #     if self.limit_discount and self.limit_discount != self.company_id.limit_discount: | ||||
|  |     #         self.company_id.write({'limit_discount': self.limit_discount}) | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class ResDiscountSettings(models.TransientModel): | ||||
|  |     _inherit = 'res.config.settings' | ||||
|  | 
 | ||||
|  |     so_order_approval = fields.Boolean("Sale Discount Approval", default=lambda self: self.env.user.company_id.so_double_validation == 'two_step') | ||||
|  | 
 | ||||
|  |     so_double_validation = fields.Selection(related='company_id.so_double_validation',) | ||||
|  |                                             # help='Provide a double validation mechanism for sale exceeding maximum discount limit.') | ||||
|  |     so_double_validation_limit = fields.Float(string="Discount limit requires approval in %", | ||||
|  |                                               related='company_id.so_double_validation_limit') | ||||
|  | 
 | ||||
|  | 
 | ||||
|  |     # @api.model | ||||
|  |     # def get_values(self): | ||||
|  |     #     res = super(ResDiscountSettings, self).get_values() | ||||
|  |     #     res.update( | ||||
|  |     #         limit_discount=self.company_id.limit_discount if self.company_id.limit_discount else 0.0, | ||||
|  |     #         discount_approval=True if self.company_id.discount_approval else False | ||||
|  |     #     ) | ||||
|  |     #     return res | ||||
|  |     # | ||||
|  |     # @api.multi | ||||
|  |     # def set_values(self): | ||||
|  |     #     super(ResDiscountSettings, self).set_values() | ||||
|  |     #     self.company_id.limit_discount = self.limit_discount | ||||
|  |     #     self.company_id.discount_approval = self.discount_approval | ||||
|  | 
 | ||||
|  |     def set_values(self): | ||||
|  |         super(ResDiscountSettings, self).set_values() | ||||
|  |         self.so_double_validation = 'two_step' if self.so_order_approval else 'one_step' | ||||
| @ -0,0 +1,167 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ################################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | #    Copyright (C) 2017-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | ||||
|  | #    Author: fasluca(<https://www.cybrosys.com>) | ||||
|  | # | ||||
|  | #    This program is free software: you can modify | ||||
|  | #    it under the terms of the GNU Affero General Public License (AGPL) as | ||||
|  | #    published by the Free Software Foundation, either version 3 of the | ||||
|  | #    License, or (at your option) any later version. | ||||
|  | # | ||||
|  | #    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 for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU Affero General Public License | ||||
|  | #    along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ################################################################################### | ||||
|  | 
 | ||||
|  | from odoo import api, fields, models | ||||
|  | import odoo.addons.decimal_precision as dp | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class SaleOrder(models.Model): | ||||
|  |     _inherit = "sale.order" | ||||
|  | 
 | ||||
|  |     @api.depends('order_line.price_total') | ||||
|  |     def _amount_all(self): | ||||
|  |         """ | ||||
|  |         Compute the total amounts of the SO. | ||||
|  |         """ | ||||
|  |         for order in self: | ||||
|  |             amount_untaxed = amount_tax = amount_discount = 0.0 | ||||
|  |             for line in order.order_line: | ||||
|  |                 amount_untaxed += line.price_subtotal | ||||
|  |                 amount_tax += line.price_tax | ||||
|  |                 amount_discount += (line.product_uom_qty * line.price_unit * line.discount)/100 | ||||
|  |             order.update({ | ||||
|  |                 'amount_untaxed': order.pricelist_id.currency_id.round(amount_untaxed), | ||||
|  |                 'amount_tax': order.pricelist_id.currency_id.round(amount_tax), | ||||
|  |                 'amount_discount': order.pricelist_id.currency_id.round(amount_discount), | ||||
|  |                 'amount_total': amount_untaxed + amount_tax, | ||||
|  |             }) | ||||
|  | 
 | ||||
|  |     discount_type = fields.Selection([('percent', 'Percentage'), ('amount', 'Amount')], string='Discount type', | ||||
|  |                                      readonly=True,states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, | ||||
|  |                                      default='percent') | ||||
|  |     discount_rate = fields.Float('Discount Rate', digits=dp.get_precision('Account'), | ||||
|  |                                  readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}) | ||||
|  |     amount_untaxed = fields.Monetary(string='Untaxed Amount', store=True, readonly=True, compute='_amount_all', | ||||
|  |                                      track_visibility='always') | ||||
|  |     amount_tax = fields.Monetary(string='Taxes', store=True, readonly=True, compute='_amount_all', | ||||
|  |                                  track_visibility='always') | ||||
|  |     amount_total = fields.Monetary(string='Total', store=True, readonly=True, compute='_amount_all', | ||||
|  |                                    track_visibility='always') | ||||
|  |     amount_discount = fields.Monetary(string='Discount', store=True, readonly=True, compute='_amount_all', | ||||
|  |                                       digits=dp.get_precision('Account'), track_visibility='always') | ||||
|  | 
 | ||||
|  |     @api.onchange('discount_type', 'discount_rate', 'order_line') | ||||
|  |     def supply_rate(self): | ||||
|  |         for order in self: | ||||
|  |             if order.discount_type == 'percent': | ||||
|  |                 for line in order.order_line: | ||||
|  |                     line.discount = order.discount_rate | ||||
|  |             else: | ||||
|  |                 total = discount = 0.0 | ||||
|  |                 for line in order.order_line: | ||||
|  |                     total += round((line.product_uom_qty * line.price_unit)) | ||||
|  |                 if order.discount_rate != 0: | ||||
|  |                     discount = (order.discount_rate / total) * 100 | ||||
|  |                 else: | ||||
|  |                     discount = order.discount_rate | ||||
|  |                 for line in order.order_line: | ||||
|  |                     line.discount = discount | ||||
|  | 
 | ||||
|  |     @api.multi | ||||
|  |     def _prepare_invoice(self,): | ||||
|  |         invoice_vals = super(SaleOrder, self)._prepare_invoice() | ||||
|  |         invoice_vals.update({ | ||||
|  |             'discount_type': self.discount_type, | ||||
|  |             'discount_rate': self.discount_rate | ||||
|  |         }) | ||||
|  |         return invoice_vals | ||||
|  | 
 | ||||
|  |     @api.multi | ||||
|  |     def button_dummy(self): | ||||
|  |         self.supply_rate() | ||||
|  |         return True | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class AccountTax(models.Model): | ||||
|  |     _inherit = 'account.tax' | ||||
|  | 
 | ||||
|  |     @api.multi | ||||
|  |     def compute_all(self, price_unit, currency=None, quantity=1.0, product=None, partner=None): | ||||
|  |         if len(self) == 0: | ||||
|  |             company_id = self.env.user.company_id | ||||
|  |         else: | ||||
|  |             company_id = self[0].company_id | ||||
|  |         if not currency: | ||||
|  |             currency = company_id.currency_id | ||||
|  |         taxes = [] | ||||
|  |         prec = currency.decimal_places | ||||
|  |         round_tax = False if company_id.tax_calculation_rounding_method == 'round_globally' else True | ||||
|  |         round_total = True | ||||
|  |         if 'round' in self.env.context: | ||||
|  |             round_tax = bool(self.env.context['round']) | ||||
|  |             round_total = bool(self.env.context['round']) | ||||
|  | 
 | ||||
|  |         if not round_tax: | ||||
|  |             prec += 5 | ||||
|  |         # total_excluded = total_included = base = round(price_unit * quantity, prec) | ||||
|  |         total_excluded = total_included = base = (price_unit * quantity) | ||||
|  | 
 | ||||
|  |         for tax in self.sorted(key=lambda r: r.sequence): | ||||
|  |             if tax.amount_type == 'group': | ||||
|  |                 ret = tax.children_tax_ids.compute_all(price_unit, currency, quantity, product, partner) | ||||
|  |                 total_excluded = ret['total_excluded'] | ||||
|  |                 base = ret['base'] | ||||
|  |                 total_included = ret['total_included'] | ||||
|  |                 tax_amount = total_included - total_excluded | ||||
|  |                 taxes += ret['taxes'] | ||||
|  |                 continue | ||||
|  | 
 | ||||
|  |             tax_amount = tax._compute_amount(base, price_unit, quantity, product, partner) | ||||
|  |             if not round_tax: | ||||
|  |                 tax_amount = round(tax_amount, prec) | ||||
|  |             else: | ||||
|  |                 tax_amount = currency.round(tax_amount) | ||||
|  | 
 | ||||
|  |             if tax.price_include: | ||||
|  |                 total_excluded -= tax_amount | ||||
|  |                 base -= tax_amount | ||||
|  |             else: | ||||
|  |                 total_included += tax_amount | ||||
|  |              | ||||
|  |             tax_base = base | ||||
|  |              | ||||
|  |             if tax.include_base_amount: | ||||
|  |                 base += tax_amount | ||||
|  | 
 | ||||
|  |             taxes.append({ | ||||
|  |                 'id': tax.id, | ||||
|  |                 'name': tax.with_context(**{'lang': partner.lang} if partner else {}).name, | ||||
|  |                 'amount': tax_amount, | ||||
|  |                 'sequence': tax.sequence, | ||||
|  |                 'account_id': tax.account_id.id, | ||||
|  |                 'refund_account_id': tax.refund_account_id.id, | ||||
|  |                 'analytic': tax.analytic, | ||||
|  |                 'base': tax_base, | ||||
|  |             }) | ||||
|  |         return { | ||||
|  |             'taxes': sorted(taxes, key=lambda k: k['sequence']), | ||||
|  |             'total_excluded': total_excluded, | ||||
|  |             'total_included': total_included, | ||||
|  |             'base': base, | ||||
|  |         } | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class SaleOrderLine(models.Model): | ||||
|  |     _inherit = "sale.order.line" | ||||
|  | 
 | ||||
|  |     discount = fields.Float(string='Discount (%)', digits=(16, 20), default=0.0) | ||||
|  | 
 | ||||
| @ -0,0 +1,23 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ################################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | #    Copyright (C) 2017-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | ||||
|  | #    Author: fasluca(<https://www.cybrosys.com>) | ||||
|  | # | ||||
|  | #    This program is free software: you can modify | ||||
|  | #    it under the terms of the GNU Affero General Public License (AGPL) as | ||||
|  | #    published by the Free Software Foundation, either version 3 of the | ||||
|  | #    License, or (at your option) any later version. | ||||
|  | # | ||||
|  | #    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 for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU Affero General Public License | ||||
|  | #    along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ################################################################################### | ||||
|  | from . import invoice_report | ||||
|  | from . import sale_report | ||||
| @ -0,0 +1,40 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ################################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | #    Copyright (C) 2017-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | ||||
|  | #    Author: fasluca(<https://www.cybrosys.com>) | ||||
|  | # | ||||
|  | #    This program is free software: you can modify | ||||
|  | #    it under the terms of the GNU Affero General Public License (AGPL) as | ||||
|  | #    published by the Free Software Foundation, either version 3 of the | ||||
|  | #    License, or (at your option) any later version. | ||||
|  | # | ||||
|  | #    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 for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU Affero General Public License | ||||
|  | #    along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ################################################################################### | ||||
|  | 
 | ||||
|  | from odoo import fields, models | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class AccountInvoiceReport(models.Model): | ||||
|  |     _inherit = 'account.invoice.report' | ||||
|  | 
 | ||||
|  |     discount = fields.Float('Discount', readonly=True) | ||||
|  | 
 | ||||
|  |     def _select(self): | ||||
|  |         res = super(AccountInvoiceReport,self)._select() | ||||
|  |         select_str = res + """, sub.discount AS discount """ | ||||
|  |         return select_str | ||||
|  | 
 | ||||
|  |     def _sub_select(self): | ||||
|  |         res = super(AccountInvoiceReport,self)._sub_select() | ||||
|  |         select_str = res + """,SUM ((invoice_type.sign * ail.quantity) / (u.factor * u2.factor) * ail.price_unit * | ||||
|  |          ail.discount / 100) AS discount""" | ||||
|  |         return select_str | ||||
| @ -0,0 +1,36 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ################################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | #    Copyright (C) 2017-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | ||||
|  | #    Author: fasluca(<https://www.cybrosys.com>) | ||||
|  | # | ||||
|  | #    This program is free software: you can modify | ||||
|  | #    it under the terms of the GNU Affero General Public License (AGPL) as | ||||
|  | #    published by the Free Software Foundation, either version 3 of the | ||||
|  | #    License, or (at your option) any later version. | ||||
|  | # | ||||
|  | #    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 for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU Affero General Public License | ||||
|  | #    along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ################################################################################### | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | from odoo import fields, models | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class DiscountSaleReport(models.Model): | ||||
|  |     _inherit = 'sale.report' | ||||
|  | 
 | ||||
|  |     discount = fields.Float('Discount', readonly=True) | ||||
|  | 
 | ||||
|  |     def _select(self): | ||||
|  |         res = super(DiscountSaleReport,self)._select() | ||||
|  |         select_str = res+""",sum(l.product_uom_qty / u.factor * u2.factor * cr.rate * l.price_unit * l.discount / 100.0) | ||||
|  |          as discount""" | ||||
|  |         return select_str | ||||
| After Width: | Height: | Size: 70 KiB | 
| After Width: | Height: | Size: 50 KiB | 
| After Width: | Height: | Size: 9.9 KiB | 
| @ -0,0 +1,98 @@ | |||||
|  | <section class="oe_container"> | ||||
|  |     <div class="oe_row"> | ||||
|  |         <h2 class="oe_slogan">Global Discount In Sale</h2> | ||||
|  |         <h4 class="oe_slogan"><a href="https://www.cybrosys.com">Cybrosys Technologies</a></h4> | ||||
|  |     </div> | ||||
|  | </section> | ||||
|  | <section class="oe_container oe_dark"> | ||||
|  |     <div class="oe_row oe_spaced"> | ||||
|  |         <h3 class="oe_slogan"> | ||||
|  |             This module allows you to mention  discount  on Total of sale order and Total of Customer Invoice in two ways | ||||
|  |         </h3> | ||||
|  |     </div> | ||||
|  |     <div class="oe_row oe_spaced"> | ||||
|  |         <h4><span style="color:green;"> ★</span>As percentage</h4> | ||||
|  |         <p> | ||||
|  |             Select 'Percentage' from Discount type and give discount percentage as Discount rate. | ||||
|  |             System will update the value of Discount and Total | ||||
|  |         </p> | ||||
|  |         <h4><span style="color:green;"> ★</span> As amount</h4> | ||||
|  |         <p> | ||||
|  |             Select 'Amount' from Discount type and give discount amount as Discount rate. | ||||
|  |             System will update the value of Discount and Total | ||||
|  |         </p> | ||||
|  |     </div> | ||||
|  | </section> | ||||
|  | 
 | ||||
|  | <section class="oe_container "> | ||||
|  |     <div class="oe_row oe_spaced"> | ||||
|  | 
 | ||||
|  |         <div class="oe_span12"> | ||||
|  |             <div class="oe_demo oe_picture oe_screenshot" style="max-height:600px;"> | ||||
|  |                 <img style="border:10px solid white;" src="s_d_so.png"> | ||||
|  |                 <div class="oe_demo_footer oe_centeralign"style="background-color:rgba(162, 70, 137, 0.7);">Sale Order</div> | ||||
|  |             </div> | ||||
|  |         </div> | ||||
|  | 
 | ||||
|  |         <div class="oe_span12"> | ||||
|  |             <div class="oe_demo oe_picture oe_screenshot" style="max-height:600px;"> | ||||
|  |                 <img style="border:10px solid white;" src="s_d_inv.png"> | ||||
|  |                 <div class="oe_demo_footer oe_centeralign"style="background-color:rgba(162, 70, 137, 0.7);">Customer Invoice</div> | ||||
|  |             </div> | ||||
|  |         </div> | ||||
|  | 
 | ||||
|  |     </div> | ||||
|  | </section> | ||||
|  | 
 | ||||
|  | <section class="oe_container oe_dark"> | ||||
|  |     <div class="oe_row oe_spaced"> | ||||
|  |         <h3 class="oe_slogan"> | ||||
|  |             And the module also allows you to set a limit for total discount in percentage. Exceeding this limit | ||||
|  |             will require approval. | ||||
|  |         </h3> | ||||
|  |     </div> | ||||
|  |     <div class="oe_row oe_spaced"> | ||||
|  |         <div class="oe_span12"> | ||||
|  |             <div class="oe_demo oe_picture oe_screenshot"> | ||||
|  |                 <img src="s_d_settings.png"> | ||||
|  |             </div> | ||||
|  |         </div> | ||||
|  |     </div> | ||||
|  |     <div class="oe_row oe_spaced"> | ||||
|  |         <h4> | ||||
|  |             Manager level users can approve sale orders in 'Waiting Approval' stage. | ||||
|  |         </h4> | ||||
|  |     </div> | ||||
|  |     <div class="oe_row oe_spaced"> | ||||
|  |         <div class="oe_row_img oe_centered oe_mt32"> | ||||
|  |             <img class="oe_picture oe_screenshot" src="s_d_state.png"> | ||||
|  |         </div> | ||||
|  |     </div> | ||||
|  | </section> | ||||
|  | 
 | ||||
|  | <section class="oe_container"> | ||||
|  |     <h2 class="oe_slogan" style="margin-top:20px;" >Need Any Help?</h2> | ||||
|  |     <div class="oe_slogan" style="margin-top:10px !important;"> | ||||
|  |         <div> | ||||
|  |             <a  class="btn btn-primary btn-lg mt8" | ||||
|  |             style="color: #FFFFFF !important;border-radius: 0;" href="https://www.cybrosys.com"><i | ||||
|  |             class="fa fa-envelope"></i> Email </a> <a | ||||
|  |             class="btn btn-primary btn-lg mt8" style="color: #FFFFFF !important;border-radius: 0;" | ||||
|  |             href="https://www.cybrosys.com/contact/"><i | ||||
|  |             class="fa fa-phone"></i> Contact Us </a> <a | ||||
|  |             class="btn btn-primary btn-lg mt8" style="color: #FFFFFF !important;border-radius: 0;" | ||||
|  |             href="https://www.cybrosys.com/odoo-customization-and-installation/"><i | ||||
|  |             class="fa fa-check-square"></i> Request Customization </a> | ||||
|  |         </div> | ||||
|  |         <br> | ||||
|  |         <img src="cybro_logo.png" style="width: 190px; margin-bottom: 20px;" class="center-block"> | ||||
|  |         <div> | ||||
|  |           <a href="https://twitter.com/cybrosys" target="_blank"><i class="fa fa-2x fa-twitter" style="color:white;background: #00a0d1;width:35px;"></i></a></td> | ||||
|  |           <a href="https://www.linkedin.com/company/cybrosys-technologies-pvt-ltd" target="_blank"><i class="fa fa-2x fa-linkedin" style="color:white;background: #31a3d6;width:35px;padding-left: 3px;"></i></a></td> | ||||
|  |           <a href="https://www.facebook.com/cybrosystechnologies" target="_blank"><i class="fa fa-2x fa-facebook" style="color:white;background: #3b5998;width:35px;padding-left: 8px;"></i></a></td> | ||||
|  |           <a href="https://plus.google.com/106641282743045431892/about" target="_blank"><i class="fa fa-2x fa-google-plus" style="color:white;background: #c53c2c;width:35px;padding-left: 3px;"></i></a></td> | ||||
|  |           <a href="https://in.pinterest.com/cybrosys" target="_blank"><i class="fa fa-2x fa-pinterest" style="color:white;background: #ac0f18;width:35px;padding-left: 3px;"></i></a></td> | ||||
|  |         </div> | ||||
|  |     </div> | ||||
|  | </section> | ||||
|  | 
 | ||||
| After Width: | Height: | Size: 38 KiB | 
| After Width: | Height: | Size: 67 KiB | 
| After Width: | Height: | Size: 42 KiB | 
| After Width: | Height: | Size: 9.4 KiB | 
| @ -0,0 +1,41 @@ | |||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||
|  | <odoo> | ||||
|  |     <data> | ||||
|  | 
 | ||||
|  |         <record id="discount_account_invoice_view_form" model="ir.ui.view"> | ||||
|  |             <field name="name">discount.account.invoice</field> | ||||
|  |             <field name="model">account.invoice</field> | ||||
|  |             <field name="inherit_id" ref="account.invoice_form"/> | ||||
|  |             <field name="arch" type="xml"> | ||||
|  |                 <xpath expr="//field[@name='discount']" position="attributes"> | ||||
|  |                     <attribute name="digits">(16, 2)</attribute> | ||||
|  |                 </xpath> | ||||
|  |                 <xpath expr="//field[@name='amount_untaxed']" position="after"> | ||||
|  |                         <field name="amount_discount"/> | ||||
|  |                 </xpath> | ||||
|  |                 <xpath expr="//field[@name='comment']" position="before"> | ||||
|  |                     <div> | ||||
|  |                         <label for="discount_type" string="Discount Type :"/> | ||||
|  |                         <field name="discount_type" class="oe_inline"/> | ||||
|  |                     </div> | ||||
|  |                     <div> | ||||
|  |                         <label for="discount_rate" string="Discount Rate :"/> | ||||
|  |                         <field name="discount_rate" class="oe_inline"/> | ||||
|  |                     </div> | ||||
|  |                 </xpath> | ||||
|  |             </field> | ||||
|  |         </record> | ||||
|  | 
 | ||||
|  |         <record id="discount_view_invoice_line_tree" model="ir.ui.view"> | ||||
|  |             <field name="name">discount.account.invoice.line.tree</field> | ||||
|  |             <field name="model">account.invoice.line</field> | ||||
|  |             <field name="inherit_id" ref="account.view_invoice_line_tree"/> | ||||
|  |             <field name="arch" type="xml"> | ||||
|  |                 <xpath expr="//field[@name='discount']" position="attributes"> | ||||
|  |                     <attribute name="digits">(16, 2)</attribute> | ||||
|  |                 </xpath> | ||||
|  |             </field> | ||||
|  |         </record> | ||||
|  | 
 | ||||
|  |     </data> | ||||
|  | </odoo> | ||||
| @ -0,0 +1,18 @@ | |||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||
|  | <odoo> | ||||
|  |     <data> | ||||
|  | 
 | ||||
|  |         <template id="report_invoice_customized" inherit_id="account.report_invoice_document"> | ||||
|  |             <xpath expr="//tr[hasclass('border-black')]" position="after"> | ||||
|  |                 <tr> | ||||
|  |                     <td>Discount</td> | ||||
|  |                     <td class="text-right"> | ||||
|  |                         <span t-field="o.amount_discount" | ||||
|  |                             t-options='{"widget": "monetary", "display_currency": "o.currency_id"}'/> | ||||
|  |                     </td> | ||||
|  |                 </tr> | ||||
|  |             </xpath> | ||||
|  |         </template> | ||||
|  | 
 | ||||
|  |     </data> | ||||
|  | </odoo> | ||||
| @ -0,0 +1,33 @@ | |||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||
|  | <odoo> | ||||
|  |     <record id="res_config_settings_view_form_sale_discount" model="ir.ui.view"> | ||||
|  |         <field name="name">res.config.settings.view.form.inherit.sale.discount</field> | ||||
|  |         <field name="model">res.config.settings</field> | ||||
|  |         <field name="priority" eval="10"/> | ||||
|  |         <field name="inherit_id" ref="sale.res_config_settings_view_form" /> | ||||
|  |         <field name="arch" type="xml"> | ||||
|  |             <xpath expr="//div[@data-key='sale_management']/div[hasclass('o_settings_container')][2]/div[hasclass('o_setting_box')][2]" position="after"> | ||||
|  | 
 | ||||
|  |                 <div class="col-xs-12 col-md-6 o_setting_box"> | ||||
|  |                     <div class="o_setting_left_pane"> | ||||
|  |                         <field name="so_order_approval"/> | ||||
|  |                     </div> | ||||
|  |                     <div class="o_setting_right_pane"> | ||||
|  |                         <label for="so_order_approval"/> | ||||
|  |                         <span class="fa fa-lg fa-building-o" title="Values set here are company-specific." groups="base.group_multi_company"/> | ||||
|  |                         <div class="text-muted"> | ||||
|  |                             Managers must approve discount | ||||
|  |                         </div> | ||||
|  |                         <div class="content-group" attrs="{'invisible': [('so_order_approval', '=', False)]}"> | ||||
|  |                             <div class="row mt16"> | ||||
|  |                                 <label for="so_double_validation_limit" class="col-md-4 o_light_label"/> | ||||
|  |                                 <field name="so_double_validation_limit"/> | ||||
|  |                             </div> | ||||
|  |                         </div> | ||||
|  |                     </div> | ||||
|  |                 </div> | ||||
|  | 
 | ||||
|  |             </xpath> | ||||
|  |         </field> | ||||
|  |     </record> | ||||
|  | </odoo> | ||||
| @ -0,0 +1,21 @@ | |||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||
|  | <odoo> | ||||
|  |     <data> | ||||
|  | 
 | ||||
|  |         <template id="report_saleorder_customized" inherit_id="sale.report_saleorder_document"> | ||||
|  |             <xpath expr="//span[@t-field='line.discount']" position="replace"> | ||||
|  |                  <span t-esc="'%.2f'%(l.discount)"/> | ||||
|  |             </xpath> | ||||
|  |             <xpath expr="//tr[hasclass('border-black')]" position="after"> | ||||
|  |                 <tr> | ||||
|  |                     <td>Total Discount</td> | ||||
|  |                     <td class="text-right"> | ||||
|  |                         <span t-field="doc.amount_discount" | ||||
|  |                               t-options='{"widget": "monetary", "display_currency": doc.pricelist_id.currency_id}'/> | ||||
|  |                     </td> | ||||
|  |                 </tr> | ||||
|  |             </xpath> | ||||
|  |         </template> | ||||
|  | 
 | ||||
|  |     </data> | ||||
|  | </odoo> | ||||
| @ -0,0 +1,43 @@ | |||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||
|  | <odoo> | ||||
|  |     <data> | ||||
|  | 
 | ||||
|  |         <record id="discount_sale_view_form" model="ir.ui.view"> | ||||
|  |             <field name="name">discount.sale.order.form</field> | ||||
|  |             <field name="model">sale.order</field> | ||||
|  |             <field name="inherit_id" ref="sale.view_order_form"/> | ||||
|  |             <field name="arch" type="xml"> | ||||
|  |                 <xpath expr="//field[@name='state']" position="before"> | ||||
|  |                     <button string="Approve" type="object" name="action_approve" states="waiting" class="oe_highlight" | ||||
|  |                             groups="sales_team.group_sale_manager"/> | ||||
|  |                 </xpath> | ||||
|  |                 <xpath expr="//button[@name='action_cancel']" position="attributes"> | ||||
|  |                      <attribute name ="states">draft,sent,sale,waiting</attribute> | ||||
|  |                 </xpath> | ||||
|  |                 <!--<xpath expr="//tree/field[@name='discount']" position="replace">--> | ||||
|  |                     <!--<field name="discount" class="oe_inline" digits="(16, 2)"/> %%--> | ||||
|  |                 <!--</xpath>--> | ||||
|  |                 <xpath expr="//group[@name='sale_total']" position="replace"> | ||||
|  |                     <group col="4"> | ||||
|  |                         <group name="discount" colspan="2"> | ||||
|  |                             <field name="discount_type"/> | ||||
|  |                             <field name="discount_rate"/> | ||||
|  |                         </group> | ||||
|  |                         <group class="oe_subtotal_footer oe_right" colspan="2" name="sale_total"> | ||||
|  |                             <field name="amount_untaxed" widget='monetary' options="{'currency_field': 'currency_id'}"/> | ||||
|  |                             <field name="amount_discount" widget='monetary' options="{'currency_field': 'currency_id'}"/> | ||||
|  |                             <field name="amount_tax" widget='monetary' options="{'currency_field': 'currency_id'}"/> | ||||
|  |                             <div class="oe_subtotal_footer_separator oe_inline"> | ||||
|  |                                 <label for="amount_total" /> | ||||
|  |                                 <button name="button_dummy" | ||||
|  |                                         states="draft,sent" string="(update)" type="object" class="oe_edit_only oe_link"/> | ||||
|  |                             </div> | ||||
|  |                             <field name="amount_total" nolabel="1" class="oe_subtotal_footer_separator" widget='monetary' options="{'currency_field': 'currency_id'}"/> | ||||
|  |                         </group> | ||||
|  |                     </group> | ||||
|  |                 </xpath> | ||||
|  |             </field> | ||||
|  |         </record> | ||||
|  | 
 | ||||
|  |     </data> | ||||
|  | </odoo> | ||||