114 lines
3.9 KiB
Python
114 lines
3.9 KiB
Python
import logging
|
|
from odoo import fields
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
def get_stock_valuation(env, params):
|
|
accounts = env['account.account'].search([
|
|
('code', '=like', '1069%'),
|
|
('company_id', '=', env.company.id),
|
|
])
|
|
result = []
|
|
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 {'accounts': result, 'total': sum(r['balance'] for r in result)}
|
|
|
|
|
|
def get_price_differences(env, params):
|
|
accounts = env['account.account'].search([
|
|
('code', '=like', '5010%'),
|
|
('company_id', '=', env.company.id),
|
|
])
|
|
domain = [
|
|
('account_id', 'in', accounts.ids),
|
|
('parent_state', '=', 'posted'),
|
|
('company_id', '=', env.company.id),
|
|
]
|
|
if params.get('date_from'):
|
|
domain.append(('date', '>=', params['date_from']))
|
|
if params.get('date_to'):
|
|
domain.append(('date', '<=', params['date_to']))
|
|
lines = env['account.move.line'].search(domain, order='date desc', limit=50)
|
|
return {
|
|
'total': sum(l.balance for l in lines),
|
|
'entries': [{
|
|
'id': l.id, 'date': str(l.date),
|
|
'move': l.move_id.name, 'amount': l.balance,
|
|
'partner': l.partner_id.name if l.partner_id else '',
|
|
} for l in lines],
|
|
}
|
|
|
|
|
|
def get_cogs_ratio_by_category(env, params):
|
|
date_from = params.get('date_from')
|
|
date_to = params.get('date_to')
|
|
base_domain = [
|
|
('parent_state', '=', 'posted'),
|
|
('company_id', '=', env.company.id),
|
|
]
|
|
if date_from:
|
|
base_domain.append(('date', '>=', date_from))
|
|
if date_to:
|
|
base_domain.append(('date', '<=', date_to))
|
|
|
|
revenue_lines = env['account.move.line'].search(
|
|
base_domain + [('account_id.account_type', '=', 'income')]
|
|
)
|
|
cogs_lines = env['account.move.line'].search(
|
|
base_domain + [('account_id.account_type', '=', 'expense_direct_cost')]
|
|
)
|
|
revenue = abs(sum(l.balance for l in revenue_lines))
|
|
cogs = abs(sum(l.balance for l in cogs_lines))
|
|
ratio = (cogs / revenue * 100) if revenue else 0
|
|
return {'revenue': revenue, 'cogs': cogs, 'ratio_pct': round(ratio, 2)}
|
|
|
|
|
|
def find_unusual_adjustments(env, params):
|
|
threshold = float(params.get('threshold', 1000))
|
|
domain = [
|
|
('parent_state', '=', 'posted'),
|
|
('company_id', '=', env.company.id),
|
|
('account_id.account_type', '=', 'expense_direct_cost'),
|
|
]
|
|
lines = env['account.move.line'].search(domain)
|
|
unusual = lines.filtered(lambda l: abs(l.balance) > threshold)
|
|
return {
|
|
'count': len(unusual),
|
|
'adjustments': [{
|
|
'id': l.id, 'date': str(l.date), 'move': l.move_id.name,
|
|
'amount': l.balance, 'name': l.name or '',
|
|
} for l in unusual[:20]],
|
|
}
|
|
|
|
|
|
def get_inventory_turnover(env, params):
|
|
from .reporting import get_profit_loss
|
|
pl = get_profit_loss(env, params)
|
|
stock = get_stock_valuation(env, params)
|
|
avg_inventory = stock.get('total', 0)
|
|
cogs = 0
|
|
for line in pl.get('lines', []):
|
|
if 'cost' in line.get('name', '').lower():
|
|
cols = line.get('columns', [])
|
|
if cols:
|
|
try:
|
|
cogs = float(cols[0])
|
|
except (ValueError, TypeError):
|
|
pass
|
|
turnover = (cogs / avg_inventory) if avg_inventory else 0
|
|
return {'cogs': cogs, 'avg_inventory': avg_inventory, 'turnover': round(turnover, 2)}
|
|
|
|
|
|
TOOLS = {
|
|
'get_stock_valuation': get_stock_valuation,
|
|
'get_price_differences': get_price_differences,
|
|
'get_cogs_ratio_by_category': get_cogs_ratio_by_category,
|
|
'find_unusual_adjustments': find_unusual_adjustments,
|
|
'get_inventory_turnover': get_inventory_turnover,
|
|
}
|