From e9980155cb08a055ff0cea9bab1a7787d4957479 Mon Sep 17 00:00:00 2001 From: Haresh Chavda Date: Mon, 19 Nov 2018 14:24:56 +0530 Subject: [PATCH] [ADD]:Reverse charge mechanism in GST --- addons/l10n_in_gst/__manifest__.py | 1 + addons/l10n_in_gst/data/res_company_data.xml | 14 +++ addons/l10n_in_gst/models/account_invoice.py | 118 +++++++++++++++++- addons/l10n_in_gst/models/res_company.py | 1 + addons/l10n_in_gst/report/gst_report.py | 35 +++--- .../l10n_in_gst/security/ir.model.access.csv | 1 + .../views/account_invoice_view.xml | 24 ++++ addons/l10n_in_gst/views/res_company_view.xml | 3 + 8 files changed, 179 insertions(+), 18 deletions(-) create mode 100644 addons/l10n_in_gst/data/res_company_data.xml diff --git a/addons/l10n_in_gst/__manifest__.py b/addons/l10n_in_gst/__manifest__.py index 3a5b3d56..66be8cfd 100644 --- a/addons/l10n_in_gst/__manifest__.py +++ b/addons/l10n_in_gst/__manifest__.py @@ -17,6 +17,7 @@ 'security/ir.model.access.csv', 'data/product_uom_data.xml', 'data/note_issue_reason_data.xml', + 'data/res_company_data.xml', 'wizard/account_invoice_refund_view.xml', 'views/product_uom_view.xml', 'views/res_partner_view.xml', diff --git a/addons/l10n_in_gst/data/res_company_data.xml b/addons/l10n_in_gst/data/res_company_data.xml new file mode 100644 index 00000000..61ef0ceb --- /dev/null +++ b/addons/l10n_in_gst/data/res_company_data.xml @@ -0,0 +1,14 @@ + + + + + + 205311 + Reverse Charge(GST) + + + + + + + \ No newline at end of file diff --git a/addons/l10n_in_gst/models/account_invoice.py b/addons/l10n_in_gst/models/account_invoice.py index ef40bf6f..83f1e965 100644 --- a/addons/l10n_in_gst/models/account_invoice.py +++ b/addons/l10n_in_gst/models/account_invoice.py @@ -52,6 +52,88 @@ class AccountInvoice(models.Model): 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.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() + 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', '=', tax_line.name)]) + account_id = tax_id.account_id.id + if self.partner_id.vat: + account_id = tax_line.account_id.id + if not account_id: + account_id = tax_line.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))) + 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_gst_account_id.id, + 'credit': credit, + 'move_id': self.move_id.id, + 'invoice_id': self.id, + 'quantity': 1, + } @api.onchange('partner_id', 'company_id') def _onchange_partner_id(self): @@ -60,12 +142,31 @@ class AccountInvoice(models.Model): self.partner_id.partner_location = \ self.partner_id._get_partner_location_details(self.company_id) - @api.onchange('fiscal_position_id') def _onchange_fiscal_position_id(self): """ Onchange of Fiscal Position update tax values in invoice lines. """ - for line in self.invoice_line_ids: - line._set_taxes() + 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) + 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 @api.multi def action_move_create(self): @@ -128,3 +229,14 @@ class AccountInvoice(models.Model): 'gst_type': invoice.gst_type, }) return result + +class ReverseAccountInvoiceTax(models.Model): + _inherit = 'account.invoice.tax' + _name = 'reverse.account.invoice.tax' + + +class AccountInvoiceLine(models.Model): + _inherit = "account.invoice.line" + + reverse_invoice_line_tax_ids = fields.Many2many( + 'account.tax', string='Taxes', copy=False) \ No newline at end of file diff --git a/addons/l10n_in_gst/models/res_company.py b/addons/l10n_in_gst/models/res_company.py index d6cb70b7..b4317764 100644 --- a/addons/l10n_in_gst/models/res_company.py +++ b/addons/l10n_in_gst/models/res_company.py @@ -20,6 +20,7 @@ class Company(models.Model): default=time.strftime('2017-07-01')) company_b2c_limit_line = fields.One2many('res.company.b2c.limit', 'company_id', string='B2C Limit') + rc_gst_account_id = fields.Many2one('account.account', 'Reverse Charge') def onchange_state(self, gst_type, vat, state): result = {'vat': '', 'country_id': False} diff --git a/addons/l10n_in_gst/report/gst_report.py b/addons/l10n_in_gst/report/gst_report.py index 9561acff..11c9aac8 100644 --- a/addons/l10n_in_gst/report/gst_report.py +++ b/addons/l10n_in_gst/report/gst_report.py @@ -135,7 +135,6 @@ class GSTR1Report(models.AbstractModel): ('gst_invoice', '=', 'b2b'), ('vat', '!=', False)] if post.get('gst_invoice') == 'cdnur': final_inv_domain = common_domain + refund_domain + cdnur_domain - final_invoice_ids = acc_invoice.search(final_inv_domain) for inv in final_invoice_ids: inv_data_list = [] @@ -159,15 +158,17 @@ class GSTR1Report(models.AbstractModel): for line in inv.invoice_line_ids: cess_amount = igst_amount = cgst_amount = sgst_amount = 0.0 - - if line.invoice_line_tax_ids: + if inv.reverse_charge: + tax_lines = line.reverse_invoice_line_tax_ids + else: + tax_lines = line.invoice_line_tax_ids + if tax_lines: price_unit = line.price_unit * ( 1 - (line.discount or 0.0) / 100.0) - taxes = line.invoice_line_tax_ids.compute_all( + taxes = tax_lines.compute_all( price_unit, line.invoice_id.currency_id, line.quantity, line.product_id, line.invoice_id.partner_id)['taxes'] - for tax_data in taxes: tax = acc_tax.browse(tax_data['id']) if tax.tax_group_id.name == 'Cess': @@ -185,7 +186,7 @@ class GSTR1Report(models.AbstractModel): 'amount'] > 0): sgst_amount += tax_data['amount'] - for tax in line.invoice_line_tax_ids: + for tax in tax_lines: rate = 0 if tax.id not in tax_list: if tax.tax_group_id.name == 'IGST' \ @@ -213,7 +214,6 @@ class GSTR1Report(models.AbstractModel): line_data = self._prepare_taxable_line_data( line, inv, igst_amount, cgst_amount, sgst_amount, cess_amount, rate, tax) - if post.get('gst_invoice') in \ ['b2b', 'b2cl', 'b2cs', 'b2bur']: line_data.update({ @@ -241,7 +241,7 @@ class GSTR1Report(models.AbstractModel): if post.get('gst_invoice') == 'b2b': line_data.update({ 'inv_type': 'Regular', - 'reverse_charge': 'N', + 'reverse_charge': 'Y' if inv.reverse_charge else 'N', }) if post.get('gst_invoice') == 'b2bur': supply_type = dict(inv.fields_get( @@ -376,10 +376,14 @@ class GSTR1Report(models.AbstractModel): invoice_domain) for line in hsn_invoice_line_ids: igst_amount = cgst_amount = sgst_amount = cess_amount = 0.0 - if line.invoice_line_tax_ids: + if line.invoice_id.reverse_charge: + tax_lines = line.reverse_invoice_line_tax_ids + else: + tax_lines = line.invoice_line_tax_ids + if tax_lines: price_unit = line.price_unit * ( 1 - (line.discount or 0.0) / 100.0) - taxes = line.invoice_line_tax_ids.compute_all( + taxes = tax_lines.compute_all( price_unit, line.invoice_id.currency_id, line.quantity, line.product_id, line.invoice_id.partner_id)['taxes'] @@ -446,10 +450,11 @@ class GSTR1Report(models.AbstractModel): no_of_recepient = 0 for inv in result: - taxable_value_total += float(inv['taxable_value']) - igst_amount += float(inv['igst']) - sgst_amount += float(inv['sgst']) - cgst_amount += float(inv['cgst']) + if inv.get('reverse_charge') != 'Y': + taxable_value_total += float(inv['taxable_value']) + igst_amount += float(inv['igst']) + sgst_amount += float(inv['sgst']) + cgst_amount += float(inv['cgst']) if post.get('gst_invoice') == 'b2b': if inv['reverse_charge'] == 'N': @@ -473,7 +478,7 @@ class GSTR1Report(models.AbstractModel): invoice_value = 0.0 for invoice_id in invoices_list: ids = self.env['account.invoice'].search( - [('number', '=', invoice_id)]) + [('number', '=', invoice_id), ('reverse_charge', '=', False)]) invoice_value += ids.amount_total summary.update({ "no_of_invoices": no_of_invoices, diff --git a/addons/l10n_in_gst/security/ir.model.access.csv b/addons/l10n_in_gst/security/ir.model.access.csv index f0a601b3..2f7ca89d 100644 --- a/addons/l10n_in_gst/security/ir.model.access.csv +++ b/addons/l10n_in_gst/security/ir.model.access.csv @@ -3,3 +3,4 @@ access_note_issue_reason_all,access_note_issue_reason_all,model_note_issue_reaso access_note_issue_reason,access_note_issue_reason,model_note_issue_reason,,1,0,0,0 access_res_company_b2c_limit_all,access_res_company_b2c_limit_all,model_res_company_b2c_limit,base.group_system,1,1,1,1 access_res_company_b2c_limit,access_res_company_b2c_limit,model_res_company_b2c_limit,,1,0,0,0 +access_reverse_account_invoice_tax,access_reverse_account_invoice_tax,model_reverse_account_invoice_tax,,1,0,0,0 \ No newline at end of file diff --git a/addons/l10n_in_gst/views/account_invoice_view.xml b/addons/l10n_in_gst/views/account_invoice_view.xml index 3ef83780..0a6ed72c 100644 --- a/addons/l10n_in_gst/views/account_invoice_view.xml +++ b/addons/l10n_in_gst/views/account_invoice_view.xml @@ -77,6 +77,9 @@ + + + {'invisible': [('tax_line_ids', '=', [])]} + + + + + + + + @@ -112,5 +123,18 @@ Nature of Transaction + + in_reverse.account.invoice.tax.tree + reverse.account.invoice.tax + + + + + + + + + + \ No newline at end of file diff --git a/addons/l10n_in_gst/views/res_company_view.xml b/addons/l10n_in_gst/views/res_company_view.xml index cff18ac4..5887500b 100644 --- a/addons/l10n_in_gst/views/res_company_view.xml +++ b/addons/l10n_in_gst/views/res_company_view.xml @@ -18,6 +18,9 @@ + + +