mirror of
https://github.com/bringout/oca-ocb-sale.git
synced 2026-04-26 14:51:59 +02:00
Initial commit: Sale packages
This commit is contained in:
commit
14e3d26998
6469 changed files with 2479670 additions and 0 deletions
|
|
@ -0,0 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import product
|
||||
from . import product_template
|
||||
from . import product_pricelist
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
116
odoo-bringout-oca-ocb-product/product/populate/product.py
Normal file
116
odoo-bringout-oca-ocb-product/product/populate/product.py
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
import logging
|
||||
import collections
|
||||
|
||||
from odoo import models
|
||||
from odoo.tools import populate
|
||||
from odoo.addons.stock.populate.stock import COMPANY_NB_WITH_STOCK
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ProductCategory(models.Model):
|
||||
_inherit = "product.category"
|
||||
_populate_sizes = {"small": 50, "medium": 500, "large": 5_000}
|
||||
|
||||
def _populate_factories(self):
|
||||
return [("name", populate.constant('PC_{counter}'))]
|
||||
|
||||
def _populate(self, size):
|
||||
categories = super()._populate(size)
|
||||
# Set parent/child relation
|
||||
self._populate_set_parents(categories, size)
|
||||
return categories
|
||||
|
||||
def _populate_set_parents(self, categories, size):
|
||||
_logger.info('Set parent/child relation of product categories')
|
||||
parent_ids = []
|
||||
rand = populate.Random('product.category+parent_generator')
|
||||
|
||||
for category in categories:
|
||||
if rand.random() < 0.25:
|
||||
parent_ids.append(category.id)
|
||||
|
||||
categories -= self.browse(parent_ids) # Avoid recursion in parent-child relations.
|
||||
parent_childs = collections.defaultdict(lambda: self.env['product.category'])
|
||||
for category in categories:
|
||||
if rand.random() < 0.25: # 1/4 of remaining categories have a parent.
|
||||
parent_childs[rand.choice(parent_ids)] |= category
|
||||
|
||||
for count, (parent, children) in enumerate(parent_childs.items()):
|
||||
if (count + 1) % 1000 == 0:
|
||||
_logger.info('Setting parent: %s/%s', count + 1, len(parent_childs))
|
||||
children.write({'parent_id': parent})
|
||||
|
||||
class ProductProduct(models.Model):
|
||||
_inherit = "product.product"
|
||||
_populate_sizes = {"small": 150, "medium": 5_000, "large": 50_000}
|
||||
_populate_dependencies = ["product.category"]
|
||||
|
||||
def _populate_get_types(self):
|
||||
return ["consu", "service"], [2, 1]
|
||||
|
||||
def _populate_get_product_factories(self):
|
||||
category_ids = self.env.registry.populated_models["product.category"]
|
||||
types, types_distribution = self._populate_get_types()
|
||||
|
||||
def get_rand_float(values, counter, random):
|
||||
return random.randrange(0, 1500) * random.random()
|
||||
|
||||
# TODO sale & purchase uoms
|
||||
|
||||
return [
|
||||
("sequence", populate.randomize([False] + [i for i in range(1, 101)])),
|
||||
("active", populate.randomize([True, False], [0.8, 0.2])),
|
||||
("type", populate.randomize(types, types_distribution)),
|
||||
("categ_id", populate.randomize(category_ids)),
|
||||
("list_price", populate.compute(get_rand_float)),
|
||||
("standard_price", populate.compute(get_rand_float)),
|
||||
]
|
||||
|
||||
def _populate_factories(self):
|
||||
return [
|
||||
("name", populate.constant('product_product_name_{counter}')),
|
||||
("description", populate.constant('product_product_description_{counter}')),
|
||||
("default_code", populate.constant('PP-{counter}')),
|
||||
("barcode", populate.constant('BARCODE-PP-{counter}')),
|
||||
] + self._populate_get_product_factories()
|
||||
|
||||
|
||||
class SupplierInfo(models.Model):
|
||||
_inherit = 'product.supplierinfo'
|
||||
|
||||
_populate_sizes = {'small': 450, 'medium': 15_000, 'large': 180_000}
|
||||
_populate_dependencies = ['res.partner', 'product.product', 'product.template']
|
||||
|
||||
def _populate_factories(self):
|
||||
random = populate.Random('product_with_supplierinfo')
|
||||
company_ids = self.env.registry.populated_models['res.company'][:COMPANY_NB_WITH_STOCK] + [False]
|
||||
partner_ids = self.env.registry.populated_models['res.partner']
|
||||
product_templates_ids = self.env['product.product'].browse(self.env.registry.populated_models['product.product']).product_tmpl_id.ids
|
||||
product_templates_ids += self.env.registry.populated_models['product.template']
|
||||
product_templates_ids = random.sample(product_templates_ids, int(len(product_templates_ids) * 0.95))
|
||||
|
||||
def get_company_id(values, counter, random):
|
||||
partner = self.env['res.partner'].browse(values['partner_id'])
|
||||
if partner.company_id:
|
||||
return partner.company_id.id
|
||||
return random.choice(company_ids)
|
||||
|
||||
def get_delay(values, counter, random):
|
||||
# 5 % with huge delay (between 5 month and 6 month), otherwise between 1 and 10 days
|
||||
if random.random() > 0.95:
|
||||
return random.randint(150, 210)
|
||||
return random.randint(1, 10)
|
||||
|
||||
return [
|
||||
('partner_id', populate.randomize(partner_ids)),
|
||||
('company_id', populate.compute(get_company_id)),
|
||||
('product_tmpl_id', populate.iterate(product_templates_ids)),
|
||||
('product_name', populate.constant("SI-{counter}")),
|
||||
('sequence', populate.randint(1, 10)),
|
||||
('min_qty', populate.randint(0, 10)),
|
||||
('price', populate.randint(10, 100)),
|
||||
('delay', populate.compute(get_delay)),
|
||||
]
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import models
|
||||
from odoo.tools import populate
|
||||
from datetime import timedelta, date
|
||||
|
||||
|
||||
class Pricelist(models.Model):
|
||||
_inherit = "product.pricelist"
|
||||
_populate_sizes = {"small": 20, "medium": 100, "large": 1_500}
|
||||
_populate_dependencies = ["res.company"]
|
||||
|
||||
def _populate(self, size):
|
||||
|
||||
# Reflect the settings with data created
|
||||
self.env['res.config.settings'].create({
|
||||
'group_product_pricelist': True, # Activate pricelist
|
||||
'group_sale_pricelist': True, # Activate advanced pricelist
|
||||
}).execute()
|
||||
|
||||
return super()._populate(size)
|
||||
|
||||
def _populate_factories(self):
|
||||
company_ids = self.env.registry.populated_models["res.company"]
|
||||
|
||||
return [
|
||||
("company_id", populate.iterate(company_ids + [False for i in range(len(company_ids))])),
|
||||
("name", populate.constant('product_pricelist_{counter}')),
|
||||
("currency_id", populate.randomize(self.env["res.currency"].search([("active", "=", True)]).ids)),
|
||||
("sequence", populate.randomize([False] + [i for i in range(1, 101)])),
|
||||
("discount_policy", populate.randomize(["with_discount", "without_discount"])),
|
||||
("active", populate.randomize([True, False], [0.8, 0.2])),
|
||||
]
|
||||
|
||||
|
||||
class PricelistItem(models.Model):
|
||||
_inherit = "product.pricelist.item"
|
||||
_populate_sizes = {"small": 500, "medium": 5_000, "large": 50_000}
|
||||
_populate_dependencies = ["product.product", "product.template", "product.pricelist"]
|
||||
|
||||
def _populate_factories(self):
|
||||
pricelist_ids = self.env.registry.populated_models["product.pricelist"]
|
||||
product_ids = self.env.registry.populated_models["product.product"]
|
||||
p_tmpl_ids = self.env.registry.populated_models["product.template"]
|
||||
categ_ids = self.env.registry.populated_models["product.category"]
|
||||
|
||||
def get_target_info(iterator, field_name, model_name):
|
||||
random = populate.Random("pricelist_target")
|
||||
for values in iterator:
|
||||
# If product population is updated to consider multi company
|
||||
# the company of product would have to be considered
|
||||
# for product_id & product_tmpl_id
|
||||
applied_on = values["applied_on"]
|
||||
if applied_on == "0_product_variant":
|
||||
values["product_id"] = random.choice(product_ids)
|
||||
elif applied_on == "1_product":
|
||||
values["product_tmpl_id"] = random.choice(p_tmpl_ids)
|
||||
elif applied_on == "2_product_category":
|
||||
values["categ_id"] = random.choice(categ_ids)
|
||||
yield values
|
||||
|
||||
def get_prices(iterator, field_name, model_name):
|
||||
random = populate.Random("pricelist_prices")
|
||||
for values in iterator:
|
||||
# Fixed price, percentage, formula
|
||||
compute_price = values["compute_price"]
|
||||
if compute_price == "fixed":
|
||||
# base = "list_price" = default
|
||||
# fixed_price
|
||||
values["fixed_price"] = random.randint(1, 1000)
|
||||
elif compute_price == "percentage":
|
||||
# base = "list_price" = default
|
||||
# percent_price
|
||||
values["percent_price"] = random.randint(1, 100)
|
||||
else: # formula
|
||||
# pricelist base not considered atm.
|
||||
values["base"] = random.choice(["list_price", "standard_price"])
|
||||
values["price_discount"] = random.randint(0, 100)
|
||||
# price_min_margin, price_max_margin
|
||||
# price_round ??? price_discount, price_surcharge
|
||||
yield values
|
||||
|
||||
now = date.today()
|
||||
|
||||
def get_date_start(values, counter, random):
|
||||
if random.random() > 0.5: # 50 % of chance to have validation dates
|
||||
return now + timedelta(days=random.randint(-20, 20))
|
||||
else:
|
||||
False
|
||||
|
||||
def get_date_end(values, counter, random):
|
||||
if values['date_start']: # 50 % of chance to have validation dates
|
||||
return values['date_start'] + timedelta(days=random.randint(5, 100))
|
||||
else:
|
||||
False
|
||||
|
||||
return [
|
||||
("pricelist_id", populate.randomize(pricelist_ids)),
|
||||
("applied_on", populate.randomize(
|
||||
["3_global", "2_product_category", "1_product", "0_product_variant"],
|
||||
[5, 3, 2, 1],
|
||||
)),
|
||||
("compute_price", populate.randomize(
|
||||
["fixed", "percentage", "formula"],
|
||||
[5, 3, 1],
|
||||
)),
|
||||
("_price", get_prices),
|
||||
("_target", get_target_info),
|
||||
("min_quantity", populate.randint(0, 50)),
|
||||
("date_start", populate.compute(get_date_start)),
|
||||
("date_end", populate.compute(get_date_end)),
|
||||
]
|
||||
|
|
@ -0,0 +1,187 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
import logging
|
||||
from collections import defaultdict
|
||||
from functools import reduce
|
||||
|
||||
from odoo import models
|
||||
from odoo.tools import populate
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ProductAttribute(models.Model):
|
||||
_inherit = "product.attribute"
|
||||
_populate_sizes = {"small": 20, "medium": 150, "large": 750}
|
||||
|
||||
def _populate(self, size):
|
||||
|
||||
# Reflect the settings with data created
|
||||
self.env['res.config.settings'].create({
|
||||
'group_product_variant': True, # Activate variant
|
||||
}).execute()
|
||||
|
||||
return super()._populate(size)
|
||||
|
||||
def _populate_factories(self):
|
||||
return [
|
||||
("name", populate.constant('PA_{counter}')),
|
||||
("sequence", populate.randomize([False] + [i for i in range(1, 101)])),
|
||||
("create_variant", populate.randomize(["always", "dynamic", "no_variant"])),
|
||||
]
|
||||
|
||||
|
||||
class ProductAttributeValue(models.Model):
|
||||
_inherit = "product.attribute.value"
|
||||
_populate_dependencies = ["product.attribute"]
|
||||
_populate_sizes = {"small": 100, "medium": 1_000, "large": 10_000}
|
||||
|
||||
def _populate_factories(self):
|
||||
attribute_ids = self.env.registry.populated_models["product.attribute"]
|
||||
|
||||
return [
|
||||
("name", populate.constant('PAV_{counter}')),
|
||||
("sequence", populate.randomize([False] + [i for i in range(1, 101)])),
|
||||
("attribute_id", populate.randomize(attribute_ids)),
|
||||
]
|
||||
|
||||
|
||||
class ProductTemplate(models.Model):
|
||||
_inherit = "product.template"
|
||||
_populate_sizes = {"small": 150, "medium": 5_000, "large": 50_000}
|
||||
_populate_dependencies = ["product.attribute.value", "product.category"]
|
||||
|
||||
def _populate(self, size):
|
||||
res = super()._populate(size)
|
||||
|
||||
def set_barcode_variant(sample_ratio):
|
||||
random = populate.Random('barcode_product_template')
|
||||
product_variants_ids = res.product_variant_ids.ids
|
||||
product_variants_ids = random.sample(product_variants_ids, int(len(product_variants_ids) * sample_ratio))
|
||||
product_variants = self.env['product.product'].browse(product_variants_ids)
|
||||
_logger.info('Set barcode on product variants (%s)', len(product_variants))
|
||||
for product in product_variants:
|
||||
product.barcode = "BARCODE-PT-%s" % product.id
|
||||
|
||||
set_barcode_variant(0.85)
|
||||
|
||||
return res
|
||||
|
||||
def _populate_factories(self):
|
||||
attribute_ids = self.env.registry.populated_models["product.attribute"]
|
||||
attribute_ids_by_types = defaultdict(list)
|
||||
attributes = self.env["product.attribute"].browse(attribute_ids)
|
||||
for attr in attributes:
|
||||
attribute_ids_by_types[attr.create_variant].append(attr.id)
|
||||
|
||||
def get_attributes(values, counter, random):
|
||||
if random.random() < 0.20: # 20 % chance to have no attributes
|
||||
return False
|
||||
attributes_qty = random.choices(
|
||||
[1, 2, 3, 4, 5, 6, 8, 10],
|
||||
[10, 9, 8, 7, 6, 4, 1, 0.5],
|
||||
)[0]
|
||||
attr_line_vals = []
|
||||
attribute_used_ids = attribute_ids
|
||||
if random.random() < 0.20: # 20 % chance of using only always attributes (to test when product has lot of variant)
|
||||
attribute_used_ids = attribute_ids_by_types["always"]
|
||||
|
||||
no_variant = False
|
||||
values_count = [0 for i in range(attributes_qty)]
|
||||
|
||||
def will_exceed(i):
|
||||
return not no_variant and reduce((lambda x, y: (x or 1) * (y or 1)), values_count[i:] + [values_count[i] + 1] + values_count[:i]) > 1000
|
||||
|
||||
for i in range(attributes_qty):
|
||||
if will_exceed(i):
|
||||
return attr_line_vals
|
||||
attr_id = random.choice(attribute_used_ids)
|
||||
attr = self.env["product.attribute"].browse(attr_id)
|
||||
if attr.create_variant == "dynamic":
|
||||
no_variant = True
|
||||
if not attr.value_ids:
|
||||
# attribute without any value
|
||||
continue
|
||||
nb_values = len(attr.value_ids)
|
||||
vals_qty = random.randrange(nb_values) + 1
|
||||
value_ids = set()
|
||||
for __ in range(vals_qty):
|
||||
# Ensure that we wouldn't have > 1k variants with the generated attributes combination
|
||||
if will_exceed(i):
|
||||
break
|
||||
random_value_id = attr.value_ids[random.randrange(nb_values)].id
|
||||
if random_value_id not in value_ids:
|
||||
values_count[i] += 1
|
||||
value_ids.add(random_value_id)
|
||||
|
||||
attr_line_vals.append((0, 0, {
|
||||
"attribute_id": attr_id,
|
||||
"value_ids": [(6, 0, list(value_ids))],
|
||||
}))
|
||||
|
||||
return attr_line_vals
|
||||
|
||||
return [
|
||||
("name", populate.constant('product_template_name_{counter}')),
|
||||
("description", populate.constant('product_template_description_{counter}')),
|
||||
("default_code", populate.constant('PT-{counter}')),
|
||||
("attribute_line_ids", populate.compute(get_attributes)),
|
||||
] + self.env['product.product']._populate_get_product_factories()
|
||||
|
||||
|
||||
class ProductTemplateAttributeExclusion(models.Model):
|
||||
_inherit = "product.template.attribute.exclusion"
|
||||
_populate_dependencies = ["product.template"]
|
||||
_populate_sizes = {"small": 200, "medium": 1_000, "large": 5_000}
|
||||
|
||||
def _populate_factories(self):
|
||||
p_tmpl_ids = self.env.registry.populated_models["product.template"]
|
||||
|
||||
configurable_templates = self.env["product.template"].search([
|
||||
('id', 'in', p_tmpl_ids),
|
||||
('has_configurable_attributes', '=', True),
|
||||
])
|
||||
tmpl_ids_possible = []
|
||||
multi_values_attribute_lines_by_tmpl = {}
|
||||
for template in configurable_templates:
|
||||
multi_values_attribute_lines = template.attribute_line_ids.filtered(
|
||||
lambda l: len(l.value_ids) > 1
|
||||
)
|
||||
if len(multi_values_attribute_lines) < 2:
|
||||
continue
|
||||
tmpl_ids_possible.append(template.id)
|
||||
multi_values_attribute_lines_by_tmpl[template.id] = multi_values_attribute_lines
|
||||
|
||||
def get_product_template_attribute_value_id(values, counter, random):
|
||||
return random.choice(multi_values_attribute_lines_by_tmpl[values['product_tmpl_id']].product_template_value_ids.ids)
|
||||
|
||||
def get_value_ids(values, counter, random):
|
||||
attr_val = self.env['product.template.attribute.value'].browse(values['product_template_attribute_value_id']).attribute_line_id
|
||||
remaining_lines = multi_values_attribute_lines_by_tmpl[values['product_tmpl_id']] - attr_val
|
||||
return [(
|
||||
# TODO: multiple values
|
||||
6, 0, [random.choice(remaining_lines.product_template_value_ids).id]
|
||||
)]
|
||||
|
||||
return [
|
||||
("product_tmpl_id", populate.randomize(tmpl_ids_possible)),
|
||||
("product_template_attribute_value_id", populate.compute(get_product_template_attribute_value_id)),
|
||||
("value_ids", populate.compute(get_value_ids)),
|
||||
]
|
||||
|
||||
|
||||
class ProductTemplateAttributeValue(models.Model):
|
||||
_inherit = "product.template.attribute.value"
|
||||
_populate_dependencies = ["product.template"]
|
||||
|
||||
def _populate(self, size):
|
||||
p_tmpl_ids = self.env.registry.populated_models["product.template"]
|
||||
ptavs = self.search([('product_tmpl_id', 'in', p_tmpl_ids)])
|
||||
# ptavs are automatically created when specifying attribute lines on product templates.
|
||||
|
||||
rand = populate.Random("ptav_extra_price_generator")
|
||||
for ptav in ptavs:
|
||||
if rand.random() < 0.50: # 50% of having a extra price
|
||||
ptav.price_extra = rand.randrange(500) * rand.random()
|
||||
|
||||
return ptavs
|
||||
Loading…
Add table
Add a link
Reference in a new issue