@ -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> |