1
0
forked from Mapan/odoo17e
odoo17e-kedaikipas58/addons/account_inter_company_rules/models/account_move.py
2024-12-10 09:04:09 +07:00

153 lines
7.1 KiB
Python

# -*- coding: utf-8 -*-
from odoo import fields, models, _
class AccountMove(models.Model):
_inherit = 'account.move'
auto_generated = fields.Boolean(string='Auto Generated Document', copy=False, default=False)
auto_invoice_id = fields.Many2one('account.move', string='Source Invoice', readonly=True, copy=False, index='btree_not_null')
def _post(self, soft=True):
# OVERRIDE to generate cross invoice based on company rules.
invoices_map = {}
posted = super()._post(soft)
for invoice in posted.filtered(lambda move: move.is_invoice()):
company_sudo = self.env['res.company'].sudo()._find_company_from_partner(invoice.partner_id.id)
if company_sudo and company_sudo.rule_type == 'invoice_and_refund' and not invoice.auto_generated:
invoices_map.setdefault(company_sudo, self.env['account.move'])
invoices_map[company_sudo] += invoice
for company_sudo, invoices in invoices_map.items():
context = dict(self.env.context, default_company_id=company_sudo.id)
context.pop('default_journal_id', None)
invoices.with_user(company_sudo.intercompany_user_id.id).with_context(context).with_company(company_sudo.id)._inter_company_create_invoices()
return posted
def _inter_company_create_invoices(self):
''' Create cross company invoices.
:return: The newly created invoices.
'''
# Prepare invoice values.
invoices_vals_per_type = {}
inverse_types = {
'in_invoice': 'out_invoice',
'in_refund': 'out_refund',
'out_invoice': 'in_invoice',
'out_refund': 'in_refund',
}
for inv in self:
invoice_vals = inv._inter_company_prepare_invoice_data(inverse_types[inv.move_type])
invoice_vals['invoice_line_ids'] = []
for line in inv.invoice_line_ids:
invoice_vals['invoice_line_ids'].append((0, 0, line._inter_company_prepare_invoice_line_data()))
inv_new = inv.with_context(default_move_type=invoice_vals['move_type']).new(invoice_vals)
for line in inv_new.invoice_line_ids.filtered(lambda l: l.display_type not in ('line_note', 'line_section')):
# We need to adapt the taxes following the fiscal position, but we must keep the
# price unit.
price_unit = line.price_unit
line.tax_ids = line._get_computed_taxes()
line.price_unit = price_unit
invoice_vals = inv_new._convert_to_write(inv_new._cache)
invoice_vals.pop('line_ids', None)
invoice_vals['origin_invoice'] = inv
invoices_vals_per_type.setdefault(invoice_vals['move_type'], [])
invoices_vals_per_type[invoice_vals['move_type']].append(invoice_vals)
# Create invoices.
moves = self.env['account.move']
for invoice_type, invoices_vals in invoices_vals_per_type.items():
for invoice in invoices_vals:
origin_invoice = invoice['origin_invoice']
invoice.pop('origin_invoice')
msg = _("Automatically generated from %(origin)s of company %(company)s.", origin=origin_invoice.name, company=origin_invoice.company_id.name)
am = self.with_context(default_type=invoice_type).create(invoice)
am.message_post(body=msg)
moves += am
return moves
def _inter_company_prepare_invoice_data(self, invoice_type):
r''' Get values to create the invoice.
/!\ Doesn't care about lines, see '_inter_company_prepare_invoice_line_data'.
:return: Python dictionary of values.
'''
self.ensure_one()
# We need the fiscal position in the company (already in context) we are creating the
# invoice, not the fiscal position of the current invoice (self.company)
delivery_partner_id = self.company_id.partner_id.address_get(['delivery'])['delivery']
delivery_partner = self.env['res.partner'].browse(delivery_partner_id)
fiscal_position_id = self.env['account.fiscal.position']._get_fiscal_position(
self.company_id.partner_id, delivery=delivery_partner
)
return {
'move_type': invoice_type,
'ref': self.ref,
'partner_id': self.company_id.partner_id.id,
'currency_id': self.currency_id.id,
'auto_generated': True,
'auto_invoice_id': self.id,
'company_id': self.env.company.id,
'invoice_date': self.invoice_date,
'invoice_date_due': self.invoice_date_due,
'payment_reference': self.payment_reference,
'invoice_origin': _('%s Invoice: %s', self.company_id.name, self.name),
'fiscal_position_id': fiscal_position_id,
}
class AccountMoveLine(models.Model):
_inherit = 'account.move.line'
def _inter_company_prepare_invoice_line_data(self):
''' Get values to create the invoice line.
We prioritize the analytic distribution in the following order:
- Default Analytic Distribution model specific to Company B
- Analytic Distribution set for the line in Company A's document if available to Company B
:return: Python dictionary of values.
'''
self.ensure_one()
vals = {
'display_type': self.display_type,
'sequence': self.sequence,
'name': self.name,
'quantity': self.quantity,
'discount': self.discount,
'price_unit': self.price_unit,
}
if not self.product_id.company_id:
vals['product_id'] = self.product_id.id
vals['product_uom_id'] = self.product_uom_id.id
company_b = self.env['res.company']._find_company_from_partner(self.move_id.partner_id.id)
company_b_default_distribution = self.env['account.analytic.distribution.model']._get_distribution({
"product_id": self.product_id.id,
"product_categ_id": self.product_id.categ_id.id,
"partner_id": self.partner_id.id,
"partner_category_id": self.partner_id.category_id.ids,
"account_prefix": self.account_id.code,
"company_id": company_b.id,
})
analytic_distribution = {}
if self.analytic_distribution:
account_ids = self._get_analytic_account_ids()
accounts_with_company = self.env['account.analytic.account'].browse(account_ids).filtered('company_id')
for key, val in self.analytic_distribution.items():
is_company_account = False
for account_id in key.split(','):
if int(account_id) in accounts_with_company.ids:
is_company_account = True
break
if not is_company_account:
analytic_distribution[key] = val
if company_b_default_distribution or analytic_distribution:
vals['analytic_distribution'] = dict(company_b_default_distribution, **analytic_distribution)
return vals