diff options
Diffstat (limited to 'addons/l10n_in/models/account_invoice.py')
| -rw-r--r-- | addons/l10n_in/models/account_invoice.py | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/addons/l10n_in/models/account_invoice.py b/addons/l10n_in/models/account_invoice.py new file mode 100644 index 00000000..d755cebd --- /dev/null +++ b/addons/l10n_in/models/account_invoice.py @@ -0,0 +1,129 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, models, _ +from odoo.exceptions import ValidationError + + +class AccountMove(models.Model): + _inherit = "account.move" + + @api.depends('amount_total') + def _compute_amount_total_words(self): + for invoice in self: + invoice.amount_total_words = invoice.currency_id.amount_to_text(invoice.amount_total) + + amount_total_words = fields.Char("Total (In Words)", compute="_compute_amount_total_words") + l10n_in_gst_treatment = fields.Selection([ + ('regular', 'Registered Business - Regular'), + ('composition', 'Registered Business - Composition'), + ('unregistered', 'Unregistered Business'), + ('consumer', 'Consumer'), + ('overseas', 'Overseas'), + ('special_economic_zone', 'Special Economic Zone'), + ('deemed_export', 'Deemed Export') + ], string="GST Treatment", readonly=True, states={'draft': [('readonly', False)]}) + l10n_in_state_id = fields.Many2one('res.country.state', string="Location of supply") + l10n_in_company_country_code = fields.Char(related='company_id.country_id.code', string="Country code") + l10n_in_gstin = fields.Char(string="GSTIN") + # For Export invoice this data is need in GSTR report + l10n_in_shipping_bill_number = fields.Char('Shipping bill number', readonly=True, states={'draft': [('readonly', False)]}) + l10n_in_shipping_bill_date = fields.Date('Shipping bill date', readonly=True, states={'draft': [('readonly', False)]}) + l10n_in_shipping_port_code_id = fields.Many2one('l10n_in.port.code', 'Port code', states={'draft': [('readonly', False)]}) + l10n_in_reseller_partner_id = fields.Many2one('res.partner', 'Reseller', domain=[('vat', '!=', False)], help="Only Registered Reseller", readonly=True, states={'draft': [('readonly', False)]}) + + @api.onchange('partner_id') + def _onchange_partner_id(self): + """Use journal type to define document type because not miss state in any entry including POS entry""" + if self.l10n_in_company_country_code == 'IN': + self.l10n_in_gst_treatment = self.partner_id.l10n_in_gst_treatment + return super()._onchange_partner_id() + + @api.model + def _l10n_in_get_indian_state(self, partner): + """In tax return filing, If customer is not Indian in that case place of supply is must set to Other Territory. + So we set Other Territory in l10n_in_state_id when customer(partner) is not Indian + Also we raise if state is not set in Indian customer. + State is big role under GST because tax type is depend on.for more information check this https://www.cbic.gov.in/resources//htdocs-cbec/gst/Integrated%20goods%20&%20Services.pdf""" + if partner.country_id and partner.country_id.code == 'IN' and not partner.state_id: + raise ValidationError(_("State is missing from address in '%s'. First set state after post this invoice again.", partner.name)) + elif partner.country_id and partner.country_id.code != 'IN': + return self.env.ref('l10n_in.state_in_ot') + return partner.state_id + + + @api.model + def _get_tax_grouping_key_from_tax_line(self, tax_line): + # OVERRIDE to group taxes also by product. + res = super()._get_tax_grouping_key_from_tax_line(tax_line) + if tax_line.move_id.journal_id.company_id.country_id.code == 'IN': + res['product_id'] = tax_line.product_id.id + res['product_uom_id'] = tax_line.product_uom_id + return res + + @api.model + def _get_tax_grouping_key_from_base_line(self, base_line, tax_vals): + # OVERRIDE to group taxes also by product. + res = super()._get_tax_grouping_key_from_base_line(base_line, tax_vals) + if base_line.move_id.journal_id.company_id.country_id.code == 'IN': + res['product_id'] = base_line.product_id.id + res['product_uom_id'] = base_line.product_uom_id + return res + + @api.model + def _get_tax_key_for_group_add_base(self, line): + # DEPRECATED: TO BE REMOVED IN MASTER + tax_key = super(AccountMove, self)._get_tax_key_for_group_add_base(line) + + tax_key += [ + line.product_id.id, + line.product_uom_id, + ] + return tax_key + + def _l10n_in_get_shipping_partner(self): + """Overwrite in sale""" + self.ensure_one() + return self.partner_id + + @api.model + def _l10n_in_get_shipping_partner_gstin(self, shipping_partner): + """Overwrite in sale""" + return shipping_partner.vat + + def _post(self, soft=True): + """Use journal type to define document type because not miss state in any entry including POS entry""" + posted = super()._post(soft) + gst_treatment_name_mapping = {k: v for k, v in + self._fields['l10n_in_gst_treatment']._description_selection(self.env)} + for move in posted.filtered(lambda m: m.l10n_in_company_country_code == 'IN'): + """Check state is set in company/sub-unit""" + company_unit_partner = move.journal_id.l10n_in_gstin_partner_id or move.journal_id.company_id + if not company_unit_partner.state_id: + raise ValidationError(_( + "State is missing from your company/unit %(company_name)s (%(company_id)s).\nFirst set state in your company/unit.", + company_name=company_unit_partner.name, + company_id=company_unit_partner.id + )) + elif self.journal_id.type == 'purchase': + move.l10n_in_state_id = company_unit_partner.state_id + + shipping_partner = move._l10n_in_get_shipping_partner() + # In case of shipping address does not have GSTN then also check customer(partner_id) GSTN + # This happens when Bill-to Ship-to transaction where shipping(Ship-to) address is unregistered and customer(Bill-to) is registred. + move.l10n_in_gstin = move._l10n_in_get_shipping_partner_gstin(shipping_partner) or move.partner_id.vat + if not move.l10n_in_gstin and move.l10n_in_gst_treatment in ['regular', 'composition', 'special_economic_zone', 'deemed_export']: + raise ValidationError(_( + "Partner %(partner_name)s (%(partner_id)s) GSTIN is required under GST Treatment %(name)s", + partner_name=shipping_partner.name, + partner_id=shipping_partner.id, + name=gst_treatment_name_mapping.get(move.l10n_in_gst_treatment) + )) + if self.journal_id.type == 'sale': + move.l10n_in_state_id = self._l10n_in_get_indian_state(shipping_partner) + if not move.l10n_in_state_id: + move.l10n_in_state_id = self._l10n_in_get_indian_state(move.partner_id) + #still state is not set then assumed that transaction is local like PoS so set state of company unit + if not move.l10n_in_state_id: + move.l10n_in_state_id = company_unit_partner.state_id + return posted |
