account_shared_bank_cash_au.../models/account_journal.py

211 lines
9.4 KiB
Python

# -*- coding: utf-8 -*-
import logging
import pytz
from datetime import datetime, timedelta
from odoo import models, fields, api, _
from odoo.exceptions import UserError
_logger = logging.getLogger(__name__)
class AccountJournal(models.Model):
_inherit = 'account.journal'
@api.model
def _cron_create_cash_intercompany_entries(self, target_date=None, journal_ids=None):
"""Cron action to automatically generate cash centralization entries.
Runs daily at 12:00 PM WIB (05:00 AM UTC) to process the previous day's net cash movements.
"""
# Determine the target date (previous day in WIB by default)
if not target_date:
jakarta_tz = pytz.timezone('Asia/Jakarta')
now_jakarta = datetime.now(jakarta_tz)
prev_day = (now_jakarta - timedelta(days=1)).date()
elif isinstance(target_date, str):
prev_day = fields.Date.from_string(target_date)
else:
prev_day = target_date
_logger.info("Starting cash intercompany centralization for date %s", prev_day)
# Search for all cash journals that have centralization configured
domain = [
('type', '=', 'cash'),
('is_centralized', '=', True)
]
if journal_ids:
domain.append(('id', 'in', journal_ids))
journals = self.sudo().search(domain)
results = []
for journal in journals:
# Check basic configuration requirements
parent_company = journal.parent_company_id
parent_journal = journal.parent_journal_id
branch_rk_account = journal.branch_intercompany_account_id
parent_rk_account = journal.parent_intercompany_account_id
if not parent_company or not parent_journal or not branch_rk_account or not parent_rk_account:
msg = _("Centralization settings are incomplete (Parent Company, Parent Journal, or RK accounts not configured).")
_logger.warning("Skipping cash journal %s (%s): %s", journal.name, journal.company_id.name, msg)
results.append((journal.id, 'incomplete', msg))
continue
# Ensure default cash account is present
branch_cash_account = journal.default_account_id
if not branch_cash_account:
msg = _("Journal has no default account configured.")
_logger.warning("Skipping cash journal %s (%s): %s", journal.name, journal.company_id.name, msg)
results.append((journal.id, 'no_account', msg))
continue
# Check for existing intercompany transfer entries for this day to prevent duplication
existing_move = self.env['account.move'].sudo().search([
('journal_id', '=', journal.id),
('date', '=', prev_day),
('is_cash_intercompany_transfer', '=', True),
('state', '!=', 'cancel')
], limit=1)
if existing_move:
msg = _("Centralization already run for this date. (Move: %s)") % existing_move.name
_logger.info("Skipping cash journal %s (%s): %s", journal.name, journal.company_id.name, msg)
results.append((journal.id, 'already_run', msg))
continue
# Find all posted journal items on the branch cash account for the target date,
# excluding centralization transfers we generate.
lines = self.env['account.move.line'].sudo().search([
('company_id', '=', journal.company_id.id),
('account_id', '=', branch_cash_account.id),
('date', '=', prev_day),
('parent_state', '=', 'posted'),
('move_id.is_cash_intercompany_transfer', '=', False)
])
# Calculate net movement (debit - credit)
debit_sum = sum(lines.mapped('debit'))
credit_sum = sum(lines.mapped('credit'))
net_balance = debit_sum - credit_sum
_logger.info(
"Journal %s (%s) net movement on %s: Debits=%s, Credits=%s, Net=%s",
journal.name, journal.company_id.name, prev_day, debit_sum, credit_sum, net_balance
)
if net_balance <= 0.0:
msg = _("No positive net cash movement (Net Balance: %s).") % net_balance
_logger.info("Skipping journal %s on %s: %s", journal.name, prev_day, msg)
results.append((journal.id, 'no_balance', msg))
continue
# Identify the parent cash account ( Kas Besar Hasil Penjualan - 111103)
# Search by code 111103 with the parent company's context
parent_cash_account = self.env['account.account'].sudo().with_company(parent_company).search([
('code', '=', '111103'),
('company_ids', 'in', [parent_company.id])
], limit=1)
if not parent_cash_account:
parent_cash_account = parent_journal.default_account_id
if not parent_cash_account:
msg = _("Parent cash account (111103 or default account of parent journal) not found in company %s.") % parent_company.name
_logger.error("Skipping journal %s: %s", journal.name, msg)
results.append((journal.id, 'no_parent_account', msg))
continue
# Handle currency conversion if parent and branch currencies differ
parent_currency = parent_company.currency_id
branch_currency = journal.company_id.currency_id
if branch_currency != parent_currency:
amount_parent_curr = branch_currency._convert(
net_balance, parent_currency, parent_company, prev_day
)
else:
amount_parent_curr = net_balance
# 1. Create the Branch company journal entry
branch_line_ids = [
(0, 0, {
'name': _("Cash Centralization - %s") % prev_day,
'account_id': branch_rk_account.id,
'debit': net_balance,
'credit': 0.0,
'company_id': journal.company_id.id,
'display_type': 'product',
}),
(0, 0, {
'name': _("Cash Centralization - %s") % prev_day,
'account_id': branch_cash_account.id,
'debit': 0.0,
'credit': net_balance,
'company_id': journal.company_id.id,
'display_type': 'product',
})
]
# 2. Create the Parent company journal entry
parent_line_ids = [
(0, 0, {
'name': _("Cash Centralization: %s - %s") % (journal.company_id.name, prev_day),
'account_id': parent_cash_account.id,
'debit': amount_parent_curr,
'credit': 0.0,
'partner_id': journal.company_id.partner_id.id,
'company_id': parent_company.id,
'display_type': 'product',
}),
(0, 0, {
'name': _("Cash Centralization: %s - %s") % (journal.company_id.name, prev_day),
'account_id': parent_rk_account.id,
'debit': 0.0,
'credit': amount_parent_curr,
'partner_id': journal.company_id.partner_id.id,
'company_id': parent_company.id,
'display_type': 'product',
})
]
try:
# Create and post branch entry
branch_move = self.env['account.move'].sudo().with_company(journal.company_id).create({
'move_type': 'entry',
'date': prev_day,
'company_id': journal.company_id.id,
'journal_id': journal.id,
'ref': f"Cash Centralization - {prev_day}",
'is_cash_intercompany_transfer': True,
'line_ids': branch_line_ids,
})
branch_move.action_post()
# Create and post parent entry
parent_move = self.env['account.move'].sudo().with_company(parent_company).create({
'move_type': 'entry',
'date': prev_day,
'company_id': parent_company.id,
'journal_id': parent_journal.id,
'partner_id': journal.company_id.partner_id.id,
'ref': f"Cash Centralization - {prev_day} ({journal.company_id.name})",
'is_cash_intercompany_transfer': True,
'line_ids': parent_line_ids,
})
parent_move.action_post()
msg = _("Successfully created branch entry %s and parent entry %s.") % (branch_move.name, parent_move.name)
_logger.info("Successfully centralized cash for %s: %s", journal.name, msg)
results.append((journal.id, 'success', msg))
except Exception as e:
msg = str(e)
_logger.error(
"Failed to create cash centralization entries for journal %s on %s: %s",
journal.name, prev_day, msg
)
results.append((journal.id, 'error', msg))
return results