131 lines
4.6 KiB
Python
131 lines
4.6 KiB
Python
import logging
|
|
from odoo import fields
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
def get_close_checklist(env, params):
|
|
from .bank_reconciliation import get_unreconciled_bank_lines
|
|
from .journal_review import find_draft_entries, find_sequence_gaps
|
|
from .hst_management import calculate_hst_balance
|
|
|
|
period = params.get('period', str(fields.Date.today())[:7])
|
|
date_from = f'{period}-01'
|
|
import calendar
|
|
year, month = int(period[:4]), int(period[5:7])
|
|
last_day = calendar.monthrange(year, month)[1]
|
|
date_to = f'{period}-{last_day:02d}'
|
|
|
|
p = {'date_from': date_from, 'date_to': date_to}
|
|
|
|
bank = get_unreconciled_bank_lines(env, p)
|
|
drafts = find_draft_entries(env, {'min_age_days': '0'})
|
|
gaps = find_sequence_gaps(env, p)
|
|
hst = calculate_hst_balance(env, p)
|
|
|
|
checklist = [
|
|
{'item': 'Bank Reconciliation', 'status': 'ok' if bank['count'] == 0 else 'attention', 'detail': f"{bank['count']} unreconciled lines"},
|
|
{'item': 'Draft Entries', 'status': 'ok' if drafts['count'] == 0 else 'attention', 'detail': f"{drafts['count']} draft entries"},
|
|
{'item': 'Sequence Gaps', 'status': 'ok' if gaps['count'] == 0 else 'warning', 'detail': f"{gaps['count']} gaps found"},
|
|
{'item': 'HST Balance', 'status': 'info', 'detail': f"Net HST: ${hst['net_hst']:.2f}"},
|
|
]
|
|
return {'period': period, 'checklist': checklist}
|
|
|
|
|
|
def get_unreconciled_counts(env, params):
|
|
accounts = env['account.account'].search([
|
|
('reconcile', '=', True),
|
|
('company_ids', 'in', env.company.id),
|
|
])
|
|
result = []
|
|
for acct in accounts:
|
|
count = env['account.move.line'].search_count([
|
|
('account_id', '=', acct.id),
|
|
('reconciled', '=', False),
|
|
('parent_state', '=', 'posted'),
|
|
])
|
|
if count > 0:
|
|
result.append({
|
|
'account_id': acct.id,
|
|
'code': acct.code,
|
|
'name': acct.name,
|
|
'unreconciled_count': count,
|
|
})
|
|
return {'accounts': sorted(result, key=lambda x: -x['unreconciled_count'])}
|
|
|
|
|
|
def find_entries_in_locked_period(env, params):
|
|
company = env.company
|
|
lock_date = company.fiscalyear_lock_date
|
|
if not lock_date:
|
|
return {'status': 'no_lock_date', 'entries': []}
|
|
entries = env['account.move'].search([
|
|
('date', '<=', lock_date),
|
|
('state', '=', 'draft'),
|
|
('company_id', '=', company.id),
|
|
])
|
|
return {
|
|
'lock_date': str(lock_date),
|
|
'count': len(entries),
|
|
'entries': [{'id': e.id, 'name': e.name, 'date': str(e.date)} for e in entries[:20]],
|
|
}
|
|
|
|
|
|
def get_accrual_status(env, params):
|
|
accrual_codes = params.get('account_codes', ['2100', '2110', '2120'])
|
|
result = []
|
|
for code in accrual_codes:
|
|
accounts = env['account.account'].search([
|
|
('code', '=like', f'{code}%'),
|
|
('company_ids', 'in', env.company.id),
|
|
])
|
|
for acct in accounts:
|
|
balance = sum(env['account.move.line'].search([
|
|
('account_id', '=', acct.id),
|
|
('parent_state', '=', 'posted'),
|
|
]).mapped('balance'))
|
|
result.append({'code': acct.code, 'name': acct.name, 'balance': balance})
|
|
return {'accruals': result}
|
|
|
|
|
|
def run_hash_integrity_check(env, params):
|
|
try:
|
|
result = env.company._check_hash_integrity()
|
|
return {
|
|
'status': 'completed',
|
|
'results': result.get('results', []),
|
|
'printing_date': result.get('printing_date', ''),
|
|
}
|
|
except Exception as e:
|
|
return {'error': str(e)}
|
|
|
|
|
|
def get_period_summary(env, params):
|
|
date_from = params.get('date_from')
|
|
date_to = params.get('date_to')
|
|
try:
|
|
report = env.ref('account_reports.trial_balance_report')
|
|
except Exception:
|
|
report = env.ref('account.trial_balance_report', raise_if_not_found=False)
|
|
if not report:
|
|
return {'error': 'Trial balance report not found'}
|
|
options = report.get_options({'date': {'date_from': date_from, 'date_to': date_to}})
|
|
lines = report._get_lines(options)
|
|
return {
|
|
'period': f'{date_from} to {date_to}',
|
|
'lines': [{
|
|
'name': l.get('name', ''),
|
|
'columns': [c.get('no_format', c.get('name', '')) for c in l.get('columns', [])],
|
|
} for l in lines[:100]],
|
|
}
|
|
|
|
|
|
TOOLS = {
|
|
'get_close_checklist': get_close_checklist,
|
|
'get_unreconciled_counts': get_unreconciled_counts,
|
|
'find_entries_in_locked_period': find_entries_in_locked_period,
|
|
'get_accrual_status': get_accrual_status,
|
|
'run_hash_integrity_check': run_hash_integrity_check,
|
|
'get_period_summary': get_period_summary,
|
|
}
|