From 34af6f521e3c77cc9653e0cfb3acaf043e2acfd4 Mon Sep 17 00:00:00 2001 From: Haresh Chavda Date: Thu, 11 Jan 2018 10:52:40 +0530 Subject: [PATCH] [ADD] account_discount Module --- addons/account_discount/__init__.py | 3 + addons/account_discount/__manifest__.py | 28 ++ .../data/account_discount_data.xml | 22 ++ .../demo/discount_config_demo.xml | 15 ++ .../i18n/account_discount.pot | 252 ++++++++++++++++++ addons/account_discount/models/__init__.py | 5 + .../models/account_invoice.py | 143 ++++++++++ .../models/discount_config.py | 49 ++++ .../models/res_config_settings.py | 61 +++++ .../report/custom_invoice_report.xml | 59 ++++ .../account_discount/report/report_menu.xml | 12 + .../security/ir.model.access.csv | 3 + .../static/description/icon.png | Bin 0 -> 11278 bytes addons/account_discount/tests/__init__.py | 5 + .../account_discount/tests/discount_common.py | 22 ++ .../tests/test_01_account_discount.py | 89 +++++++ .../tests/test_02_account_discount_invoice.py | 26 ++ .../views/account_invoice_views.xml | 37 +++ .../views/discount_config_view.xml | 27 ++ .../views/res_config_settings_views.xml | 45 ++++ 20 files changed, 903 insertions(+) create mode 100644 addons/account_discount/__init__.py create mode 100644 addons/account_discount/__manifest__.py create mode 100644 addons/account_discount/data/account_discount_data.xml create mode 100644 addons/account_discount/demo/discount_config_demo.xml create mode 100644 addons/account_discount/i18n/account_discount.pot create mode 100644 addons/account_discount/models/__init__.py create mode 100644 addons/account_discount/models/account_invoice.py create mode 100644 addons/account_discount/models/discount_config.py create mode 100644 addons/account_discount/models/res_config_settings.py create mode 100644 addons/account_discount/report/custom_invoice_report.xml create mode 100644 addons/account_discount/report/report_menu.xml create mode 100644 addons/account_discount/security/ir.model.access.csv create mode 100644 addons/account_discount/static/description/icon.png create mode 100644 addons/account_discount/tests/__init__.py create mode 100644 addons/account_discount/tests/discount_common.py create mode 100644 addons/account_discount/tests/test_01_account_discount.py create mode 100644 addons/account_discount/tests/test_02_account_discount_invoice.py create mode 100644 addons/account_discount/views/account_invoice_views.xml create mode 100644 addons/account_discount/views/discount_config_view.xml create mode 100644 addons/account_discount/views/res_config_settings_views.xml diff --git a/addons/account_discount/__init__.py b/addons/account_discount/__init__.py new file mode 100644 index 00000000..84245eb2 --- /dev/null +++ b/addons/account_discount/__init__.py @@ -0,0 +1,3 @@ +# Part of Flectra See LICENSE file for full copyright and licensing details. + +from . import models diff --git a/addons/account_discount/__manifest__.py b/addons/account_discount/__manifest__.py new file mode 100644 index 00000000..ef858027 --- /dev/null +++ b/addons/account_discount/__manifest__.py @@ -0,0 +1,28 @@ +# Part of Flectra See LICENSE file for full copyright and licensing details. + +{ + 'name': "Account Discount", + 'description': """ + Customized module for amending discounts + """, + 'summary': 'Global Discount on Account Invoice', + 'author': 'FlectraHQ', + 'category': 'Accounting', + 'website': 'https://flectrahq.com', + 'version': '1.0', + 'depends': ['account_invoicing'], + 'data': [ + 'security/ir.model.access.csv', + 'data/account_discount_data.xml', + 'views/account_invoice_views.xml', + 'views/res_config_settings_views.xml', + 'views/discount_config_view.xml', + 'report/report_menu.xml', + 'report/custom_invoice_report.xml', + ], + 'demo':[ + 'demo/discount_config_demo.xml', + ], + 'installable': True, + 'auto_install': False, +} diff --git a/addons/account_discount/data/account_discount_data.xml b/addons/account_discount/data/account_discount_data.xml new file mode 100644 index 00000000..04e2310c --- /dev/null +++ b/addons/account_discount/data/account_discount_data.xml @@ -0,0 +1,22 @@ + + + + + + 1000 + 25 + + + + + 500 + 15 + + + + + 100 + 10 + + + diff --git a/addons/account_discount/demo/discount_config_demo.xml b/addons/account_discount/demo/discount_config_demo.xml new file mode 100644 index 00000000..1a8b6fca --- /dev/null +++ b/addons/account_discount/demo/discount_config_demo.xml @@ -0,0 +1,15 @@ + + + + + + 1200 + 10 + + + + + 2500 + 25 + + \ No newline at end of file diff --git a/addons/account_discount/i18n/account_discount.pot b/addons/account_discount/i18n/account_discount.pot new file mode 100644 index 00000000..d9b7d5f7 --- /dev/null +++ b/addons/account_discount/i18n/account_discount.pot @@ -0,0 +1,252 @@ +# Translation of Flectra Server. +# This file contains the translation of the following modules: +# * account_discount +# +msgid "" +msgstr "" +"Project-Id-Version: Flectra Server 1.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-01-04 11:43+0000\n" +"PO-Revision-Date: 2018-01-04 11:43+0000\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: account_discount +#: model:ir.ui.view,arch_db:account_discount.custom_invoice_report_layout +msgid "&nbsp;on" +msgstr "" + +#. module: account_discount +#: model:ir.ui.view,arch_db:account_discount.inherit_account_invoice_form +msgid "(Update Discount)" +msgstr "" + +#. module: account_discount +#: model:ir.ui.view,arch_db:account_discount.custom_invoice_report_layout +msgid "Discount" +msgstr "" + +#. module: account_discount +#: model:ir.ui.view,arch_db:account_discount.custom_invoice_report_layout +msgid "Gross Amount" +msgstr "" + +#. module: account_discount +#: model:ir.ui.view,arch_db:account_discount.custom_invoice_report_layout +msgid "Subtotal" +msgstr "" + +#. module: account_discount +#: model:ir.ui.view,arch_db:account_discount.custom_invoice_report_layout +msgid "Total" +msgstr "" + +#. module: account_discount +#: model:ir.ui.view,arch_db:account_discount.account_discount_config_view_form +msgid "Account Discount Configuration" +msgstr "" + +#. module: account_discount +#: model:ir.ui.view,arch_db:account_discount.res_config_settings_view_form_invoice_discount_form +msgid "Allow global discount on the Invoice" +msgstr "" + +#. module: account_discount +#: code:addons/account_discount/models/discount_config.py:21 +#, python-format +msgid "Assigned group already exist!" +msgstr "" + +#. module: account_discount +#: model:ir.model.fields,field_description:account_discount.field_account_discount_config_create_uid +msgid "Created by" +msgstr "" + +#. module: account_discount +#: model:ir.model.fields,field_description:account_discount.field_account_discount_config_create_date +msgid "Created on" +msgstr "" + +#. module: account_discount +#: model:ir.model.fields,field_description:account_discount.field_account_invoice_discount +#: model:ir.ui.view,arch_db:account_discount.inherit_account_invoice_form +msgid "Discount" +msgstr "" + +#. module: account_discount +#: model:ir.model.fields,field_description:account_discount.field_account_invoice_discount_per +msgid "Discount (%)" +msgstr "" + +#. module: account_discount +#: code:addons/account_discount/models/account_invoice.py:123 +#, python-format +msgid "Discount (%s) should be less than Gross Amount (%s)." +msgstr "" + +#. module: account_discount +#: model:ir.model.fields,field_description:account_discount.field_account_invoice_discount_amount +msgid "Discount Amount" +msgstr "" + +#. module: account_discount +#: model:ir.model.fields,field_description:account_discount.field_account_invoice_discount_method +msgid "Discount Method" +msgstr "" + +#. module: account_discount +#: code:addons/account_discount/models/account_invoice.py:121 +#, python-format +msgid "Discount should be less than Gross Amount" +msgstr "" + +#. module: account_discount +#: model:ir.actions.act_window,name:account_discount.action_account_discount_config +#: model:ir.ui.menu,name:account_discount.menu_account_order +msgid "Discounts" +msgstr "" + +#. module: account_discount +#: model:ir.model.fields,field_description:account_discount.field_account_discount_config_display_name +msgid "Display Name" +msgstr "" + +#. module: account_discount +#: model:ir.model.fields,field_description:account_discount.field_res_config_settings_global_discount_invoice_apply +msgid "Do you want to set global discount limit?" +msgstr "" + +#. module: account_discount +#: model:ir.model.fields,field_description:account_discount.field_account_discount_config_fix_amount +#: model:ir.model.fields,field_description:account_discount.field_res_config_settings_global_discount_fix_invoice_amount +msgid "Fix Amount" +msgstr "" + +#. module: account_discount +#: code:addons/account_discount/models/discount_config.py:30 +#, python-format +msgid "Fix amount (%s) is greater than configuration Amount (%s)!" +msgstr "" + +#. module: account_discount +#: selection:account.invoice,discount_method:0 +msgid "Fixed" +msgstr "" + +#. module: account_discount +#: model:ir.model.fields,field_description:account_discount.field_res_config_settings_global_discount_invoice_line +msgid "Global Discounts" +msgstr "" + +#. module: account_discount +#: model:ir.model.fields,field_description:account_discount.field_account_invoice_gross_amount +msgid "Gross Amount" +msgstr "" + +#. module: account_discount +#: model:ir.model.fields,field_description:account_discount.field_account_discount_config_group_id +msgid "Groups" +msgstr "" + +#. module: account_discount +#: model:ir.model.fields,field_description:account_discount.field_account_discount_config_id +msgid "ID" +msgstr "" + +#. module: account_discount +#: model:ir.model,name:account_discount.model_account_invoice +msgid "Invoice" +msgstr "" + +#. module: account_discount +#: model:ir.ui.view,arch_db:account_discount.res_config_settings_view_form_invoice_discount_form +msgid "Invoice Discount" +msgstr "" + +#. module: account_discount +#: model:ir.model.fields,field_description:account_discount.field_account_discount_config___last_update +msgid "Last Modified on" +msgstr "" + +#. module: account_discount +#: model:ir.model.fields,field_description:account_discount.field_account_discount_config_write_uid +msgid "Last Updated by" +msgstr "" + +#. module: account_discount +#: model:ir.model.fields,field_description:account_discount.field_account_discount_config_write_date +msgid "Last Updated on" +msgstr "" + +#. module: account_discount +#: selection:account.invoice,discount_method:0 +#: model:ir.model.fields,field_description:account_discount.field_account_discount_config_percentage +msgid "Percentage" +msgstr "" + +#. module: account_discount +#: model:ir.model.fields,field_description:account_discount.field_res_config_settings_global_discount_percentage_invoice +msgid "Percentage (%)" +msgstr "" + +#. module: account_discount +#: code:addons/account_discount/models/discount_config.py:44 +#, python-format +msgid "Percentage (%s) is greater than configuration Percentage (%s)!" +msgstr "" + +#. module: account_discount +#: code:addons/account_discount/models/account_invoice.py:95 +#, python-format +msgid "Percentage should be between 0% to 100%" +msgstr "" + +#. module: account_discount +#: code:addons/account_discount/models/discount_config.py:38 +#, python-format +msgid "Percentage should be between 0% to 100%!" +msgstr "" + +#. module: account_discount +#: model:ir.ui.view,arch_db:account_discount.inherit_account_invoice_form +msgid "Subtotal" +msgstr "" + +#. module: account_discount +#: code:addons/account_discount/models/account_invoice.py:98 +#, python-format +msgid "You are not allowed to apply Discount Percentage (%s) more than configured Discount Percentage (%s) in configuration setting!" +msgstr "" + +#. module: account_discount +#: code:addons/account_discount/models/account_invoice.py:107 +#, python-format +msgid "You are not allowed to apply Discount Percentage(%s) more than configured Discount Percentage (%s) in configuration setting!" +msgstr "" + +#. module: account_discount +#: code:addons/account_discount/models/account_invoice.py:138 +#, python-format +msgid "You're not allowed to apply this amount of discount as discount Amount (%s) is greater than Configuration Amount (%s)." +msgstr "" + +#. module: account_discount +#: code:addons/account_discount/models/account_invoice.py:129 +#, python-format +msgid "You're not allowed to apply this amount of discount as discount Amount (%s) is greater than assign Fix Amount (%s)." +msgstr "" + +#. module: account_discount +#: model:ir.model,name:account_discount.model_account_discount_config +msgid "account.discount.config" +msgstr "" + +#. module: account_discount +#: model:ir.model,name:account_discount.model_res_config_settings +msgid "res.config.settings" +msgstr "" + diff --git a/addons/account_discount/models/__init__.py b/addons/account_discount/models/__init__.py new file mode 100644 index 00000000..90260aba --- /dev/null +++ b/addons/account_discount/models/__init__.py @@ -0,0 +1,5 @@ +# Part of Flectra See LICENSE file for full copyright and licensing details. + +from . import res_config_settings +from . import discount_config +from . import account_invoice diff --git a/addons/account_discount/models/account_invoice.py b/addons/account_discount/models/account_invoice.py new file mode 100644 index 00000000..ea87ba8c --- /dev/null +++ b/addons/account_discount/models/account_invoice.py @@ -0,0 +1,143 @@ +# Part of Flectra See LICENSE file for full copyright and licensing details. + +from flectra import models, fields, api, _ +from flectra.tools.misc import formatLang +from flectra.exceptions import Warning + + +class AccountInvoice(models.Model): + _inherit = "account.invoice" + + @api.multi + @api.depends('discount_amount', 'discount_per', 'amount_untaxed') + def _get_discount(self): + total_discount = 0.0 + for record in self: + for invoice_line_id in record.invoice_line_ids: + total_price = ( + invoice_line_id.quantity * invoice_line_id.price_unit) + total_discount += \ + (total_price * invoice_line_id.discount) / 100 + record.discount = record.currency_id.round(total_discount) + + @api.multi + @api.depends('invoice_line_ids', 'discount_per', 'discount_amount') + def _get_total_amount(self): + for invoice_id in self: + invoice_id.gross_amount = sum( + [line_id.quantity * line_id.price_unit + for line_id in invoice_id.invoice_line_ids]) + + discount_method = fields.Selection( + [('fixed', 'Fixed'), ('per', 'Percentage')], string="Discount Method") + discount_amount = fields.Float(string="Discount Amount") + discount_per = fields.Float(string="Discount (%)") + discount = fields.Monetary( + string='Discount', readonly=True, compute='_get_discount', + track_visibility='always') + gross_amount = fields.Float(string="Gross Amount", + compute='_get_total_amount', store=True) + + @api.multi + def calculate_discount(self): + self._check_constrains() + for line in self.invoice_line_ids: + line.write({'discount': 0.0}) + amount_untaxed = self.amount_untaxed + if self.discount_method == 'per': + for line in self.invoice_line_ids: + line.write({'discount': line.discount + self.discount_per}) + else: + for line in self.invoice_line_ids: + discount_value_ratio = \ + (self.discount_amount * line.price_subtotal) / \ + amount_untaxed + discount_per_ratio = \ + (discount_value_ratio * 100) / line.price_subtotal + line.write({'discount': line.discount + discount_per_ratio}) + + @api.constrains('discount_per', 'discount_amount', 'invoice_line_ids') + def _check_constrains(self): + self.onchange_discount_per() + self.onchange_discount_amount() + + @api.onchange('discount_method') + def onchange_discount_method(self): + self.discount_amount = 0.0 + self.discount_per = 0.0 + if self.discount_method and not self.invoice_line_ids: + raise Warning('No Invoice Line(s) were found!') + + @api.multi + def get_maximum_per_amount(self): + account_dis_config_obj = self.env['account.discount.config'] + max_percentage = 0 + max_amount = 0 + check_group = False + for groups_id in self.env.user.groups_id: + account_dis_config_id = account_dis_config_obj.search( + [('group_id', '=', groups_id.id)]) + if account_dis_config_id: + check_group = True + if account_dis_config_id.percentage > max_percentage: + max_percentage = account_dis_config_id.percentage + if account_dis_config_id.fix_amount > max_amount: + max_amount = account_dis_config_id.fix_amount + return {'max_percentage': max_percentage, + 'max_amount': max_amount, 'check_group': check_group} + + @api.onchange('discount_per') + def onchange_discount_per(self): + values = self.get_maximum_per_amount() + if self.discount_method == 'per' and ( + self.discount_per > 100 or self.discount_per < 0) \ + and values.get('check_group', False): + raise Warning(_("Percentage should be between 0% to 100%")) + if self.discount_per > values.get('max_percentage', False) \ + and values.get('check_group', False): + raise Warning(_("You are not allowed to apply Discount Percentage " + "(%s) more than configured Discount Percentage " + "(%s) in configuration setting!") % ( + formatLang(self.env, self.discount_per, digits=2), + formatLang(self.env, values['max_percentage'], digits=2))) + config_id = self.env[ + 'res.config.settings'].search([], order='id desc', limit=1) + if config_id and config_id.global_discount_invoice_apply: + if config_id.global_discount_percentage_invoice < self.discount_per: + raise Warning(_("You are not allowed to apply Discount " + "Percentage(%s) more than configured Discount" + " Percentage (%s) in configuration setting!" + ) % ( + formatLang(self.env, self.discount_per, digits=2), + formatLang(self.env, config_id.global_discount_percentage_invoice, + digits=2))) + + @api.onchange('discount_amount') + def onchange_discount_amount(self): + if self.discount_method == 'per': + return True + values = self.get_maximum_per_amount() + if self.discount < 0: + raise Warning(_("Discount should be less than Gross Amount")) + if self.discount > self.gross_amount: + raise Warning(_("Discount (%s) should be less than " + "Gross Amount (%s).") % ( + formatLang(self.env, self.discount, digits=2), + formatLang(self.env, self.gross_amount, digits=2))) + if self.discount > values.get('max_amount', False) \ + and values.get('check_group', False): + raise Warning(_("You're not allowed to apply this amount of " + "discount as discount Amount (%s) is greater than" + " assign Fix Amount (%s).") % ( + formatLang(self.env, self.discount, digits=2), + formatLang(self.env, values['max_amount'], digits=2))) + config_id = self.env[ + 'res.config.settings'].search([], order='id desc', limit=1) + if config_id and config_id.global_discount_invoice_apply: + if config_id.global_discount_fix_invoice_amount < self.discount_amount: + raise Warning(_("You're not allowed to apply this amount of" + " discount as discount Amount (%s) is greater" + " than Configuration Amount (%s).") % ( + formatLang(self.env, self.discount, digits=2), + formatLang(self.env, config_id.global_discount_fix_invoice_amount, + digits=2))) diff --git a/addons/account_discount/models/discount_config.py b/addons/account_discount/models/discount_config.py new file mode 100644 index 00000000..a813c426 --- /dev/null +++ b/addons/account_discount/models/discount_config.py @@ -0,0 +1,49 @@ +# Part of Flectra See LICENSE file for full copyright and licensing details. + +from flectra import api, fields, models, _ +from flectra.tools.misc import formatLang + + +class AccountDiscountConfig(models.Model): + _name = 'account.discount.config' + + group_id = fields.Many2one('res.groups', 'Groups', required=True) + fix_amount = fields.Float('Fix Amount', required=True) + percentage = fields.Float('Percentage', required=True) + + @api.constrains('group_id') + def _check_already_exist(self): + check_name = self.search( + [('id', '!=', self.id), + ('group_id.name', '=', self.group_id.name)]) + if check_name: + raise ValueError( + _("Assigned group already exist!")) + + @api.constrains('fix_amount') + def _check_fix_amount_value(self): + config_id = self.env['res.config.settings'].search( + [], order='id desc', limit=1) + if config_id and config_id.global_discount_invoice_apply \ + and config_id.global_discount_fix_invoice_amount < self.fix_amount: + raise ValueError( + _("Fix amount (%s) is greater than configuration Amount (%s)!" + ) % (formatLang( + self.env, self.fix_amount, digits=2), formatLang( + self.env, config_id.global_discount_fix_invoice_amount, digits=2))) + + @api.constrains('percentage') + def _check_percentage(self): + if self.percentage < 0 or self.percentage > 100: + raise ValueError(_("Percentage should be between 0% to 100%!")) + config_id = self.env[ + 'res.config.settings'].search([], order='id desc', limit=1) + if config_id and config_id.global_discount_invoice_apply \ + and config_id.global_discount_percentage_invoice < self.percentage: + raise ValueError( + _("Percentage (%s) is greater than configuration Percentage " + "(%s)!") % (formatLang( + self.env, self.percentage, digits=2), + formatLang(self.env, + config_id.global_discount_percentage_invoice, + digits=2))) diff --git a/addons/account_discount/models/res_config_settings.py b/addons/account_discount/models/res_config_settings.py new file mode 100644 index 00000000..81ad7870 --- /dev/null +++ b/addons/account_discount/models/res_config_settings.py @@ -0,0 +1,61 @@ +# Part of Flectra See LICENSE file for full copyright and licensing details. + +from flectra import api, fields, models + + +class ResConfigSettings(models.TransientModel): + _inherit = 'res.config.settings' + + global_discount_invoice_line = fields.Boolean( + "Global Discounts", + implied_group='account_discount.global_discount_invoice_line') + global_discount_invoice_apply = fields.Boolean( + "Do you want to set global discount limit?", + implied_group='account_discount.global_discount_invoice_apply') + global_discount_fix_invoice_amount = fields.Integer( + 'Fix Amount', + implied_group='account_discount.global_discount_invoice_apply') + global_discount_percentage_invoice = fields.Integer( + 'Percentage (%)', + implied_group='account_discount.global_discount_percentage_invoice') + + @api.onchange('global_discount_invoice_line') + def onchange_global_discount_invoice_line(self): + if not self.global_discount_invoice_line: + self.global_discount_invoice_apply = False + + @api.onchange('global_discount_invoice_apply') + def onchange_global_discount_invoice_apply(self): + if not self.global_discount_invoice_apply: + self.global_discount_fix_invoice_amount = False + + @api.model + def get_values(self): + res = super(ResConfigSettings, self).get_values() + res.update( + global_discount_invoice_line=self.env[ + 'ir.config_parameter'].sudo().get_param( + 'global_discount_invoice_line'), + global_discount_invoice_apply=self.env[ + 'ir.config_parameter'].sudo().get_param( + 'global_discount_invoice_apply'), + global_discount_fix_invoice_amount=int(self.env[ + 'ir.config_parameter'].sudo().get_param( + 'global_discount_fix_invoice_amount')), + global_discount_percentage_invoice=int(self.env[ + 'ir.config_parameter'].sudo().get_param( + 'global_discount_percentage_invoice')), + ) + return res + + def set_values(self): + super(ResConfigSettings, self).set_values() + params = self.env['ir.config_parameter'].sudo() + params.set_param('global_discount_invoice_line', + self.global_discount_invoice_line) + params.set_param('global_discount_invoice_apply', + self.global_discount_invoice_apply) + params.set_param('global_discount_fix_invoice_amount', + self.global_discount_fix_invoice_amount) + params.set_param('global_discount_percentage_invoice', + self.global_discount_percentage_invoice) diff --git a/addons/account_discount/report/custom_invoice_report.xml b/addons/account_discount/report/custom_invoice_report.xml new file mode 100644 index 00000000..5d4c7d5b --- /dev/null +++ b/addons/account_discount/report/custom_invoice_report.xml @@ -0,0 +1,59 @@ + + + + \ No newline at end of file diff --git a/addons/account_discount/report/report_menu.xml b/addons/account_discount/report/report_menu.xml new file mode 100644 index 00000000..c43d7519 --- /dev/null +++ b/addons/account_discount/report/report_menu.xml @@ -0,0 +1,12 @@ + + + + diff --git a/addons/account_discount/security/ir.model.access.csv b/addons/account_discount/security/ir.model.access.csv new file mode 100644 index 00000000..5c811c04 --- /dev/null +++ b/addons/account_discount/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_account_discount_config,access_account_discount_config,model_account_discount_config,base.group_system,1,1,1,1 +access_account_discount_config_all,access_account_discount_config_all,model_account_discount_config,,1,0,0,0 diff --git a/addons/account_discount/static/description/icon.png b/addons/account_discount/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..b44ec8a1f6950f28b55195deabfc132073ffe4ec GIT binary patch literal 11278 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 z z7)@HXM96(_<36?XmsCpABlT#lwZu+56H$&dPm-wQqv0ZZJ5EX#lm%4#!DtiQaB z|7f?LeYCXfj8-rf+ZmfjKRjO^N4%K{Q*ecL;)+`2J&I4EvS{jSf=xy<-&8u zlIyHwb}l8t!coyNMKsJaq?sQ;{;-UlS0Zmb@X@YaS4$CENQ$NZ5f&iPGm?<}-sm%UHZ^~hes=oIV8`r$NiTsTbL`9IK-50s zVb#(F0m_Y?NJ}-mz9F%{GZjx?c4CEWG;ay@2)aGcH$08r?(5+DhJ&QTa#cz!ezIv7 z8IJE2%R<4NcP(sFxO$|}S@+e`T;-{AkmYt2+b>Ze zNVo8hj3(O70r6p&YM_yk2`db5vt!SBr^HXM<@1?WhIZ)uGE?k(o|L_6je!dw)?(1k8fCoIM(U95j)r)nD&(qi| zaE7m;lqZ@m6#2y4Wzib0ckx+YU?e6>EkEalXbRj$Q}VoewA@psMS7<9W{lf@%YU}d ztFhcCD3C0Sy?M5GX7X@g24SnqVdc2>P1h|-rn7&Bwcp4ZQ7~ji=TJ$wEwUeCYzV#T zUN=C%_a_B#&gYzh^07h*IkzAZTMn$o?6!YOnFT93?Y73_+&&=0ccOhXjaATTqJNiXPPk+edvqsqp&VkX)HcRwCM8r zX;8A*bS%~shvkknCXdn?#=3pA804WK{(&)F=+^{nviC;G>#Q*#ZGq%+ws zJpd4}LIQdR2l8R!SzUIqkiX#A*skg2NtdMd=P}O?H1I%c`L&q9U*EfQ3nSGOoKACj_;ll-&3u|oGQwCSL)V| z((@Ym4h=vD+zXx^m04j8la`{^*8nn5{V?M+uvBYTRx^6^)W6w;`_J8^0V3x0xGq?| zW=`Hh(8*)=yC)QCf&W-SCP~ih#W{`gzfBI2R-PrW$c_DuFUKO)bnfa4fk=fyL~^=n zh?5|{i5j`wribo+^3Pr8N7?bH>B=C@{AraT%s{?f!~xhHAkk8VD-DSB>JFE+64i}lgCs67CewdN^dz`3#hhtb zAt&t{pFZl7?Gx~U2{)$1;2*_tzx$SwVn?&!GZF=W;mnO0fbAlki?s`XyYebQACVUU zr4y=kpQ2PSA+VrwK4cO5?O5{_%?6$$W^TLOv)t%aX%DUsHQvs9&9o=!2TVfTfiS!8 zjc@6UX|af6KWiF;hB1H`aKpjzB?J*7;y-Fc`c<{kP8_@2mk)31w*S`@CvM1NCzls5 zrH*fp{!jpXW0+j-cX)$Pb(n?n%l;*NfHW+RKhAika}^ILIm~Y7oRg5HV#wy6uo#hR zaX+2{-<2dHL&sz9Mr_xw7xE2JZ@v6=T(Z*fV0E`#c?Sw;$}+hfk;=B||Bbc&?@~Vg z_Dais9`iTF5T*~}Aj?6CAizZ-QPHvm;b}iYQ!ga0CYCc1hh<}%_%uN4-6JlnVaZz} zp*Iqd*)8bfsCQzcw4yn`z4MLqYKFOq>pI7t0(3u?78HJ;2Al4Ub|Tab5P$a>wara z{N>-?Bn=$=wZIS2@VY`BXoOnD+vZ2rg33}E_5Ha;C&kn*=sdojw8TWX7F9?UtJxbX z?>za+SJMk=XRu{||Dde1LMUE#cD$lOCrk5%t|M1;h(>m@y<7kK4Tc?0F~e=Uw^`O{ zz?`Rj2lGpbl2Cahey^vhRD?n1DedHDvD$f)?KXQr%nEZgH{KjRl9ENx_Ym7Ap{FgE zEe|nev6qfCx+dZE?`7INy?0lrO0Q!OPyDLl0aRQHOUiJ@Lx++8=0k1 zA3{>y{2VdK8%OsL3s`+f2u#NXxo>a&Xr^fC+LQ3hHBLI-6 z-0`YR38`gnJrS$u5qL&Qj<4L)eT$>6&-*qJVHtp4oco%ANjo?`<$HD+s?S-`t`#dM zX==_i**~NPhn}h+@gzxyM0#;g}})e0%-_m>sc+saq{E>(W;ATb7aALAlx44L^DR_ueQlFN;_KzkPI zW+6RFwD$|3AO`N?CAZk|SStH0Eav`ylf0mW)M?Hk0zJ*fbg4^RUrlt>AcY6c2;@0* zi9Cg#;Ys@cIn~d%fryFYTtz){6A3SI^2&^Uk_`uJ+p8TNaw*E25}U-8$S=zd8^8GT znH`$!(z39?^-z=Wz^`BPBaQ=ai#I*bv_EcFbBW(YekepvTko;PqV@yYHEhXro(cADij1-})mk9UV`R`oI*f z(B+Zr@rYUH*W_cLTgRB#k2h0ZgbImSG-fFKoZ0zi7hL~Gc6-BreG_lpiSU8>ZeXwF ziQDFsB2}bvdoQd0(^m3cSJ8jt9CIaPO!Cc;fFKMJdNKN>6YcN-yIJc_|I@&=PSd;v zl9+^73arS0Pj%e*){12tPrU6JHR@c?qlDO_Ac77yJ_+)~aRII8V zmpW-R+XENe`hVTv5+bQGSUNfDIuxd8YUe~6G(;;9@OGC_`kR&GlE*gl3XK}h%X4t5W50$pGZ=Ivh+v6)!grmJAI>n$MX1< zIBggOzl_+J9;FP(c%&T`Jg|-=1WqCYWPv8_#z#NBF4s(@H+n50L}1!na+R*$REnLf z5kL7|QTHuGuX|Kl4dr_RVJk(aAxwSG`VNtS!G|6(sy{YMxjZ0Az<$-DAV*h`&5hXi9LV>G z3lmlbyRNwp&sP(*l`BH9NFebSH+v%cqy+bVacf_WC@uxDzIAJz^2k?Y&ak`R-v9E@wwPe+@z1<;Z|B2n}avU*&F*x z3IWYY-&tnQ;nNH?&Fj)#L^i<3ay(&Axim^z|8aU=w;(BA{=7xH`+ct)+Yq z?c!Nzr?~(@5Q3Zm@iuuBw@9f0Or%0%a0~9|*uh(Jx3*!1Bi$#ZJE1J7U~)(v`uEfA z^2eoI4Sm?=I((ke>l7RORrJX)(T&!%S2>vdPIt&4*&Jew0tic(oet(R6i@XTy4tvH zOrJAMG=jxgeA!ZQ0Am<<5q$(!Q+SK%d%r_|sz66{$E_|?bW)5FZRo&!$B#uNaZcj~ zX%~K01_c_U-X2Y_+M*zW?uOXJPUrU14Zu=X?9b7ckSFE3{dp9+VQ_ux= zB0K@;c%7|S*oP1)XPh;oyp!U&FU4GTLuw)6b1e)<%-M8LAO{+5xlrif4RBVzeRVZ;K z{JOxbjPHa?wm^Rm%N8_dtobLy03{5?i;CugMWcqge218%Jpzzms41bA&^4wutM*s< zhr*bmL$Y9%aEB90UZ!96yIKP*zp%0ua2#jM?pSz4(wiKt<#yZgi-P=5W_~M9?%3|4 z##`0(!;`EzA;SbkcVU)XZ(28oPclBXc!kECZSj%Vf*v0K6RCTS1)cTtwvmL1IFi3u zvBS@ej$$j~p4hud!e#qS8^+mq=;dyR0Y)zPJT5ea_Z7%`zAZ+Xsi13~HcYGJ0{CyZ zboL!xp#>eZd={C@C@Fv0SlEKI*D1LYuRobmwp6CZbADlaoA!sUO?&}zkA> zR@P1M(X5Ji{4T9y{MqIGZGaq9F8`2D_4i}}9dP^cP1$#)mBMR}m>3yj z{~J1VO%pEZ-x$T=kP9#q|3=$xI|+)ENc9VgtVAF?58Zh<8Oq?yK<5xuOIRl-NwKz- z1;30s8!I#;a0r^Gy@$ZGflRI_OeC@w;o_lOZ=$ey%N^$Og_c|kvMAu)oV3CD2w8}C zIII@hzeyg|g)DP15d4fJ5_7#MK4^QprS%!oIYWS9wGt?+B&t7%Zz8n4=gWpAh%GiX zT+UYvtK|z#KO;%vkX72+?EnC8T^b6UAkHHBF$o zN8HPsy(2S{JF|6r<5=f%@f=e1u8ehvZ<{_^V58TNmU>d!@*>b*5->~J7+6cQbiW=F zw&7hUm%k6I6TRqUoYfe5h;zEee@^$p^)f~k4|kE|zWpluyhmn>u4SCEG}n=iP8!WS zH87{JV}X@^P)C2^%zj2l`;d@KjYT`Y$^-G^zVDx*GczVrKUcPVVEKz^`1Qxi{wTn6 za#mo`w`m=)`;4qGNlznn+wX5q@i*stTRmXVYoaow@^2LpRnaxp+{T%Mo$Yw>`V*8m zQ5fRMlp3D7tu(fAY&5mHEtUD_Ggd8{5#;t&H(ODXv!1w@ZZ6c(y#F%I{{7~@@xWqs ziKFN-lLr(KdlBu?YNJNkp5cCbRTp5n;ro7fp=9nw>p(7MQ|*zj%q>EH)EL$$;Qplb z^X~^EA0_>YoxnCRpIHh;<(B%tmZ>y)|0vGZp%r^+)bu-K=ku(~QR3MXC0yed#~Z)4>?nP!-;L_z-Ym z--1$gGC1*KsUJ#9o0%DNnbYh4=HiqmWc~50=PN(6R$5L;G|&?52^_UR<=MQA9<5;7 zPYmmGYz?^b>r3(M*R~`=9LIBjrUs;(z*HQT345b<#V!}+4_3z(^gTa68~3t1-A-1w zBcrs3H!oLMY-U_QdSBRRst}IchiQ@qC3SCG3R>b#&*Iws^j@rT-#1Le^*s8ig%7v% z{xi{?G79tj9<;p#TFAlF8sUN_Lvm_?f9Nm)hQ}J7vs5f0N6FB)SHJrI(0~9s7kTfb zAFDUg5=hE&Y!2g%ghUo&7%+pKGax_-*o5Z#x9C-m_%#2vB7+9o7zQe!urxU*GrAMF z^8<%$#6i4Vxr+L)oS0lUxE~^>TvYuUvgGLM6_t`sZ2vUtv-J<*AibW#+b^P*DZ)aW z(k^?bmb0lWfg#coYAEBAnQZU(&Iq*V+=*9ZcS4cQy5O0nhk1~=gL^~8iy`>q>vzxfa>BPm|wmub$eRj#nF|AHv4Vdv6)DTWOoz##$vt`S=#{F#}5 zM)G))4GM#s$$_(~SW*cZdlidtDN%`^`vVxH*SWL!E=MJ16D+;%?M4oS_tPVb_+f3=q}Z?j884bmre`_-ibSZCHxxpJ;reA&eJr zoW35O&;2>)wT6uQ-Py}i70kK$UUH=b(zJ*?Ye}Vl7B>LT3x}C#YiK6?MB)nsT6hE??EpgtsZn&|%el9WAAu1l&Up5^)+$?dWxlh=^H`x_MTjGRAmeWd{rl zYpg2I@xf6HOM99aYZEpv1X^i+d;>3W`STV6Br2aFQj(+HLkniQQ-zJcWuyueNfvMC zy`^$l?#USeL9za=2IEcGswr$iD84a&<5r3Na#|y5sdOOau!d;E&ESl{LnJ7R1`BA4 z`_NM*hTkvhclVyQCA#O%y~U}MBYPtjaxeRsuz@ykWlqEM&3vh^(>frMqisDJ1vc73 zM4LfRt_g%R;vFo?Rb>xAN&(ZUx0snrjc#aK&x@^w8n5S&$5G+a_E3Jrq>U>MQ!~nK z+b@t5hY*4m`SwPndtXt_l>-1ey4+^VCAoYFob;LxqIJyjXE zP|9`sSPdLf&1nDI2LOyAD1}sr_iIIJ-xd5qd`IH<*7x4wt{*8F1(RF#J`bM87BExO z%sBAjkP!>~?J>1bPJR`8ZXIxtBnldoUJiittpiSt=DK6b?5JiQeNBnZwmhIR2Q?F2 zI1-b!)^(Or40c+hcty3YTH1*X9prf(6_j?$%eCZa{@1dPxzG-y`0xQ3o%8bgZUfbC5x6$pWeFj z{~tL*8fu2Jvffm$$oab)B;3~z(dxL18?FeexE7?3t!KaeFMJYJ)rXgp>>o4^l2!HO z4E;Gl6&!jZZlz3EzQlJi21$B!GPFpv=xIqdTgb>k^Pk3SMeO)CET^-$NXM~K3K<{? z)CQy&j*db?hy7-wEb83=5$4wW)9(U8`+~10gt^-Tl?&cEe7Pf!b_SQ1ap3jONz|xe z*2Oy%t4Lmo<+t#i_lf)Vk!T6zRAo8bn?#G<@P*_5|G6Qxoruwb|gXsIMZ)JTQR zrW)GM*AFd2FS`KwEFM_>4P6C0Mc^0>TuDi4l<#mdu@-j^R~?E&R_tx})^)Z0&@~=W zDOVMQo@cKg6qCLz&6;A87)36Y9Om_uaSR>2j;B`&-F-oaa$AkG~JU&ywCiZ>Zqef|{2LSfa^gjbrn{mjQ zOPL5kF!%`V=X^4UnSOjN(TDkB8;``)Uq%jjJfS?|Iu3)Irr$h8N45TR3jQ$GG*7Go z@gx%zp4->)U;|a|8|Qfb<;-^z>EJK5L*p$q1sy4Y=(%IFnu!#aqgcX?1jYP-&j}uPV{j_RRiz_Y28ZI$+#PC**ZrB8`%&snO`QOOay$}I8MA{7#3#BW!~}0V-*+lZ2j<>lQVp` zPTcT0(cx9d`N!6rpF8Q_u79TT$FEQ&*mZ9I7E7!&9$duW4^it$~ zdlR~T`!$RFW}ICF$gAA{JJG(NBBx%qF{D95ki0pC^BZ+I3}jnMM#2sn|D!Vwb1(JH z_s*@A7j|9?hK@}GZP6Q90p=H!pjSyO+R2I6T~kfqd1(cT!@8`QpG;4OAp4g32Fd6T zb+i{V2ftp7D}h%}HAhkn=}37nf!gO>C08iRV|%%r8hb|^utP{n?u9OuA*ogr!f12y zROndHtL=%>!FF@%BzZ3V<`JQ#HGZIu{_)4T*bFh|G|PM>3D|Q;3*cEOO#24fH0=q- zk_}A!9Mts3K4t8SQN0OE#2=yQi?{c?(XzyETBndWD;{!5eARb>YJ_?2fOU^!S<|0zNEA z!FLj#DIdw__^eXU_U2q+5UUpK0o + + + + account.invoice.inherit.form + account.invoice + + + + + + +
+ + + + + +
+
+
+
+
diff --git a/addons/account_discount/views/discount_config_view.xml b/addons/account_discount/views/discount_config_view.xml new file mode 100644 index 00000000..cb7a0c17 --- /dev/null +++ b/addons/account_discount/views/discount_config_view.xml @@ -0,0 +1,27 @@ + + + + account.discount.config + account.discount.config + + + + + + + + + + + + Discounts + account.discount.config + form + tree + + + + + diff --git a/addons/account_discount/views/res_config_settings_views.xml b/addons/account_discount/views/res_config_settings_views.xml new file mode 100644 index 00000000..2a608923 --- /dev/null +++ b/addons/account_discount/views/res_config_settings_views.xml @@ -0,0 +1,45 @@ + + + + res.config.settings.view.form.inherit.discount.account + res.config.settings + + + + +

Invoice Discount

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