diff --git a/addons/l10n_ae/__init__.py b/addons/l10n_ae/__init__.py index 6f4c944d..446f769c 100644 --- a/addons/l10n_ae/__init__.py +++ b/addons/l10n_ae/__init__.py @@ -1,4 +1,7 @@ # -*- coding: utf-8 -*- -# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details. +# Part of Odoo, Flectra. See LICENSE file for full copyright +# and licensing details. # Copyright (C) 2014 Tech Receptives (). + +from . import models diff --git a/addons/l10n_ae/__manifest__.py b/addons/l10n_ae/__manifest__.py index ac9ba04c..2d2c4db5 100644 --- a/addons/l10n_ae/__manifest__.py +++ b/addons/l10n_ae/__manifest__.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- -# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details. +# Part of Odoo, Flectra. See LICENSE file for full copyright +# and licensing details. # Copyright (C) 2014 Tech Receptives () @@ -17,6 +18,7 @@ United Arab Emirates accounting chart and localization. 'data': [ 'data/account_data.xml', 'data/l10n_ae_chart_data.xml', - 'data/account_chart_template_data.yml', + 'data/account_fiscal_position_data.xml', + 'data/account_chart_template_data.yml' ], } diff --git a/addons/l10n_ae/data/account_fiscal_position_data.xml b/addons/l10n_ae/data/account_fiscal_position_data.xml new file mode 100644 index 00000000..e565fd67 --- /dev/null +++ b/addons/l10n_ae/data/account_fiscal_position_data.xml @@ -0,0 +1,112 @@ + + + + + + + Zero + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Exempted + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/addons/l10n_ae/data/l10n_ae_chart_data.xml b/addons/l10n_ae/data/l10n_ae_chart_data.xml index db0f4728..c5a62ad3 100644 --- a/addons/l10n_ae/data/l10n_ae_chart_data.xml +++ b/addons/l10n_ae/data/l10n_ae_chart_data.xml @@ -13,7 +13,7 @@ 101 - + @@ -1469,6 +1469,13 @@ + + 581001 + Customs Expense + + + + @@ -1498,4 +1505,169 @@ + + + Excise Payable Account + 2013001 + + + + + + + Excise Receivable Account + 1034001 + + + + + + + Vat Payable Account + 2013002 + + + + + + + Vat Receivable Account + 1034002 + + + + + + + Sale - Excise 50% + Sale Excise 50% + sale + percent + 50 + + + excise + + + + + Purchase - Excise 50% + Purchase Excise 50% + purchase + percent + 50 + + + excise + + + + + Sale - Zero% + Sale Zero% + sale + percent + 0 + + + + + + + Purchase - Zero% + Purchase Zero% + purchase + percent + 0 + + + + + + + Sale - Excise 100% + Sale Excise 100% + sale + percent + 100 + + + excise + + + + + Purchase - Excise 100% + Purchase Excise 100% + purchase + percent + excise + 100 + + + + + + + Sale - VAT Exempted + Sale VAT Exempted + sale + percent + 0 + + + exempted + + + + + Purchase - VAT Exempted + Purchase VAT Exempted + purchase + percent + 0 + + + exempted + + + + + Custom + Custom VAT + purchase + percent + 5 + + + customs + + + 0 + + + + Sale - VAT 5% + Sale VAT 5% + sale + percent + 5 + + + vat + + + + + Purchase - VAT 5% + Purchase VAT 5% + purchase + percent + 5 + + + vat + + + diff --git a/addons/l10n_ae/models/__init__.py b/addons/l10n_ae/models/__init__.py new file mode 100644 index 00000000..31d2deb5 --- /dev/null +++ b/addons/l10n_ae/models/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Flectra. See LICENSE file for full copyright and licensing details. + +from . import account_tax diff --git a/addons/l10n_ae/models/account_tax.py b/addons/l10n_ae/models/account_tax.py new file mode 100644 index 00000000..2233144b --- /dev/null +++ b/addons/l10n_ae/models/account_tax.py @@ -0,0 +1,27 @@ +# Part of Flectra. See LICENSE file for full copyright and licensing details. + + +from flectra import fields, models + + +class AccountTaxTemplate(models.Model): + _inherit = 'account.tax.template' + + tax_type = fields.Selection([ + ('vat', 'VAT'), ('customs', 'Customs'), ('excise', 'Excise'), + ('exempted', 'Exempted'), ('other', 'Other')], 'VAT Type') + + def _get_tax_vals(self, company, tax_template_to_tax): + self.ensure_one() + res = super(AccountTaxTemplate, self)._get_tax_vals( + company, tax_template_to_tax) + res['tax_type'] = self.tax_type + return res + + +class AccountTax(models.Model): + _inherit = 'account.tax' + + tax_type = fields.Selection([ + ('vat', 'VAT'), ('customs', 'Customs'), ('excise', 'Excise'), + ('exempted', 'Exempted'), ('other', 'Other')], 'VAT Type') diff --git a/addons/l10n_ae_extend/__init__.py b/addons/l10n_ae_extend/__init__.py new file mode 100644 index 00000000..b69ffe84 --- /dev/null +++ b/addons/l10n_ae_extend/__init__.py @@ -0,0 +1,5 @@ +# Part of Flectra. See LICENSE file for full copyright and licensing details. + +from . import models +from . import wizard +from . import reports diff --git a/addons/l10n_ae_extend/__manifest__.py b/addons/l10n_ae_extend/__manifest__.py new file mode 100644 index 00000000..1ad1c77f --- /dev/null +++ b/addons/l10n_ae_extend/__manifest__.py @@ -0,0 +1,30 @@ +# Part of Flectra. See LICENSE file for full copyright and licensing details. + +{ + 'name': 'U.A.E. - Accounting Extend', + 'author': 'FlectraHQ', + 'website': 'https://www.flectrahq.com/', + 'category': 'Localization', + 'description': """ +United Arab Emirates accounting chart and localization. +======================================================= + + """, + 'depends': ['l10n_ae', 'account_invoicing', 'sale_management', 'purchase'], + 'data': [ + 'security/ir.model.access.csv', + 'data/journal_data.xml', + 'data/vat_config_type_data.xml', + 'views/report_vat_201_view.xml', + 'views/report_menu_view.xml', + 'views/vat_config_type.xml', + 'views/company_view.xml', + 'views/purchase_order_view.xml', + 'views/sale_order_view.xml', + 'views/account_invoice_view.xml', + 'wizard/vat_201_view.xml', + ], + 'demo': [ + 'demo/account_invoice_demo.xml', + ], +} diff --git a/addons/l10n_ae_extend/data/journal_data.xml b/addons/l10n_ae_extend/data/journal_data.xml new file mode 100644 index 00000000..0b108d19 --- /dev/null +++ b/addons/l10n_ae_extend/data/journal_data.xml @@ -0,0 +1,137 @@ + + + + + + 433101 + Local Sale + + + + + Local Sale + LCLS + sale + + + + + + 433102 + Inside GCC Sale + + + + + Inside GCC Sale + IGCCS + sale + + + + + + 433103 + Outside GCC Sale + + + + + Outside GCC Sale + OGCCS + sale + + + + + + 433104 + Designated Zone Sale + + + + + Designated Zone Sale + DZS + sale + + + + + + 205301 + Reverse Charge(Vat) + + + + + 581002 + VAT Expense + + + + + + + + + + + + 571001 + Local Purchase + + + + + Local Purchase + LCLP + purchase + + + + + + 571002 + Inside GCC Purchase + + + + + Inside GCC Purchase + IGCCP + purchase + + + + + + 571003 + Outside GCC Purchase + + + + + Outside GCC Purchase + OGCCP + purchase + + + + + + 571004 + Designated Zone Purchase + + + + + Designated Zone Purchase + DZP + purchase + + + + + + diff --git a/addons/l10n_ae_extend/data/vat_config_type_data.xml b/addons/l10n_ae_extend/data/vat_config_type_data.xml new file mode 100644 index 00000000..5e6d5f7b --- /dev/null +++ b/addons/l10n_ae_extend/data/vat_config_type_data.xml @@ -0,0 +1,71 @@ + + + + + + Local Sale + LCLSJC + + sale + local_sale + + + + Inside GCC Sale + IGCCSJC + + sale + inside_gcc_sale + + + + Outside GCC Sale + OGCCSJC + + sale + outside_gcc_sale + + + + Designated Zone Sale + DZSJC + + sale + designated_zone_sale + + + + + Local Purchase + LCLPJC + + purchase + local_purchase + + + + Inside GCC Purchase + IGCCPJC + + purchase + inside_gcc_purchase + + + + Outside GCC Purchase + OGCCPJC + + purchase + outside_gcc_purchase + + + + Designated Zone Purchase + DZPJC + + purchase + designated_zone_purchase + + + + diff --git a/addons/l10n_ae_extend/demo/account_invoice_demo.xml b/addons/l10n_ae_extend/demo/account_invoice_demo.xml new file mode 100644 index 00000000..9592453e --- /dev/null +++ b/addons/l10n_ae_extend/demo/account_invoice_demo.xml @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + out_invoice + + + + + + + + + Graphics Card + + + 885.0 + 2.0 + + + + + + + + + + + + + + out_refund + + + + + + + + + + Graphics Card + + 885.0 + + 1.0 + + + + + + + + + + + + + in_invoice + + + + + + + + + Graphics Card + + + 876.0 + 20.0 + + + + + + + + + + + + + + in_refund + + + + + + + + + + Graphics Card + + + 876.0 + 10.0 + + + + + + + + + + + + + + in_invoice + + + + + + + + + + Graphics Card + + + 876.0 + 20.0 + + + + + + + + + + + + + in_refund + + + + + + + + + + Graphics Card + + + 876.0 + 5.0 + + + + + + + + \ No newline at end of file diff --git a/addons/l10n_ae_extend/models/__init__.py b/addons/l10n_ae_extend/models/__init__.py new file mode 100644 index 00000000..9252a0a7 --- /dev/null +++ b/addons/l10n_ae_extend/models/__init__.py @@ -0,0 +1,7 @@ +# Part of flectra. See LICENSE file for full copyright and licensing details. + +from . import vat_config_type +from . import company +from . import sale +from . import purchase +from . import account_invoice diff --git a/addons/l10n_ae_extend/models/account_invoice.py b/addons/l10n_ae_extend/models/account_invoice.py new file mode 100644 index 00000000..252c6542 --- /dev/null +++ b/addons/l10n_ae_extend/models/account_invoice.py @@ -0,0 +1,191 @@ +# Part of Flectra. See LICENSE file for full copyright and licensing details. + +from flectra import fields, models, api, _ +from flectra.exceptions import Warning + + +class ReverseAccountInvoiceTax(models.Model): + _inherit = 'account.invoice.tax' + _name = 'reverse.account.invoice.tax' + + +class AccountInvoice(models.Model): + _inherit = 'account.invoice' + + @api.multi + def _default_config_type(self): + domain = [] + if self._context.get('type', False) in ['out_invoice', 'out_refund']: + domain = [('journal_id.type', '=', 'sale')] + elif self._context.get('type', False) in ['in_invoice', 'in_refund']: + domain = [('journal_id.type', '=', 'purchase')] + return self.vat_config_type.search(domain, limit=1) + + vat_config_type = fields.Many2one( + 'vat.config.type', 'Vat Type', default=_default_config_type, + readonly=True, states={'draft': [('readonly', False)]}) + reverse_charge = fields.Boolean( + 'Reverse Charge', readonly=True, + states={'draft': [('readonly', False)]}) + reverse_tax_line_ids = fields.One2many( + 'reverse.account.invoice.tax', 'invoice_id', string='Tax Lines', + readonly=True, states={'draft': [('readonly', False)]}, copy=False) + + @api.onchange('vat_config_type') + def onchange_vat_config_type(self): + if self.vat_config_type: + self.journal_id = self.vat_config_type.journal_id.id + if self.vat_config_type.vat_type == 'designated_zone_purchase': + fiscal_position_id = self.fiscal_position_id.search( + [('name', 'ilike', 'exempt')], limit=1) + if not fiscal_position_id: + fiscal_position_id = self.env.ref('l10n_ae.fp_in_exempted') + else: + fiscal_position_id = fiscal_position_id.id + self.fiscal_position_id = fiscal_position_id + else: + self.journal_id = self._default_journal() + + @api.one + @api.depends( + 'state', 'currency_id', 'invoice_line_ids.price_subtotal', + 'move_id.line_ids.amount_residual', + 'move_id.line_ids.currency_id') + def _compute_residual(self): + super(AccountInvoice, self)._compute_residual() + sign = self.type in ['in_refund', 'out_refund'] and -1 or 1 + if self.reverse_charge: + residual = self.residual - self.amount_tax + self.residual_signed = abs(residual) * sign + self.residual = abs(residual) + + @api.multi + def action_invoice_open(self): + if not self.reverse_charge: + return super(AccountInvoice, self).action_invoice_open() + if not self.company_id.rc_vat_account_id: + raise Warning(_('Define Reverse Charge Account in Company!')) + list_data = [] + account_tax_obj = self.env['account.tax'] + custom_amount = 0.0 + self.reverse_tax_line_ids = [[6, 0, []]] + for tax_line in self.tax_line_ids: + tax_id = account_tax_obj.search([('name', 'ilike', tax_line.name)]) + custom_amount += \ + tax_line.amount_total if tax_id.tax_type == 'customs' else 0.0 + account_id = tax_id.account_id.id + if self.partner_id.vat: + account_id = tax_line.account_id.id + elif tax_id.tax_type == 'vat': + account_id = self.company_id.vat_expense_account_id.id + list_data.append((0, 0, { + 'name': tax_line.name, + 'partner_id': + self.partner_id.parent_id.id or self.partner_id.id, + 'account_id': account_id, + 'debit': tax_line.amount_total, + 'move_id': False, + 'invoice_id': self.id, + 'tax_line_id': tax_id, + 'quantity': 1, + } + )) + + total_tax_amount = self.amount_tax + reverse_list_data = [] + for tax_line_id in self.tax_line_ids: + reverse_list_data.append((0, 0, tax_line_id.read()[0])) + + if reverse_list_data: + self.update({'reverse_tax_line_ids': reverse_list_data}) + for line_id in self.invoice_line_ids: + line_id.reverse_invoice_line_tax_ids = \ + [[6, 0, line_id.invoice_line_tax_ids.ids]] + + self.invoice_line_ids.update({'invoice_line_tax_ids': [[6, 0, []]]}) + self.update({'tax_line_ids': [[6, 0, []]], 'amount_tax': 0.0}) + res = super(AccountInvoice, self).action_invoice_open() + + for move_line_id in list_data: + move_line_id[2].update({'move_id': self.move_id.id}) + list_data.append( + (0, 0, self.get_move_line_vals(total_tax_amount - custom_amount))) + if custom_amount: + list_data.append((0, 0, self.get_move_line_vals(custom_amount))) + self.move_id.state = 'draft' + self.move_id.line_ids = list_data + self.move_id.post() + return res + + @api.multi + def get_move_line_vals(self, credit): + return { + 'name': '/', + 'partner_id': self.partner_id.parent_id.id or self.partner_id.id, + 'account_id': self.company_id.rc_vat_account_id.id, + 'credit': credit, + 'move_id': self.move_id.id, + 'invoice_id': self.id, + 'quantity': 1, + } + + @api.onchange('purchase_id') + def purchase_order_change(self): + if self.purchase_id: + self.vat_config_type = self.purchase_id.vat_config_type.id + self.reverse_charge = self.purchase_id.reverse_charge + return super(AccountInvoice, self).purchase_order_change() + + @api.onchange('partner_id', 'company_id') + def _onchange_partner_id(self): + res = super(AccountInvoice, self)._onchange_partner_id() + self.journal_id = self.vat_config_type.journal_id.id + return res + + @api.onchange('state', 'partner_id', 'invoice_line_ids', + 'vat_config_type', 'reverse_charge') + def _onchange_allowed_purchase_ids(self): + result = super(AccountInvoice, self)._onchange_allowed_purchase_ids() + result['domain']['purchase_id'] += [ + ('vat_config_type', '=', self.vat_config_type.id), + ('reverse_charge', '=', self.reverse_charge)] + return result + + @api.onchange('fiscal_position_id') + def _onchange_fiscal_position_id(self): + if self.fiscal_position_id: + for line in self.invoice_line_ids: + line._set_taxes() + + @api.multi + @api.returns('self') + def refund(self, date_invoice=None, + date=None, description=None, journal_id=None): + result = super(AccountInvoice, self).refund( + date_invoice=date_invoice, date=date, + description=description, journal_id=journal_id) + result.write({ + 'vat_config_type': result.refund_invoice_id.vat_config_type.id}) + if result.refund_invoice_id.type == 'in_invoice': + result.write( + {'reverse_charge': result.refund_invoice_id.reverse_charge}) + if result.type == 'in_refund' \ + and result.refund_invoice_id.reverse_charge: + for index, line_id in enumerate(result.invoice_line_ids): + line_id.invoice_line_tax_ids = [[ + 6, 0, result.refund_invoice_id.invoice_line_ids[ + index].reverse_invoice_line_tax_ids.ids]] + result._onchange_invoice_line_ids() + return result + + +class AccountInvoiceLine(models.Model): + _inherit = "account.invoice.line" + + reverse_invoice_line_tax_ids = fields.Many2many( + 'account.tax', string='Taxes', copy=False) + + @api.v8 + def get_invoice_line_account(self, type, product, fpos, company): + return self.invoice_id.vat_config_type.\ + journal_id.default_debit_account_id diff --git a/addons/l10n_ae_extend/models/company.py b/addons/l10n_ae_extend/models/company.py new file mode 100644 index 00000000..a1f9e3a1 --- /dev/null +++ b/addons/l10n_ae_extend/models/company.py @@ -0,0 +1,12 @@ +# Part of Flectra. See LICENSE file for full copyright and licensing details. + +from flectra import fields, models + + +class ResCompany(models.Model): + _inherit = 'res.company' + + rc_vat_account_id = fields.Many2one('account.account', 'Reverse Charge') + customs_duty_account_id = fields.Many2one( + 'account.account', 'Customs Expense') + vat_expense_account_id = fields.Many2one('account.account', 'Vat Expense') diff --git a/addons/l10n_ae_extend/models/purchase.py b/addons/l10n_ae_extend/models/purchase.py new file mode 100644 index 00000000..719ef18c --- /dev/null +++ b/addons/l10n_ae_extend/models/purchase.py @@ -0,0 +1,19 @@ +# Part of Flectra. See LICENSE file for full copyright and licensing details. + +from flectra import fields, models, api + + +class PurchaseOrder(models.Model): + _inherit = 'purchase.order' + + @api.multi + def _default_config_type(self): + return self.vat_config_type.search([ + ('journal_id.type', '=', 'purchase')], limit=1) + + vat_config_type = fields.Many2one( + 'vat.config.type', 'Vat Type', default=_default_config_type, + readonly=True, states={'draft': [('readonly', False)]}) + reverse_charge = fields.Boolean( + 'Reverse Charge', readonly=True, + states={'draft': [('readonly', False)]}) diff --git a/addons/l10n_ae_extend/models/sale.py b/addons/l10n_ae_extend/models/sale.py new file mode 100644 index 00000000..6740ebfb --- /dev/null +++ b/addons/l10n_ae_extend/models/sale.py @@ -0,0 +1,27 @@ +# Part of Flectra. See LICENSE file for full copyright and licensing details. + +from flectra import fields, models, api + + +class SaleOrder(models.Model): + _inherit = 'sale.order' + + @api.multi + def _default_config_type(self): + return self.vat_config_type.search([ + ('journal_id.type', '=', 'sale')], limit=1) + + vat_config_type = fields.Many2one( + 'vat.config.type', 'Vat Type', default=_default_config_type, + readonly=True, states={'draft': [('readonly', False)]}) + + @api.multi + def _prepare_invoice(self): + invoice_vals = super(SaleOrder, self)._prepare_invoice() + invoice_vals.update({ + 'vat_config_type': self.vat_config_type.id, + 'journal_id': self.vat_config_type.journal_id.id, + 'account_id': + self.vat_config_type.journal_id.default_debit_account_id.id, + }) + return invoice_vals diff --git a/addons/l10n_ae_extend/models/vat_config_type.py b/addons/l10n_ae_extend/models/vat_config_type.py new file mode 100644 index 00000000..f9157e57 --- /dev/null +++ b/addons/l10n_ae_extend/models/vat_config_type.py @@ -0,0 +1,23 @@ +# Part of Flectra. See LICENSE file for full copyright and licensing details. + +from flectra import fields, models + + +class JournalConfigType(models.Model): + _name = 'vat.config.type' + _description = 'Config Type' + + name = fields.Char('Name') + code = fields.Char('Code') + journal_id = fields.Many2one('account.journal', 'Journal') + vat_type = fields.Selection([ + ('local_sale', 'Local Sale'), + ('inside_gcc_sale', 'Inside GCC Sale'), + ('outside_gcc_sale', 'Outside GCC Sale'), + ('designated_zone_sale', 'Designated Zone Sale'), + ('local_purchase', 'Local Purchase'), + ('inside_gcc_purchase', 'Inside GCC Purchase'), + ('outside_gcc_purchase', 'Outside GCC Purchase'), + ('designated_zone_purchase', 'Designated Zone Purchase')]) + type = fields.Selection([ + ('sale', 'Sale'), ('purchase', 'Purchase')], 'Type') diff --git a/addons/l10n_ae_extend/reports/__init__.py b/addons/l10n_ae_extend/reports/__init__.py new file mode 100644 index 00000000..cab3c42d --- /dev/null +++ b/addons/l10n_ae_extend/reports/__init__.py @@ -0,0 +1,3 @@ +# Part of Flectra. See LICENSE file for full copyright and licensing details. + +from . import vat_201_report diff --git a/addons/l10n_ae_extend/reports/vat_201_report.py b/addons/l10n_ae_extend/reports/vat_201_report.py new file mode 100644 index 00000000..120bce79 --- /dev/null +++ b/addons/l10n_ae_extend/reports/vat_201_report.py @@ -0,0 +1,201 @@ +# Part of Flectra. See LICENSE file for full copyright and licensing details. + + +from flectra import api, models + +VAT_SALE_TYPE = ['local_sale', 'inside_gcc_sale', + 'outside_gcc_sale', 'designated_zone_sale'] +VAT_PURCHASE_TYPE = ['local_purchase', 'inside_gcc_purchase', + 'outside_gcc_purchase', 'designated_zone_purchase'] + + +class ReportVat201(models.AbstractModel): + _name = 'report.l10n_ae_extend.vat_201' + + def get_invoice_ids(self, data, invoice_type, vat_type, reverse_charge): + return self.env['account.invoice'].search([ + ('date_invoice', '<=', data['form']['date_to']), + ('date_invoice', '>=', data['form']['date_from']), + ('state', 'in', ['open', 'paid']), + ('type', 'in', invoice_type), + ('vat_config_type.vat_type', 'in', vat_type), + ('reverse_charge', '=', reverse_charge)]) + + def get_local_sale(self, data): + return self.get_invoice_data_for_local(data, ['local_sale']) + + def get_inside_gcc_sale(self, data): + return self.get_invoice_data_for_local(data, ['inside_gcc_sale']) + + def get_outside_gcc_sale(self, data): + return self.get_invoice_data_for_local(data, ['outside_gcc_sale']) + + def get_designated_zone_sale(self, data): + return self.get_invoice_data_for_local(data, VAT_SALE_TYPE) + + def get_total_sale(self, data): + return self.get_invoice_data_for_local(data, VAT_SALE_TYPE) + + def get_subtotal(self, line, tax_ids): + return line.price_subtotal if any( + [tax_id for tax_id in tax_ids + if tax_id.tax_type == 'vat' and tax_id.amount != 0.0]) else 0.0 + + def get_customs_amount(self, tax_ids): + account_tax_object = self.env['account.tax'] + customs_amount = 0.0 + for tax_line_id in tax_ids: + tax_id = account_tax_object.search([ + ('name', '=', tax_line_id.name), ('tax_type', '=', 'customs')]) + customs_amount += tax_line_id.amount_total if tax_id else 0.0 + return customs_amount + + def get_tax_amount(self, tax_ids): + return sum([tax_id.amount for tax_id in tax_ids + if tax_id.tax_id.tax_type == 'vat']) + + def get_invoice_data_for_local(self, data, vat_type): + invoices = self.get_invoice_ids( + data, ['out_invoice', 'out_refund'], vat_type, False) + data_dict = { + 'amount': 0.0, 'total_exempted_amount': 0.0, + 'total_exempted_adjustment': 0.0, 'adjustment': 0.0, + 'tax_amount': 0.0, 'return_tax_amount': 0.0, + 'total_zero_amount': 0.0, 'zero_adjustment': 0.0} + for invoice_id in invoices: + check_line_vat_tax = 0.0 + tax_amount = self.get_tax_amount(invoice_id.tax_line_ids) + for line in invoice_id.invoice_line_ids: + data_dict.update( + self.set_zero_exempted_amount( + data_dict, invoice_id, line, + line.invoice_line_tax_ids)) + check_line_vat_tax += \ + self.get_subtotal(line, line.invoice_line_tax_ids) + check_line_vat_tax += \ + self.get_customs_amount(invoice_id.tax_line_ids) + if invoice_id.type == 'out_refund': + data_dict['adjustment'] += check_line_vat_tax + data_dict['return_tax_amount'] += tax_amount + else: + data_dict['amount'] += check_line_vat_tax + data_dict['tax_amount'] += tax_amount + return data_dict + + def set_zero_exempted_amount( + self, data_dict, invoice_id, line, tax_line_ids): + for tax_id in tax_line_ids: + if tax_id.amount == 0.0: + if invoice_id.type in ['out_invoice', 'in_invoice']: + data_dict['total_exempted_amount'] += \ + line.price_subtotal \ + if tax_id.tax_type == 'exempted' else 0.0 + data_dict['total_zero_amount'] += \ + line.price_subtotal \ + if tax_id.tax_type != 'exempted' else 0.0 + elif invoice_id.type in ['out_refund', 'in_refund']: + data_dict['total_exempted_adjustment'] += \ + line.price_subtotal \ + if tax_id.tax_type == 'exempted' else 0.0 + data_dict['zero_adjustment'] += \ + line.price_subtotal \ + if tax_id.tax_type != 'exempted' else 0.0 + return data_dict + + def get_invoice_data_for_local_purchase(self, data, vat_type): + invoices = self.get_invoice_ids( + data, ['in_invoice', 'in_refund'], vat_type, False) + return self.get_data(invoices) + + def get_data(self, invoices): + data_dict = { + 'amount': 0.0, 'total_exempted_amount': 0.0, + 'total_exempted_adjustment': 0.0, 'adjustment': 0.0, + 'tax_amount': 0.0, 'return_tax_amount': 0.0, + 'total_zero_amount': 0.0, 'zero_adjustment': 0.0} + for invoice_id in invoices: + check_line_vat_tax = 0.0 + invoice_tax_lines = invoice_id.tax_line_ids + if invoice_id.reverse_charge: + invoice_tax_lines = invoice_id.reverse_tax_line_ids + tax_amount = self.get_tax_amount(invoice_tax_lines) + + for line in invoice_id.invoice_line_ids: + tax_line_ids = line.invoice_line_tax_ids + if invoice_id.reverse_charge: + tax_line_ids = line.reverse_invoice_line_tax_ids + data_dict.update(self.set_zero_exempted_amount( + data_dict, invoice_id, line, tax_line_ids)) + check_line_vat_tax += self.get_subtotal(line, tax_line_ids) + check_line_vat_tax += \ + self.get_customs_amount(invoice_id.tax_line_ids) + if invoice_id.type == 'in_refund': + data_dict['adjustment'] += check_line_vat_tax + data_dict['return_tax_amount'] += tax_amount + else: + data_dict['amount'] += check_line_vat_tax + data_dict['tax_amount'] += tax_amount + return data_dict + + def get_local_purchase(self, data): + return self.get_invoice_data_for_local_purchase( + data, ['local_purchase']) + + def get_inside_outside_gcc_purchase(self, data): + return self.get_invoice_data_for_local_purchase( + data, ['inside_gcc_purchase', 'outside_gcc_purchase']) + + def get_zero_vat_purchase(self, data): + return self.get_invoice_data_for_local_purchase( + data, VAT_PURCHASE_TYPE) + + def get_total_purchase(self, data): + reverse_dict = self.get_reverse_charge_data(data) + all_type_dict = self.get_invoice_data_for_local_purchase( + data, VAT_PURCHASE_TYPE) + all_type_dict['amount'] += \ + reverse_dict['amount'] + all_type_dict['total_zero_amount'] + \ + all_type_dict['total_exempted_amount'] + all_type_dict['tax_amount'] += reverse_dict['tax_amount'] + all_type_dict['return_tax_amount'] += reverse_dict['return_tax_amount'] + all_type_dict['adjustment'] += \ + reverse_dict['adjustment'] + all_type_dict['zero_adjustment'] + \ + all_type_dict['total_exempted_adjustment'] + return all_type_dict + + def get_reverse_charge_data(self, data): + invoices = self.get_invoice_ids( + data, ['in_invoice', 'in_refund'], VAT_PURCHASE_TYPE, True) + return self.get_data(invoices) + + def get_total_vat_due(self, data): + sale_data = self.get_total_sale(data) + purchase_data = self.get_total_purchase(data) + vals = { + 'total_tax_amount': + (sale_data['tax_amount'] - sale_data['return_tax_amount'] + ) - (purchase_data['tax_amount'] - purchase_data[ + 'return_tax_amount'])} + return vals + + @api.model + def get_report_values(self, docids, data=None): + currency_id = \ + self.env['res.currency'].browse(data['form']['currency_id'][0]) + return { + 'data': data, + 'currency_name': currency_id.name, + 'get_local_sale': self.get_local_sale(data), + 'get_inside_gcc_sale': self.get_inside_gcc_sale(data), + 'get_outside_gcc_sale': self.get_outside_gcc_sale(data), + 'get_designated_zone_sale': self.get_designated_zone_sale(data), + 'get_total_sale': self.get_total_sale(data), + 'get_local_purchase': self.get_local_purchase(data), + 'get_inside_outside_gcc_purchase': + self.get_inside_outside_gcc_purchase(data), + 'get_zero_vat_purchase': self.get_zero_vat_purchase(data), + 'get_total_purchase': self.get_total_purchase(data), + 'get_total_vat_due': self.get_total_vat_due(data), + 'get_reverse_charge_data': self.get_reverse_charge_data(data), + 'currency_id': currency_id, + } diff --git a/addons/l10n_ae_extend/security/ir.model.access.csv b/addons/l10n_ae_extend/security/ir.model.access.csv new file mode 100644 index 00000000..6159a43a --- /dev/null +++ b/addons/l10n_ae_extend/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_vat_config_type,access_vat_config_type,model_vat_config_type,,1,0,0,0 +access_reverse_account_invoice_tax,access_reverse_account_invoice_tax,model_reverse_account_invoice_tax,,1,0,0,0 diff --git a/addons/l10n_ae_extend/static/description/icon.png b/addons/l10n_ae_extend/static/description/icon.png new file mode 100644 index 00000000..51356fed Binary files /dev/null and b/addons/l10n_ae_extend/static/description/icon.png differ diff --git a/addons/l10n_ae_extend/tests/__init__.py b/addons/l10n_ae_extend/tests/__init__.py new file mode 100644 index 00000000..de9cd504 --- /dev/null +++ b/addons/l10n_ae_extend/tests/__init__.py @@ -0,0 +1,4 @@ +# Part of Flectra See LICENSE file for full copyright and licensing details. + +from . import test_ae_common +from . import test_account_invoice diff --git a/addons/l10n_ae_extend/tests/test_account_invoice.py b/addons/l10n_ae_extend/tests/test_account_invoice.py new file mode 100644 index 00000000..b7d6b92a --- /dev/null +++ b/addons/l10n_ae_extend/tests/test_account_invoice.py @@ -0,0 +1,100 @@ +# Part of Flectra See LICENSE file for full copyright and licensing details. + +from .test_ae_common import TestAECommon +import time +import datetime +from dateutil.relativedelta import relativedelta + + +class TestAccountInvoice(TestAECommon): + def setUp(self): + super(TestAccountInvoice, self).setUp() + + def get_invoice(self, invoice_type, reverse_charge): + invoice_id = self.AccountInvoice.create({ + 'name': 'Test Customer Invoice', + 'partner_id': self.partner_id.id, + 'currency_id': self.env.ref('base.USD').id, + 'account_id': self.account_id.id, + 'type': invoice_type, + 'date_invoice': time.strftime('%Y') + '-03-12', + 'journal_id': self.journal_id.id, + 'vat_config_type': self.config_type_local_sale.id, + 'reverse_charge': reverse_charge, + }) + self.AccountInvoiceLine.create({ + 'product_id': self.product_id.id, + 'quantity': 10, + 'price_unit': 885.00, + 'invoice_id': invoice_id.id, + 'name': 'Graphics Card', + 'account_id': self.account_id.id, + }) + return invoice_id + + def test_customer_invoice(self): + invoice_id = self.get_invoice('out_invoice', False) + line_1 = invoice_id.invoice_line_ids[0] + line_1.get_invoice_line_account( + 'out_invoice', self.product_id, False, self.main_company) + self.assertEquals( + line_1.account_id, + invoice_id.vat_config_type.journal_id.default_debit_account_id) + self.assertEquals( + invoice_id.journal_id, invoice_id.vat_config_type.journal_id) + + def test_vendor_bills(self): + invoice_id = self.get_invoice('in_invoice', True) + line_1 = invoice_id.invoice_line_ids[0] + line_1._onchange_product_id() + invoice_id._onchange_invoice_line_ids() + amount_tax = invoice_id.amount_tax + self.assertEquals(len(invoice_id.tax_line_ids), 1) + self.assertEquals(len(invoice_id.reverse_tax_line_ids), 0) + invoice_id.action_invoice_open() + self.assertEquals(invoice_id.amount_tax, 0) + self.assertEquals(len(invoice_id.tax_line_ids), 0) + self.assertEquals(len(invoice_id.reverse_tax_line_ids), 1) + move_line_id = self.env['account.move.line'].search([ + ('move_id', '=', invoice_id.move_id.id), + ('account_id', '=', self.main_company.rc_vat_account_id.id)]) + self.assertEquals(move_line_id.credit, amount_tax) + + def test_report_data(self): + report_obj = self.env['report.l10n_ae_extend.vat_201'] + date_to = (datetime.date.today() - relativedelta(days=10) + ).strftime('%Y-%m-%d') + date_from = (datetime.date.today() - relativedelta(months=1) + ).strftime('%Y-%m-01') + data = {'form': { + 'date_to': date_to, + 'date_from': date_from, + 'company_id': [self.main_company.id, self.main_company.name], + 'currency_id': [self.main_company.currency_id.id, + self.main_company.currency_id.name], + }} + dict_data = report_obj.get_report_values(None, data) + + self.assertEquals( + dict_data['get_local_sale']['amount'], 1770) + self.assertEquals(dict_data['get_local_sale']['tax_amount'], 88.5) + self.assertEquals(dict_data['get_local_sale']['adjustment'], 885) + self.assertEquals( + dict_data['get_local_sale']['return_tax_amount'], 44.25) + + self.assertEquals(dict_data['get_local_purchase']['amount'], 17520) + self.assertEquals(dict_data['get_local_purchase']['tax_amount'], 876) + self.assertEquals(dict_data['get_local_purchase']['adjustment'], 8760) + self.assertEquals( + dict_data['get_local_purchase']['return_tax_amount'], 438) + + self.assertEquals( + dict_data['get_reverse_charge_data']['amount'], 17520) + self.assertEquals( + dict_data['get_reverse_charge_data']['tax_amount'], 876) + self.assertEquals( + dict_data['get_reverse_charge_data']['adjustment'], 4380) + self.assertEquals( + dict_data['get_reverse_charge_data']['return_tax_amount'], 219) + self.assertEquals( + dict_data['get_total_vat_due']['total_tax_amount'], -1050.75) diff --git a/addons/l10n_ae_extend/tests/test_ae_common.py b/addons/l10n_ae_extend/tests/test_ae_common.py new file mode 100644 index 00000000..f27cc8a0 --- /dev/null +++ b/addons/l10n_ae_extend/tests/test_ae_common.py @@ -0,0 +1,27 @@ +# Part of Flectra See LICENSE file for full copyright and licensing details. + +from flectra.tests.common import TransactionCase + + +class TestAECommon(TransactionCase): + def setUp(self): + super(TestAECommon, self).setUp() + + self.AccountInvoice = self.env['account.invoice'] + self.AccountInvoiceLine = self.env['account.invoice.line'] + self.config_type_local_sale = \ + self.env.ref('l10n_ae_extend.config_type_1') + self.config_type_inside_gcc = \ + self.env.ref('l10n_ae_extend.config_type_2') + self.main_company = self.env.ref('base.main_company') + + self.partner_id = self.env.ref('base.res_partner_3') + self.account_id = self.env.ref('l10n_ae_extend.local_sale_uae_account') + self.journal_id = self.env.ref('l10n_ae_extend.local_sale_journal') + self.product_id = self.env.ref('product.product_product_24') + + self.customer_tax_id = self.env.ref('l10n_ae.sale_uae_vat_5') + self.supplier_tax_id = self.env.ref('l10n_ae.purchase_uae_vat_5') + self.product_id.write({ + 'taxes_id': [(6, 0, [self.customer_tax_id.id])], + 'supplier_taxes_id': [(6, 0, [self.supplier_tax_id.id])]}) diff --git a/addons/l10n_ae_extend/views/account_invoice_view.xml b/addons/l10n_ae_extend/views/account_invoice_view.xml new file mode 100644 index 00000000..81100f23 --- /dev/null +++ b/addons/l10n_ae_extend/views/account_invoice_view.xml @@ -0,0 +1,66 @@ + + + + uae.account.invoice.form.inherit + account.invoice + + + + + + + + + + + + + + reverse.account.invoice.tax.tree + reverse.account.invoice.tax + + + + + + + + + + + + uae.account.invoice.supplier.form.inherit + account.invoice + + + + + + + + + + + + + + + + + + + + + + + uae.account.tax.form.inherit + account.tax + + + + + + + + + diff --git a/addons/l10n_ae_extend/views/company_view.xml b/addons/l10n_ae_extend/views/company_view.xml new file mode 100644 index 00000000..ef2cfd76 --- /dev/null +++ b/addons/l10n_ae_extend/views/company_view.xml @@ -0,0 +1,16 @@ + + + + uae.res.company.form.inherit + res.company + + + + + + + + + + + diff --git a/addons/l10n_ae_extend/views/purchase_order_view.xml b/addons/l10n_ae_extend/views/purchase_order_view.xml new file mode 100644 index 00000000..c47c0ad1 --- /dev/null +++ b/addons/l10n_ae_extend/views/purchase_order_view.xml @@ -0,0 +1,16 @@ + + + + uae.purchase.order.form.inherit + purchase.order + + + + + + + + + + + diff --git a/addons/l10n_ae_extend/views/report_menu_view.xml b/addons/l10n_ae_extend/views/report_menu_view.xml new file mode 100644 index 00000000..88cf4a14 --- /dev/null +++ b/addons/l10n_ae_extend/views/report_menu_view.xml @@ -0,0 +1,11 @@ + + + + diff --git a/addons/l10n_ae_extend/views/report_vat_201_view.xml b/addons/l10n_ae_extend/views/report_vat_201_view.xml new file mode 100644 index 00000000..84b12cac --- /dev/null +++ b/addons/l10n_ae_extend/views/report_vat_201_view.xml @@ -0,0 +1,131 @@ + + + + \ No newline at end of file diff --git a/addons/l10n_ae_extend/views/sale_order_view.xml b/addons/l10n_ae_extend/views/sale_order_view.xml new file mode 100644 index 00000000..b53a9d28 --- /dev/null +++ b/addons/l10n_ae_extend/views/sale_order_view.xml @@ -0,0 +1,13 @@ + + + + uae.sale.order.form.inherit + sale.order + + + + + + + + diff --git a/addons/l10n_ae_extend/views/vat_config_type.xml b/addons/l10n_ae_extend/views/vat_config_type.xml new file mode 100644 index 00000000..870e9f84 --- /dev/null +++ b/addons/l10n_ae_extend/views/vat_config_type.xml @@ -0,0 +1,54 @@ + + + + vat.config.type.tree + vat.config.type + + + + + + + + + + + + + vat.config.type.form + vat.config.type + +
+ + + + + + + + + + + + + + +
+
+
+ + + Vat Types + vat.config.type + form + tree,form + [] + {} + + + + +
diff --git a/addons/l10n_ae_extend/wizard/__init__.py b/addons/l10n_ae_extend/wizard/__init__.py new file mode 100644 index 00000000..6defc409 --- /dev/null +++ b/addons/l10n_ae_extend/wizard/__init__.py @@ -0,0 +1,3 @@ +# Part of Flectra. See LICENSE file for full copyright and licensing details. + +from . import vat_201 diff --git a/addons/l10n_ae_extend/wizard/vat_201.py b/addons/l10n_ae_extend/wizard/vat_201.py new file mode 100644 index 00000000..1ecf28ad --- /dev/null +++ b/addons/l10n_ae_extend/wizard/vat_201.py @@ -0,0 +1,22 @@ +# Part of Flectra. See LICENSE file for full copyright and licensing details. + +from flectra import fields, models + + +class Vat201Report(models.TransientModel): + + _name = "vat.201.report" + _description = "Vat 201" + + date_from = fields.Date(string='Start Date') + date_to = fields.Date(string='End Date') + company_id = fields.Many2one( + 'res.company', string='Company', + required=True, default=lambda self: self.env.user.company_id) + currency_id = fields.Many2one(related='company_id.currency_id') + + def print_report(self, data): + data['form'] = \ + self.read(['date_from', 'date_to', 'company_id', 'currency_id'])[0] + return self.env.ref('l10n_ae_extend.action_report_vat_201' + ).report_action(self, data=data) diff --git a/addons/l10n_ae_extend/wizard/vat_201_view.xml b/addons/l10n_ae_extend/wizard/vat_201_view.xml new file mode 100644 index 00000000..224d09eb --- /dev/null +++ b/addons/l10n_ae_extend/wizard/vat_201_view.xml @@ -0,0 +1,34 @@ + + + + + Vat 201 + vat.201.report + +
+ + + + +
+
+
+
+
+ + + Vat 201 + vat.201.report + ir.actions.act_window + form + form + + {} + new + + + + +