flectra/addons/l10n_in_gst/models/account_invoice.py

242 lines
11 KiB
Python

# Part of Flectra See LICENSE file for full copyright and licensing details.
from flectra import api, fields, models, _
from flectra.exceptions import ValidationError
class AccountInvoice(models.Model):
_inherit = 'account.invoice'
gst_invoice = fields.Selection(
[('b2b', 'B2B'), ('b2cl', 'B2CL'), ('b2cs', 'B2CS'),
('b2bur', 'B2BUR')], string='GST Invoice',
help='B2B Supplies: Taxable supplies made to other registered '
'taxpayers.\n\nB2C Large [For outward supplies]: Taxable '
'outward '
'supplies to consumers where\na)The place of supply is '
'outside the state where the supplier is registered and '
'b)The '
'total invoice value is more than the limit defined in '
'company B2C lines.\ne.g., If in B2C line, B2CL limit is '
'set to Rs 2,50,000 and invoice is of amount Rs 3,00,000 then'
'invoice '
'will be considered as of type B2CL.\n\nB2C Small '
'[For outward supplies]: Supplies made to consumers and '
'unregistered persons of the following nature\n'
'a) Intra-State: any value b) Inter-State: Total invoice '
'value is'
' less than the limit defined in company B2C lines.\n'
'e.g., If in B2C line, B2CS limit is set to Rs 2,50,000 '
'(for period 01-01-2017 to 31-12-2017) for inter state '
'supply '
'and invoice value is Rs 2,00,000 then invoice will be '
'considered as of type B2CS.\n\nB2BUR [For inward supplies]: '
'Inward supplies received from an unregistered supplier \n\n',
copy=False)
e_commerce_partner_id = fields.Many2one('res.partner',
string='E-Commerce Partner')
vat = fields.Char(string='GSTIN',
help='Goods and Services Taxpayer Identification '
'Number', size=15, copy=False)
gst_type = fields.Selection(
[('regular', 'Regular'), ('unregistered', 'Unregistered'),
('composite', 'Composite'), ('volunteer', 'Volunteer')],
string='GST Type', copy=False)
partner_location = fields.Selection(
[('inter_state', 'Inter State'), ('intra_state', 'Intra State'),
('inter_country', 'Inter Country')],
related='partner_id.partner_location', string="Partner Location")
fiscal_position_id = fields.Many2one('account.fiscal.position',
string='Nature of Transaction',
oldname='fiscal_position',
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):
super(AccountInvoice, self)._onchange_partner_id()
if self.partner_id and not self.partner_id.partner_location:
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. """
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):
""" Do not apply taxes if company has been registered under
composition scheme. """
for invoice in self:
if invoice.type in ('out_invoice',
'out_refund') and \
invoice.company_id.gst_type == 'composite':
for line in invoice.invoice_line_ids:
line.invoice_line_tax_ids = [(6, 0, [])]
line.invoice_id._onchange_invoice_line_ids()
return super(AccountInvoice, self).action_move_create()
@api.multi
def invoice_validate(self):
""" Apply GST invoice type at the time of invoice validation. """
for invoice in self:
partner_location = self.partner_id.partner_location
if invoice.partner_id.vat:
invoice.write({
'vat': invoice.partner_id.vat,
'gst_type': invoice.partner_id.gst_type,
'gst_invoice': 'b2b'
})
elif invoice.type == 'out_invoice' and partner_location:
b2c_limit = self.env['res.company.b2c.limit'].search(
[('date_from', '<=', invoice.date_invoice),
('date_to', '>=', invoice.date_invoice),
('company_id', '=', invoice.company_id.id)])
if not b2c_limit:
raise ValidationError(_('Please define B2C limit line in '
'company for current period!'))
if partner_location == 'inter_state' and \
invoice.amount_total > b2c_limit.b2cl_limit:
invoice.write({'gst_invoice': 'b2cl'})
if partner_location == 'intra_state' or partner_location == \
'inter_state' and invoice.amount_total < \
b2c_limit.b2cs_limit:
invoice.write({'gst_invoice': 'b2cs'})
elif invoice.type == 'in_invoice' and partner_location and \
partner_location != 'inter_country':
invoice.write({'gst_invoice': 'b2bur'})
return super(AccountInvoice, self).invoice_validate()
@api.model
def _prepare_refund(self, invoice, date_invoice=None, date=None,
description=None, journal_id=None):
""" Refund invoice creation, update value of GST Invoice from
base invoice. """
result = super(AccountInvoice, self)._prepare_refund(
invoice, date_invoice=date_invoice, date=date,
description=description, journal_id=journal_id)
if result.get('refund_invoice_id'):
invoice = self.env['account.invoice'].browse(
result.get('refund_invoice_id'))
result.update({
'gst_invoice': invoice.gst_invoice, 'vat': invoice.vat,
'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)