diff --git a/setup.py b/setup.py index 8bbf44b..0e00b05 100644 --- a/setup.py +++ b/setup.py @@ -32,7 +32,7 @@ from setuptools import setup, find_packages setup(name='OdooLocust', - version='1.6.5', + version='1.6.6', description='Easily load test Odoo using Locust and odoolib.', author='Nicolas Seinlet', author_email='', diff --git a/src/OdooLocust/OdooTaskSet.py b/src/OdooLocust/OdooTaskSet.py index da85895..81e58e1 100644 --- a/src/OdooLocust/OdooTaskSet.py +++ b/src/OdooLocust/OdooTaskSet.py @@ -31,6 +31,13 @@ class OdooTaskSet(TaskSet): + model_name = False + model = False + form_fields = [] + list_fields = [] + kanban_fields = [] + filters = [] + def _get_user_context(self): res = self.client.get_model('res.users').read(self.client.user_id, ['lang', 'tz']) return { @@ -40,25 +47,22 @@ def _get_user_context(self): } def _fields_view_get(self, model, view_mode): - res = self.client.get_model(model).load_views(views=[(False, vm) for vm in list(set(["list", "form", "search", view_mode]))]) + res = self.client.get_model(model).get_views(views=[(False, vm) for vm in list(set(["list", "form", "search", view_mode]))]) return [n for n in res.get('fields_views', {}).get(view_mode, {}).get('fields', {}).keys()] def _filters_view_get(self, model): - res = self.client.get_model(model).load_views(views=[(False, vm) for vm in list(set(["list", "form", "search"]))]) + res = self.client.get_model(model).get_views(views=[(False, vm) for vm in list(set(["list", "form", "search"]))]) return [n['domain'] for n in res.get('filters', {})] - def _parse_children_menu(self, childs): - res = [] - for child in childs: - if child['action']: - res.append(child['action'].split(",")) - if child['children']: - res += self._parse_children_menu(child['children']) - return res - def _load_menu(self): + menus = [] res = self.client.get_model('ir.ui.menu').load_menus(False, context=self._get_user_context()) - return self._parse_children_menu(res['children']) + for menu_id in res.keys(): + menu = res[menu_id].get('action') + if menu: + menus.append(menu.split(",")) + print(menus) + return menus def _action_load(self, action_id, action_type=None): if not action_type: @@ -69,26 +73,33 @@ def _action_load(self, action_id, action_type=None): def _check_fields(self, model, fields_list): all_fields = self.client.get_model(model).fields_get() return [ f for f in fields_list if f in all_fields.keys() ] + + def _load_fields_lists(self, form=True, list=True, kanban=False, filters=True): + if form: + self.form_fields = self._fields_view_get(self.model_name, "form") + if list: + self.list_fields = self._fields_view_get(self.model_name, "list") + if kanban: + self.kanban_fields = self._fields_view_get(self.model_name, "kanban") + if filters: + self.filters = self._filters_view_get(self.model_name) class OdooGenericTaskSet(OdooTaskSet): - def on_start(self): self.menu = self._load_menu() self.randomlyChooseMenu() @task(1) def randomlyChooseMenu(self): + self.model_name = False self.model = False - while not self.model and self.model != "False": + while not self.model_name and self.model_name != "False": item = random.choice(self.menu) self.last_action = self._action_load(int(item[1]), item[0]) - self.model = self.last_action.get('res_model', False) - self.form_fields = self._fields_view_get(self.model, "form") - self.list_fields = self._fields_view_get(self.model, "list") - if "kanban" in self.last_action.get('view_mode', []): - self.kanban_fields = self._fields_view_get(self.model, "kanban") - self.filters = self._filters_view_get(self.model) + self.model_name = self.last_action.get('res_model', False) + self.model = self.client.get_model(self.model_name) + self._load_fields_lists(kanban="kanban" in self.last_action.get('view_mode', [])) @task(30) def form_view(self): @@ -96,12 +107,11 @@ def form_view(self): if self.filters and random.randint(0, 10) < 3: domain = random.choice(self.filters) context = self.client.get_user_context() - model = self.client.get_model(self.model) - nbr_records = model.search_count(domain or [], context=context) + nbr_records = self.model.search_count(domain or [], context=context) offset = random.randint(0, nbr_records % 80) if nbr_records > 80 else 0 - ids = model.search(domain or [], limit=80, offset=offset, context=context) + ids = self.model.search(domain or [], limit=80, offset=offset, context=context) if ids: - model.read(random.choice(ids), self.form_fields, context=context) + self.model.read(random.choice(ids), self.form_fields, context=context) @task(10) def list_view(self): @@ -109,14 +119,13 @@ def list_view(self): if self.filters and random.randint(0, 10) < 3: domain = random.choice(self.filters) context = self.client.get_user_context() - model = self.client.get_model(self.model) - nbr_records = model.search_count(domain or [], context=context) - ids = model.search(domain or [], limit=80) + nbr_records = self.model.search_count(domain or [], context=context) + ids = self.model.search(domain or [], limit=80) if nbr_records > 80: offset = random.randint(0, nbr_records % 80) - ids = model.search(domain or [], limit=80, offset=offset, context=context) + ids = self.model.search(domain or [], limit=80, offset=offset, context=context) if ids: - model.search_read([('id', 'in', ids)], self.list_fields, context=context) + self.model.search_read([('id', 'in', ids)], self.list_fields, context=context) @task(10) def kanban_view(self): @@ -125,11 +134,10 @@ def kanban_view(self): if self.filters and random.randint(0, 10) < 3: domain = random.choice(self.filters) context = self.client.get_user_context() - model = self.client.get_model(self.model) - nbr_records = model.search_count(domain or [], context=context) - ids = model.search(domain or [], limit=80) + nbr_records = self.model.search_count(domain or [], context=context) + ids = self.model.search(domain or [], limit=80) if nbr_records > 80: offset = random.randint(0, nbr_records % 80) - ids = model.search(domain or [], limit=80, offset=offset, context=context) + ids = self.model.search(domain or [], limit=80, offset=offset, context=context) if ids: - model.search_read([('id', 'in', ids)], self.kanban_fields, context=context) + self.model.search_read([('id', 'in', ids)], self.kanban_fields, context=context) diff --git a/src/OdooLocust/crm/lead.py b/src/OdooLocust/crm/lead.py index 17179ad..d330132 100644 --- a/src/OdooLocust/crm/lead.py +++ b/src/OdooLocust/crm/lead.py @@ -35,89 +35,76 @@ import random class CrmLead(OdooTaskSet): - list_fields = ["stage_id", "active", "company_id", "calendar_event_count", "company_id", "user_company_ids", "date_deadline", "create_date", "name", "contact_name", "partner_name", "email_from", "phone", "city", "state_id", "country_id", "partner_id", "user_id", "team_id", "active", "campaign_id", "referred", "medium_id", "probability", "source_id", "message_needaction", "tag_ids", "priority"] - form_fields = ["stage_id", "active", "company_id", "calendar_event_count", "sale_amount_total", "sale_order_count", "visitor_page_count", "duplicate_lead_count", "name", "company_currency", "expected_revenue", "recurring_revenue", "recurring_plan", "automated_probability", "is_automated_probability", "probability", "is_partner_visible", "partner_id", "partner_name", "street", "street2", "city", "state_id", "zip", "country_id", "website", "lang_active_count", "lang_code", "lang_id", "is_blacklisted", "partner_is_blacklisted", "phone_blacklisted", "mobile_blacklisted", "email_state", "phone_state", "partner_email_update", "partner_phone_update", "email_from", "phone", "lost_reason_id", "date_conversion", "user_company_ids", "contact_name", "title", "function", "mobile", "type", "user_id", "date_deadline", "priority", "tag_ids", "team_id", "lead_properties", "description", "campaign_id", "medium_id", "source_id", "referred", "date_open", "date_closed", "day_open", "day_close", "display_name"] random_id = -1 - _model_id = -1 - - @property - def model_id(self): - if self._model_id < 0: - irm = self.client.get_model('ir.model.data') - irm_id = irm.search_read([('model', '=', 'crm'), ('name', '=', 'model_crm_lead')], ['res_id']) - if irm_id: - self._model_id = irm_id[0]['res_id'] - return self._model_id + model_name = 'crm.lead' + model = False def on_start(self): super().on_start() + self.model = self.client.get_model(self.model_name) + self._load_fields_lists() self.test_searchread() - def _get_search_domain(self): + if self.filters and random.randint(0, 10) < 3: + return random.choice(self.filters) name = names.get_first_name() return ['|', '|', '|', ('partner_name', 'ilike', name), ('email_from', 'ilike', name), ('contact_name', 'ilike', name), ('name', 'ilike', name)] @task(10) def test_searchread(self): - lead_model = self.client.get_model('crm.lead') - res = lead_model.search_read( - self._get_search_domain(), - self.list_fields, - limit=80, - context=self.client.get_user_context() - ) - if res: - self.random_id = res[0]['id'] + search_domains = [ + self._get_search_domain(), + [('id', '>', self.random_id)], + [] + ] + for domain in search_domains: + res = self.model.search_read( + domain, + self.list_fields, + limit=80, + context=self.client.get_user_context() + ) + if res: + self.random_id = random.choice(res)['id'] + return True @task(5) def test_websearchread(self): - lead_model = self.client.get_model('crm.lead') - res = lead_model.web_search_read( - self._get_search_domain(), - self.list_fields, + res = self.model.web_search_read( + specification={f: {} for f in self.list_fields}, + domain=self._get_search_domain(), limit=80, context=self.client.get_user_context() ) - if res: + if res and res['records']: self.random_id = res[0]['id'] @task(20) def test_read(self): - lead_model = self.client.get_model('crm.lead') - lead_model.read(self.random_id, self.form_fields, context=self.client.get_user_context()) + self.model.read(self.random_id, self.form_fields, context=self.client.get_user_context()) @task(5) def lead_stage_change(self): - lead_model = self.client.get_model('crm.lead') s1 = 229 s2 = 99 - res1 = lead_model.search([('id', '>', self.random_id), ('stage_id', '=', s1)], limit=1) - res2 = lead_model.search([('id', '>', self.random_id), ('stage_id', '=', s2)], limit=1) + res1 = self.model.search([('id', '>', self.random_id), ('stage_id', '=', s1)], limit=1) + res2 = self.model.search([('id', '>', self.random_id), ('stage_id', '=', s2)], limit=1) if res1: - lead_model.write(res1[0], {'stage_id': s2}, context=self.client.get_user_context()) + self.model.write(res1[0], {'stage_id': s2}, context=self.client.get_user_context()) if res2: - lead_model.write(res2[0], {'stage_id': s1}, context=self.client.get_user_context()) + self.model.write(res2[0], {'stage_id': s1}, context=self.client.get_user_context()) @task(5) def test_activity(self): - activity_model = self.client.get_model('mail.activity') - res = activity_model.create({ - "activity_type_id": 4, - "calendar_event_id": False, - "date_deadline": (date(2012, 1 ,1)+timedelta(days=random.randint(1,3650))).isoformat(), - "note": False, - "res_id": self.random_id, - "res_model_id": self.model_id, - "summary": "Todo", - "user_id": self.client.user_id, - }, context=self.client.get_user_context()) - activity_model.action_feedback(res, 'Done') + if self.random_id != -1: + res_id = self.model.activity_schedule(self.random_id, date_deadline=(date(2012, 1 ,1)+timedelta(days=random.randint(1,3650))).isoformat()) + activity_model = self.client.get_model('mail.activity') + activity_model.action_done(res_id) @task def test_pipeline_analysis(self): - lead_model = self.client.get_model('crm.lead') - lead_model.web_read_group( + self.model.web_read_group( ["&", ["type", "=", "opportunity"], "&", ["create_date", ">=", "2022-01-01 00:00:00"], ["create_date", "<=", "2022-12-31 23:59:59"]], ["__count"], ["stage_id", "date_deadline:month"], diff --git a/src/OdooLocust/crm/quotation.py b/src/OdooLocust/crm/quotation.py index 73e0d83..3835e02 100644 --- a/src/OdooLocust/crm/quotation.py +++ b/src/OdooLocust/crm/quotation.py @@ -33,53 +33,86 @@ import random class SaleOrder(OdooTaskSet): - list_fields = ["activity_exception_decoration", "activity_exception_icon", "activity_state", "activity_summary", "activity_type_icon", "activity_type_id", "name", "create_date", "commitment_date", "expected_date", "partner_id", "website_id", "user_id", "activity_ids", "team_id", "tag_ids", "company_id", "amount_untaxed", "amount_tax", "amount_total", "state", "validity_date", "invoice_status", "message_needaction", "currency_id"] - form_fields = ["authorized_transaction_ids", "enterprise_is_new_plan", "state", "subscription_management", "is_upselling", "stage_category", "end_date", "archived_product_count", "partner_credit_warning", "project_ids", "is_product_milestone", "project_count", "milestone_count", "tasks_count", "timesheet_count", "timesheet_total_duration", "timesheet_encode_uom_id", "expense_count", "delivery_count", "id", "planning_first_sale_line_id", "planning_initial_date", "planning_hours_to_plan", "planning_hours_planned", "invoice_count", "attendee_count", "event_booth_count", "history_count", "recurring_monthly", "mrp_production_count", "database_count", "payment_exception", "to_renew", "renew_state", "name", "partner_id", "commission_plan_frozen", "referrer_id", "commission_plan_id", "delivery_set", "is_all_service", "recompute_delivery_price", "sale_order_template_id", "validity_date", "date_order", "recurrence_id", "invoice_date_diff", "next_invoice_date", "expected_next_invoice_date", "show_update_pricelist", "pricelist_id", "company_id", "currency_id", "tax_country_id", "payment_term_id", "new_sub_id", "old_sub_id", "order_line", "is_avatax", "note", "tax_totals", "commission", "sale_order_option_ids", "user_id", "team_id", "website_id", "is_abandoned_cart", "cart_recovery_email_sent", "require_signature", "require_payment", "website_description", "reference", "client_order_ref", "tag_ids", "start_date", "first_contract_date", "avatax_unique_code", "show_update_fpos", "fiscal_position_id", "partner_invoice_id", "analytic_account_id", "visible_project", "project_id", "invoice_status", "commercial_partner_id", "payment_token_id", "warehouse_id", "picking_policy", "commitment_date", "expected_date", "show_json_popover", "json_popover", "effective_date", "delivery_status", "origin", "campaign_id", "medium_id", "source_id", "internal_note", "enterprise_final_customer_id", "enterprise_security_email", "is_staff_restricted", "subscription_tag_ids", "enterprise_saas", "upsell_order_id", "upsell_date", "upsell_content", "maintenance_subscription_id", "maintenance_main_subscription_id", "maintenance_is_activated", "maintenance_stage_category", "odoo_sh_extra_gb", "odoo_sh_extra_stagings", "odoo_sh_extra_workers", "odoo_sh_extra_dedicated", "exclude_dashboard", "github_user_ids", "is_taxcloud", "is_taxcloud_configured", "display_name"] - line_fields = ["analytic_precision", "sequence", "display_type", "product_uom_category_id", "product_type", "product_updatable", "product_id", "product_template_id", "product_template_attribute_value_ids", "product_custom_attribute_value_ids", "product_no_variant_attribute_value_ids", "is_configurable_product", "event_id", "event_ticket_id", "is_event_booth", "event_booth_category_id", "event_booth_pending_ids", "name", "temporal_type", "website_description", "analytic_distribution", "product_uom_qty", "qty_delivered", "virtual_available_at_date", "qty_available_today", "free_qty_today", "scheduled_date", "forecast_expected_date", "warehouse_id", "move_ids", "qty_to_deliver", "is_mto", "display_qty_widget", "qty_delivered_method", "qty_invoiced", "qty_to_invoice", "product_uom_readonly", "product_uom", "customer_lead", "recompute_delivery_price", "is_delivery", "price_unit", "tax_id", "price_tax", "discount", "is_downpayment", "price_subtotal", "state", "invoice_status", "currency_id", "company_id", "database_id", "computation"] - random_id = 2795659 + line_fields = [] + random_id = -1 + model_name = 'sale.order' + + def on_start(self): + super().on_start() + self.model = self.client.get_model(self.model_name) + self._load_fields_lists() + self.line_fields = self._fields_view_get('sale.order.line', 'list') + self.test_list() + + def _get_search_domain(self): + if self.filters and random.randint(0, 10) < 3: + return random.choice(self.filters) + name = names.get_first_name() + return ["|", "|", ["name", "ilike", name], ["client_order_ref", "ilike", name], ["partner_id", "child_of", name]] @task def test_list(self): - name = names.get_first_name() - saleorder_model = self.client.get_model('sale.order') - for domain in ([], ["|", "|", ["name", "ilike", name], ["client_order_ref", "ilike", name], ["partner_id", "child_of", name]]) : - res = saleorder_model.web_search_read( - domain, - self.list_fields, + search_domains = [ + self._get_search_domain(), + [('id', '>', self.random_id)], + [] + ] + for domain in search_domains: + res = self.model.web_search_read( + specification={f: {} for f in self.list_fields}, + domain=domain, limit=80, context=self.client.get_user_context(), ) - if res and domain: - self.random_id = res[0]['id'] + if res and res['records']: + self.random_id = random.choice(res['records'])['id'] + return True @task def test_form(self): - saleorder_model = self.client.get_model('sale.order') - saleorderline_model = self.client.get_model('sale.order.line') - res = saleorder_model.read( - [self.random_id], - self.form_fields, - context=self.client.get_user_context(), - ) - saleorderline_model.search_read( - [ ['order_id', '=', self.random_id] ], - self.line_fields, - context=self.client.get_user_context(), - ) + if self.random_id != -1: + saleorderline_model = self.client.get_model('sale.order.line') + res = self.model.read( + [self.random_id], + self.form_fields, + context=self.client.get_user_context(), + ) + saleorderline_model.search_read( + [ ['order_id', '=', self.random_id] ], + self.line_fields, + context=self.client.get_user_context(), + ) @task def test_set_to_quotation(self): - saleorder_model = self.client.get_model('sale.order') - saleorder_model.action_draft([self.random_id], context=self.client.get_user_context()) + if self.random_id != -1: + self.model.action_draft([self.random_id], context=self.client.get_user_context()) @task def test_quotation_confirm(self): - saleorder_model = self.client.get_model('sale.order') - res = saleorder_model.search([['state', '=', 'draft'], '!', [ 'order_line.product_id.active', '=', False ], [ 'partner_id.country_id', '!=', False], [ 'company_id', '=', 1]], context=self.client.get_user_context()) + res = self.model.search([['state', '=', 'draft'], '!', [ 'order_line.product_id.active', '=', False ], [ 'partner_id.country_id', '!=', False], [ 'company_id', '=', 1]], context=self.client.get_user_context()) if res: - saleorder_model.action_confirm(random.choice(res), context=self.client.get_user_context()) + self.random_id = random.choice(res) + self.model.action_confirm(random.choice(res), context=self.client.get_user_context()) @task def test_quotation_sendemail(self): - saleorder_model = self.client.get_model('sale.order') - saleorder_model.action_quotation_send([self.random_id], context=self.client.get_user_context()) + if self.random_id != -1: + self.model.action_quotation_send([self.random_id], context=self.client.get_user_context()) + + @task(5) + def new_quotation(self): + prtn_model = self.client.get_model('res.partner') + prod_model = self.client.get_model('product.product') + prtn_cnt = prtn_model.search_count([]) + prod_cnt = prod_model.search_count([('sale_ok', '=', True)]) + + prtn_id = prtn_model.search([], offset=random.randint(0, prtn_cnt), limit=1) + prod_id = prod_model.search([('sale_ok', '=', True)], offset=random.randint(0, prod_cnt), limit=1) + + self.random_id = self.model.create({ + 'partner_id': prtn_id[0], + 'order_line': [(0, 0, { + 'product_id': prod_id[0], + })] + })