1
2import collections
3import logging
4
5from odoo import models
6from odoo.tools import populate
7
8_logger = logging.getLogger(__name__)
9
10
11class Partner(models.Model):
12    _inherit = "res.partner"
13    _populate_dependencies = ["res.company", "res.partner.industry"]
14
15    _populate_sizes = {
16        'small': 10,
17        'medium': 2000,
18        'large': 100000,
19    }
20
21    def _populate_factories(self):
22
23        # example of more complex generator composed of multiple sub generators
24        # this define one subgenerator per "country"
25        address_factories_groups = [
26            [ # Falsy, 2 records
27                ('street', populate.iterate([False, ''])),
28                ('street2', populate.iterate([False, ''])),
29                ('city', populate.iterate([False, ''])),
30                ('zip', populate.iterate([False, ''])),
31                ('country_id', populate.iterate([False])),
32            ], [  # BE, 1 record
33                ('street', populate.iterate(['Boulevard Tintin {counter}'])),
34                ('city', populate.iterate(['Brussels'])),
35                ('zip', populate.iterate([1020])),
36                ('country_id', populate.iterate([self.env.ref('base.be').id])),
37            ], [  # US, 3 records
38                ('street', populate.iterate(['Main street', '3th street {counter}', False])),
39                ('street2', populate.iterate([False, '', 'Behind the tree {counter}'], [90, 5, 5])),
40                ('city', populate.randomize(['Sans Fransisco', 'Los Angeles', '', False])),
41                ('zip', populate.iterate([False, '', '50231'])),
42                ('country_id', populate.iterate([self.env.ref('base.us').id])),
43            ], [  # IN, 2 records
44                ('street', populate.iterate(['Main Street', 'Some Street {counter}'])),
45                ('city', populate.iterate(['ગાંધીનગર (Gandhinagar)'])),
46                ('zip', populate.randomize(['382002', '382008'])),
47                ('country_id', populate.randomize([self.env.ref('base.in').id])),
48            ], [  # other corner cases, 4 records
49                ('street', populate.iterate(['万泉寺村', 'საბჭოს სკვერი {counter}', '10th Street {counter}'])),
50                ('city', populate.iterate(['北京市', 'თბილისი', 'دبي'])),
51                ('zip', populate.iterate([False, 'UF47', '0', '10201'])),
52                ('country_id', populate.randomize([False] + self.env['res.country'].search([]).ids)),
53            ]
54        ]
55
56        def generate_address(iterator, *args):
57            address_generators = [populate.chain_factories(address_factories, self._name) for address_factories in address_factories_groups]
58            # first, exhaust all address_generators
59            for adress_generator in address_generators:
60                for adress_values in adress_generator:
61                    if adress_values['__complete']:
62                        break
63                    values = next(iterator)  # only consume main iterator if usefull
64                    yield {**values, **adress_values}
65
66            # then, go pseudorandom between generators
67            r = populate.Random('res.partner+address_generator_selector')
68            for values in iterator:
69                adress_generator = r.choice(address_generators)
70                adress_values = next(adress_generator)
71                yield {**adress_values, **values}
72
73        # state based on country
74        states = self.env['res.country.state'].search([])
75        states_per_country = collections.defaultdict(list)
76        for state in states:
77            states_per_country[state.country_id.id].append(state.id)
78
79        def get_state(values=None, random=None, **kwargs):
80            country_id = values['country_id']
81            if not country_id:
82                return False
83            return random.choice([False] + states_per_country[country_id])
84
85        def get_name(values=None, counter=0, **kwargs):
86            is_company = values['is_company']
87            complete = values['__complete']
88            return  '%s_%s_%s' % ('company' if is_company else 'partner', int(complete), counter)
89
90        industry_ids = self.env.registry.populated_models['res.partner.industry']
91        company_ids = self.env.registry.populated_models['res.company']
92
93        # not defined fields: vat, partner_longitude, date, partner_latitude, color, company_name, employee, lang, user_id
94        return [
95            ('active', populate.cartesian([True, False], [0.9, 0.1])),
96            ('employee', populate.cartesian([True, False], [0.1, 0.9])),
97            ('email', populate.iterate(
98                [False, '', 'email{counter}@example.com', '<contact 万> contact{counter}@anotherexample.com', 'invalid_email'])),
99            ('type', populate.constant('contact')),  # todo add more logic, manage 'invoice', 'delivery', 'other', 'private'
100            ('is_company', populate.iterate([True, False], [0.05, 0.95])),
101            ('_address', generate_address),
102            ('state_id', populate.compute(get_state)),
103            ('phone', populate.randomize([False, '', '+3212345678', '003212345678', '12345678'])),
104            ('mobile', populate.randomize([False, '', '+32412345678', '0032412345678', '412345678'])),
105            ('title', populate.randomize(self.env['res.partner.title'].search([]).ids)),
106            ('function', populate.randomize(
107                [False, '', 'President of Sales', 'Senior Consultant', 'Product owner', 'Functional Consultant', 'Chief Executive Officer'],
108                [50, 10, 2, 20, 5, 10, 1])),
109            ('tz', populate.randomize([tz for tz in self.env['res.partner']._fields['tz'].get_values(self.env)])),
110            ('website', populate.randomize([False, '', 'http://www.example.com'])),
111            ('credit_limit', populate.randomize(
112                [False, 0, 500, 2500, 5000, 10000],
113                [50, 30, 5, 5, 5, 5])),
114            ('name', populate.compute(get_name)),  # keep after is_company
115            ('ref', populate.randomize([False, '', '{counter}', 'p-{counter}'], [10, 10, 30, 50])),
116            ('industry_id', populate.randomize(
117                [False] + industry_ids,
118                [0.5] + ([0.5/(len(industry_ids) or 1)] * len(industry_ids)))),
119            ('comment', populate.iterate([False, '', 'This is a partner {counter}'])),
120            ('company_id', populate.iterate(
121                [False, self.env.ref('base.main_company').id] + company_ids,
122                [1, 1] + [1/(len(company_ids) or 1)]*len(company_ids))),
123            ('parent_id', populate.constant(False)),  # will be setted in _populate override
124        ]
125
126    def _populate(self, size):
127        records = super()._populate(size)
128        # set parent_ids
129        self._populate_set_companies(records)
130        return records
131
132    def _populate_set_companies(self, records):
133        _logger.info('Setting companies')
134        r_company = populate.Random('res.partner+company_has_partners') # 50% change to have partners
135        companies = records.filtered(lambda p: p.is_company and r_company.getrandbits(1))
136        partners = records - companies
137        r_partner = populate.Random('res.partner+partner_has_company')
138        r_company_pick = populate.Random('res.partner+partner_company_pick=')
139        companies_partners = collections.defaultdict(lambda: self.env['res.partner'])
140        for count, partner in enumerate(partners):
141            if bool(r_partner.getrandbits(1)):  # 50% change to have a company
142                companies_partners[r_company_pick.choice(companies)] |= partner
143
144        # batching company write improves performances a lot (~40% faster for total partner creation).
145        for count, (company, partners) in enumerate(companies_partners.items()):
146            if (count + 1) % 100 == 0:
147                _logger.info('Setting company: %s/%s', count + 1, len(companies))
148            partners.write({'parent_id': company.id})
149
150class ResPartnerIndustry(models.Model):
151    _inherit = "res.partner.industry"
152
153    _populate_sizes = {
154        'small': 15,
155        'medium': 60,
156        'large': 300,
157    }
158
159    def _populate_factories(self):
160        return [
161            ('active', populate.cartesian([False, True], [0.1, 0.9])),
162            ('name', populate.cartesian(
163                [False, 'Industry name', 'Industry name {counter}'],
164                [0.08, 0.01, 0.9])),
165            ('full_name', populate.iterate([False, 'Industry full name %s']))
166        ]
167