# -*- coding: utf-8 -*- from odoo import models, api, fields, _ from odoo.exceptions import UserError, ValidationError class AccountMove(models.Model): _inherit = 'account.move' rk_payment_journal_id = fields.Many2one( 'account.journal', string='RK Payment Journal', help='The bank/cash journal used for this Hubungan RK process' ) def _get_last_sequence(self, relaxed=False, with_prefix=None): self.ensure_one() if not self.rk_payment_journal_id: return super()._get_last_sequence(relaxed=relaxed, with_prefix=with_prefix) if self._sequence_field not in self._fields or not self._fields[self._sequence_field].store: raise ValidationError(_('%s is not a stored field', self._sequence_field)) where_string, param = self._get_last_sequence_domain(relaxed) if self._origin.id: where_string += " AND id != %(id)s " param['id'] = self._origin.id prefix_base = f"{self.journal_id.code}-{self.rk_payment_journal_id.code}" if with_prefix is not None: where_string += " AND sequence_prefix = %(with_prefix)s " param['with_prefix'] = with_prefix else: where_string += " AND sequence_prefix LIKE %(prefix_like)s " param['prefix_like'] = f"{prefix_base}/%" query = f""" SELECT {self._sequence_field} FROM {self._table} {where_string} AND sequence_prefix = (SELECT sequence_prefix FROM {self._table} {where_string} ORDER BY id DESC LIMIT 1) ORDER BY sequence_number DESC LIMIT 1 """ self.flush_model([self._sequence_field, 'sequence_number', 'sequence_prefix']) self.env.cr.execute(query, param) return (self.env.cr.fetchone() or [None])[0] def _get_starting_sequence(self): self.ensure_one() if self.rk_payment_journal_id: move_date = self.date or self.invoice_date or fields.Date.context_today(self) year_part = "%04d" % move_date.year prefix_base = f"{self.journal_id.code}-{self.rk_payment_journal_id.code}" return f"{prefix_base}/{year_part}/{move_date.month:02d}/0000" return super()._get_starting_sequence() def action_post(self): res = super().action_post() # 1. Handle Centralized entries in Parent when payment moves are posted for move in self: payments = move.payment_ids or move.origin_payment_id if not payments: continue centralized_payments = payments.filtered( lambda p: p.journal_id.sudo().is_centralized and p.company_id != p.journal_id.sudo().parent_company_id ) for payment in centralized_payments: journal_sudo = payment.journal_id.sudo() parent_company = journal_sudo.parent_company_id parent_journal = journal_sudo.parent_journal_id parent_rk_account = journal_sudo.parent_intercompany_account_id if not journal_sudo.branch_intercompany_account_id: raise UserError(_("Please configure the Branch Inter-company Account on journal %s", payment.journal_id.name)) if not parent_journal or not parent_rk_account: raise UserError(_("Please configure the Parent Journal and RK Account on journal %s", payment.journal_id.name)) parent_journal_sudo = parent_journal.sudo() parent_rk_account_sudo = parent_rk_account.sudo() print(f">>> DEBUG: Centralized Payment for {payment.name}") print(f" Company: {payment.company_id.id}, Parent Co: {parent_company.id}") print(f" Parent Journal: {parent_journal_sudo.name} (ID: {parent_journal_sudo.id})") print(f" Parent RK: {parent_rk_account_sudo.code} (ID: {parent_rk_account_sudo.id})") # Calculate currency-adjusted amount for the parent company parent_currency = parent_company.currency_id if payment.currency_id != parent_currency: amount_parent_curr = payment.currency_id._convert( payment.amount, parent_currency, parent_company, payment.date ) else: amount_parent_curr = payment.amount # Create the mirroring entry in Parent using sudo parent_move = self.env['account.move'].sudo().with_company(parent_company).create({ 'move_type': 'entry', 'date': payment.date, 'company_id': parent_company.id, 'journal_id': parent_journal.id, 'partner_id': payment.company_id.partner_id.id, 'currency_id': parent_currency.id, 'ref': f"Centralized Payment: {payment.name} ({payment.company_id.name})", 'line_ids': [ (0, 0, { 'name': payment.memo or f"Centralized Payment: {payment.name}", 'account_id': parent_rk_account.id, 'debit': amount_parent_curr, 'credit': 0.0, 'partner_id': payment.company_id.partner_id.id, 'company_id': parent_company.id, 'currency_id': payment.currency_id.id, 'amount_currency': payment.amount, 'display_type': 'product', }), (0, 0, { 'name': payment.memo or f"Centralized Payment: {payment.name}", 'account_id': parent_journal_sudo.default_account_id.id, 'debit': 0.0, 'credit': amount_parent_curr, 'partner_id': payment.company_id.partner_id.id, 'company_id': parent_company.id, 'currency_id': payment.currency_id.id, 'amount_currency': -payment.amount, 'display_type': 'product', }), ] }) parent_move.sudo().action_post() print(f" Parent Move Posted: {parent_move.name}") return res class AccountMoveLine(models.Model): _inherit = 'account.move.line' @api.model def _search_account_id(self, operator, value): res = super()._search_account_id(operator, value) if res and isinstance(res, list) and len(res) == 1: term = res[0] if len(term) == 3 and term[0] == 'account_id' and term[1] in ('in', 'not in') and isinstance(term[2], (list, tuple, set)): resolved_ids = list(term[2]) reconcile_accounts = self.env['account.account'].sudo().browse(resolved_ids).filtered('reconcile') if reconcile_accounts: cash_accounts = self.env['account.account'].sudo().search([('account_type', '=', 'asset_cash')]) if cash_accounts: if term[1] == 'in': res = [ '|', ('account_id', 'in', tuple(reconcile_accounts.ids)), '&', '&', ('account_id', 'in', tuple(cash_accounts.ids)), ('journal_id.type', '=', 'cash'), ('journal_id.company_id', '=', self.env.company.id) ] elif term[1] == 'not in': res = [ '&', ('account_id', 'not in', tuple(reconcile_accounts.ids)), '|', '|', ('account_id', 'not in', tuple(cash_accounts.ids)), ('journal_id.type', '!=', 'cash'), ('journal_id.company_id', '!=', self.env.company.id) ] return res def _related_analytic_distribution(self): res = super()._related_analytic_distribution() if res: return self.env['analytic.mixin']._clean_analytic_distribution(res) return res