# -*- coding: utf-8 -*- """Classes defining the populate factory for Bank Statements and related models.""" from odoo import models, Command from odoo.tools import populate from dateutil.relativedelta import relativedelta from functools import lru_cache import logging _logger = logging.getLogger(__name__) class AccountBankStatement(models.Model): """Populate factory part for account.bank.statements.""" _inherit = "account.bank.statement" _populate_dependencies = ['account.bank.statement.line'] def _populate(self, size): """ Populate the bank statements with random lines. :param size: :return: """ rand = populate.Random('account_bank_statement+Populate') read_group_res = self.env['account.bank.statement.line']._read_group( [('statement_id', '=', False)], ['journal_id'], ['id:array_agg'], ) bank_statement_vals_list = [] for journal, ids in read_group_res: nb_ids = len(ids) while nb_ids > 0: batch_size = min(rand.randint(1, 19), nb_ids) nb_ids -= batch_size # 50% to create a statement. statement_needed = bool(rand.randint(0, 1)) if not statement_needed: continue bank_statement_vals_list.append({ 'name': f"statement_{len(bank_statement_vals_list) + 1}", 'journal_id': journal.id, 'line_ids': [Command.set(ids)], }) return self.env['account.bank.statement'].create(bank_statement_vals_list) class AccountBankStatementLine(models.Model): """Populate factory part for account.bank.statements.line.""" _inherit = "account.bank.statement.line" _populate_sizes = { 'small': 100, 'medium': 10000, 'large': 200000, } _populate_dependencies = ['account.journal', 'res.company', 'res.partner'] def _populate_factories(self): @lru_cache() def search_partner_ids(company_id): """Search all the partners that a company has access to. This method is cached, only one search is done per company_id. :param company_id (int): the company to search partners for. :return (list): the ids of partner the company has access to. """ return self.env['res.partner'].search([ *self.env['res.company']._check_company_domain(company_id), ('id', 'in', self.env.registry.populated_models['res.partner']), ]).ids def get_partner(random, values, **kwargs): """Get a partner by selecting inside the list of partner a company has access to. There is also a chance of having no partner set. :param random: seeded random number generator. :param values (dict): the values already selected for the record. :return (int): an id of a partner accessible by the company of the statement. """ company_id = self.env['account.journal'].browse(values['journal_id']).company_id.id partner = search_partner_ids(company_id) return random.choices(partner + [False], [1/len(partner)] * len(partner) + [1])[0] def get_amount(random, **kwargs): """Get a random amount between -1000 and 1000. It is impossible to get a null amount. Because it would not be a valid statement line. :param random: seeded random number generator. :return (float): a number between -1000 and 1000. """ return random.uniform(-1000, 1000) or 1 def get_amount_currency(random, values, **kwargs): """ Get a random amount currency between one tenth of amount and 10 times amount with the same sign if foreign_currency_id is set :param random: seeded random number generator. :return (float): a number between amount / 10 and amount * 10. """ return random.uniform(0.1 * values['amount'], 10 * values['amount']) if values['foreign_currency_id'] else 0 def get_currency(random, values, **kwargs): """Get a random currency. The currency has to be empty if it is the same as the currency of the line's journal's. :param random: seeded random number generator. :param values (dict): the values already selected for the record. :return (int, bool): the id of an active currency or False if it is the same currency as the lines's journal's currency. """ journal = self.env['account.journal'].browse(values['journal_id']) currency = random.choice(self.env['res.currency'].search([('active', '=', True)]).ids) return currency if currency != (journal.currency_id or journal.company_id.currency_id).id else False company_ids = self.env['res.company'].search([ ('chart_template', '!=', False), ('id', 'in', self.env.registry.populated_models['res.company']), ]) if not company_ids: return [] journal_ids = self.env['account.journal'].search([ *self.env['account.journal']._check_company_domain(company_ids), ('type', 'in', ('cash', 'bank')), ]).ids return [ ('journal_id', populate.iterate(journal_ids)), ('partner_id', populate.compute(get_partner)), ('date', populate.randdatetime(relative_before=relativedelta(years=-4))), ('payment_ref', populate.constant('transaction_{values[date]}_{counter}')), ('amount', populate.compute(get_amount)), ('foreign_currency_id', populate.compute(get_currency)), ('amount_currency', populate.compute(get_amount_currency)), ]