From 8e6dcae450b16a7c2b12212eace2d7c302d731f2 Mon Sep 17 00:00:00 2001 From: emjay0921 Date: Tue, 30 Sep 2025 16:38:07 +0800 Subject: [PATCH 01/16] [ADD] spp_demo_common --- spp_demo_common/__init__.py | 2 + spp_demo_common/__manifest__.py | 37 ++++ .../data/ir_config_parameter_data.xml | 19 ++ spp_demo_common/models/__init__.py | 2 + spp_demo_common/models/demo_data_generator.py | 63 +++++++ spp_demo_common/models/res_config_settings.py | 22 +++ spp_demo_common/pyproject.toml | 3 + spp_demo_common/security/ir.model.access.csv | 7 + spp_demo_common/static/description/icon.png | Bin 0 -> 15480 bytes .../views/demo_data_generator_view.xml | 162 ++++++++++++++++++ spp_demo_common/views/res_config_view.xml | 45 +++++ 11 files changed, 362 insertions(+) create mode 100644 spp_demo_common/__init__.py create mode 100644 spp_demo_common/__manifest__.py create mode 100644 spp_demo_common/data/ir_config_parameter_data.xml create mode 100644 spp_demo_common/models/__init__.py create mode 100644 spp_demo_common/models/demo_data_generator.py create mode 100644 spp_demo_common/models/res_config_settings.py create mode 100644 spp_demo_common/pyproject.toml create mode 100644 spp_demo_common/security/ir.model.access.csv create mode 100644 spp_demo_common/static/description/icon.png create mode 100644 spp_demo_common/views/demo_data_generator_view.xml create mode 100644 spp_demo_common/views/res_config_view.xml diff --git a/spp_demo_common/__init__.py b/spp_demo_common/__init__.py new file mode 100644 index 000000000..d33610325 --- /dev/null +++ b/spp_demo_common/__init__.py @@ -0,0 +1,2 @@ +# Part of OpenSPP. See LICENSE file for full copyright and licensing details. +from . import models diff --git a/spp_demo_common/__manifest__.py b/spp_demo_common/__manifest__.py new file mode 100644 index 000000000..149bed514 --- /dev/null +++ b/spp_demo_common/__manifest__.py @@ -0,0 +1,37 @@ +# Part of OpenSPP. See LICENSE file for full copyright and licensing details. + + +{ + "name": "OpenSPP Demo (Common)", + "category": "OpenSPP/OpenSPP", + "version": "17.0.1.3.0", + "sequence": 1, + "author": "OpenSPP.org", + "website": "https://github.com/OpenSPP/openspp-modules", + "license": "LGPL-3", + "development_status": "Production/Stable", + "maintainers": ["jeremi", "gonzalesedwin1123", "emjay0921"], + "depends": [ + "base", + "spp_base_common", + "g2p_registry_base", + "g2p_registry_individual", + "g2p_registry_group", + "g2p_registry_membership", + ], + "excludes": [], + "external_dependencies": {}, + "data": [ + "security/ir.model.access.csv", + "data/ir_config_parameter_data.xml", + "views/res_config_view.xml", + "views/demo_data_generator_view.xml", + ], + "assets": {}, + "demo": [], + "images": [], + "application": True, + "installable": True, + "auto_install": False, + "summary": "Base demo module with generic data generator and sample data for OpenSPP modules.", +} diff --git a/spp_demo_common/data/ir_config_parameter_data.xml b/spp_demo_common/data/ir_config_parameter_data.xml new file mode 100644 index 000000000..f92d02efd --- /dev/null +++ b/spp_demo_common/data/ir_config_parameter_data.xml @@ -0,0 +1,19 @@ + + + + spp_demo_common.number_of_groups + 10 + + + spp_demo_common.members_range_from + 1 + + + spp_demo_common.members_range_to + 10 + + + spp_demo_common.batch_size + 20 + + diff --git a/spp_demo_common/models/__init__.py b/spp_demo_common/models/__init__.py new file mode 100644 index 000000000..ff6fce98c --- /dev/null +++ b/spp_demo_common/models/__init__.py @@ -0,0 +1,2 @@ +from . import res_config_settings +from . import demo_data_generator diff --git a/spp_demo_common/models/demo_data_generator.py b/spp_demo_common/models/demo_data_generator.py new file mode 100644 index 000000000..eb37c581d --- /dev/null +++ b/spp_demo_common/models/demo_data_generator.py @@ -0,0 +1,63 @@ +# Part of OpenSPP. See LICENSE file for full copyright and licensing details. +import logging + +from odoo import fields, models + +_logger = logging.getLogger(__name__) + + +class SPPDemoDataGenerator(models.Model): + _name = "spp.demo.data.generator" + _description = "SPP Demo Data Generator" + + def _default_number_of_groups(self): + default_settings = self.env["ir.config_parameter"].sudo() + return int(default_settings.get_param("spp_demo_common.number_of_groups", 10)) + + def _default_members_range_from(self): + default_settings = self.env["ir.config_parameter"].sudo() + return int(default_settings.get_param("spp_demo_common.members_range_from", 1)) + + def _default_members_range_to(self): + default_settings = self.env["ir.config_parameter"].sudo() + return int(default_settings.get_param("spp_demo_common.members_range_to", 10)) + + def _default_batch_size(self): + default_settings = self.env["ir.config_parameter"].sudo() + return int(default_settings.get_param("spp_demo_common.batch_size", 100)) + + def _default_locale_origin(self): + company_lang = self.env.user.company_id.partner_id.language + if company_lang: + lang = self.env["res.lang"].search([("code", "=", company_lang)], limit=1) + if lang: + return lang + return self.env.ref("base.lang_en") + + name = fields.Char(string="Name", required=True) + remember_settings = fields.Boolean(string="Remember Settings", default=False) + number_of_groups = fields.Integer(string="Number of Groups", default=_default_number_of_groups, required=True) + members_range_from = fields.Integer( + string="Members per Group (From)", default=_default_members_range_from, required=True + ) + members_range_to = fields.Integer(string="Members per Group (To)", default=_default_members_range_to, required=True) + locale_origin = fields.Many2one("res.lang", string="Locale Origin", required=True, default=_default_locale_origin) + batch_size = fields.Integer(string="Batch Size", default=_default_batch_size, required=True) + state = fields.Selection( + [("draft", "Draft"), ("in_progress", "In Progress"), ("completed", "Completed"), ("cancelled", "Cancelled")], + string="State", + default="draft", + required=True, + ) + locked = fields.Boolean(string="Locked", default=False) + locked_reason = fields.Text(string="Locked Reason") + + def generate_demo_data(self): + self.ensure_one() + + def refresh_page(self): + self.ensure_one() + return { + "type": "ir.actions.client", + "tag": "reload", + } diff --git a/spp_demo_common/models/res_config_settings.py b/spp_demo_common/models/res_config_settings.py new file mode 100644 index 000000000..0d347646c --- /dev/null +++ b/spp_demo_common/models/res_config_settings.py @@ -0,0 +1,22 @@ +from odoo import fields, models + + +class RegistryConfig(models.TransientModel): + _inherit = "res.config.settings" + + number_of_groups = fields.Integer( + string="Number of Groups", + config_parameter="spp_demo_common.number_of_groups", + ) + members_range_from = fields.Integer( + string="Members per Group (From)", + config_parameter="spp_demo_common.members_range_from", + ) + members_range_to = fields.Integer( + string="Members per Group (To)", + config_parameter="spp_demo_common.members_range_to", + ) + batch_size = fields.Integer( + string="Batch Size", + config_parameter="spp_demo_common.batch_size", + ) diff --git a/spp_demo_common/pyproject.toml b/spp_demo_common/pyproject.toml new file mode 100644 index 000000000..4231d0ccc --- /dev/null +++ b/spp_demo_common/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/spp_demo_common/security/ir.model.access.csv b/spp_demo_common/security/ir.model.access.csv new file mode 100644 index 000000000..d7ae2fe34 --- /dev/null +++ b/spp_demo_common/security/ir.model.access.csv @@ -0,0 +1,7 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink + +demo_data_generator_read_registry_access,Demo Data Generator Read Access,spp_demo_common.model_spp_demo_data_generator,spp_base_common.read_registry,1,0,0,0 + +demo_data_generator_write_registry_access,Demo Data Generator Write Access,spp_demo_common.model_spp_demo_data_generator,spp_base_common.write_registry,1,1,0,0 + +demo_data_generator_create_registry_access,Demo Data Generator Create Access,spp_demo_common.model_spp_demo_data_generator,spp_base_common.create_registry,1,0,1,0 diff --git a/spp_demo_common/static/description/icon.png b/spp_demo_common/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..c7dbdaaf1dace8f0ccf8c2087047ddfcf584af0c GIT binary patch literal 15480 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 + + + + view_demo_data_generator_tree + spp.demo.data.generator + 1 + + + + + + + + + + + + view_demo_data_generator_form + spp.demo.data.generator + 1 + +
+
+ +
+ +
+ Warning: Operation in progress: + +
+ +
+ +
+
+ +
+ + +
+

Demo Data Generator

+
+
+
+

+ +
+
+
+
+

+ +
+
+
+ + +
+
+
+
+
+

+ +
+
+

+ +
+
+

+ +
+
+
+
+
+
+ +
+ +
+
+ + + Generate Demo Data + ir.actions.act_window + spp.demo.data.generator + tree,form + {} + [] + +

+ Generate Dempo Data +

+ Click the create button to enter the new record. +

+
+
+ + + + tree + + + + + + + form + + + + + + +
diff --git a/spp_demo_common/views/res_config_view.xml b/spp_demo_common/views/res_config_view.xml new file mode 100644 index 000000000..687e49ee5 --- /dev/null +++ b/spp_demo_common/views/res_config_view.xml @@ -0,0 +1,45 @@ + + + + spp_demo_data_generator_config_view + res.config.settings + + + + + + + + + + + + + + + + + + + + + + + + From 6314d4e37636236733adce28f36431b5e6667974 Mon Sep 17 00:00:00 2001 From: emjay0921 Date: Tue, 30 Sep 2025 16:43:50 +0800 Subject: [PATCH 02/16] [FIX] view action --- spp_demo_common/views/demo_data_generator_view.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spp_demo_common/views/demo_data_generator_view.xml b/spp_demo_common/views/demo_data_generator_view.xml index 0b7081ce9..4ffc8aa24 100644 --- a/spp_demo_common/views/demo_data_generator_view.xml +++ b/spp_demo_common/views/demo_data_generator_view.xml @@ -139,14 +139,14 @@ tree - + form - + From 87f1e80653cd198297dd93a897093ac684a0c192 Mon Sep 17 00:00:00 2001 From: emjay0921 Date: Tue, 30 Sep 2025 16:46:07 +0800 Subject: [PATCH 03/16] [FIX] defaul lang --- spp_demo_common/models/demo_data_generator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spp_demo_common/models/demo_data_generator.py b/spp_demo_common/models/demo_data_generator.py index eb37c581d..a2abdffc0 100644 --- a/spp_demo_common/models/demo_data_generator.py +++ b/spp_demo_common/models/demo_data_generator.py @@ -27,7 +27,7 @@ def _default_batch_size(self): return int(default_settings.get_param("spp_demo_common.batch_size", 100)) def _default_locale_origin(self): - company_lang = self.env.user.company_id.partner_id.language + company_lang = self.env.user.company_id.partner_id.lang if company_lang: lang = self.env["res.lang"].search([("code", "=", company_lang)], limit=1) if lang: From c262c02837232e5c8596ee9a3aebbe5a72afdc1d Mon Sep 17 00:00:00 2001 From: emjay0921 Date: Tue, 30 Sep 2025 17:03:47 +0800 Subject: [PATCH 04/16] [ADD] fields for job queue --- .../data/ir_config_parameter_data.xml | 4 ++++ spp_demo_common/models/demo_data_generator.py | 11 +++++++++ spp_demo_common/models/res_config_settings.py | 4 ++++ .../views/demo_data_generator_view.xml | 24 +++++++++++++++++-- 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/spp_demo_common/data/ir_config_parameter_data.xml b/spp_demo_common/data/ir_config_parameter_data.xml index f92d02efd..0079499d8 100644 --- a/spp_demo_common/data/ir_config_parameter_data.xml +++ b/spp_demo_common/data/ir_config_parameter_data.xml @@ -16,4 +16,8 @@ spp_demo_common.batch_size 20 + + spp_demo_common.queue_job_minimum_size + 100 + diff --git a/spp_demo_common/models/demo_data_generator.py b/spp_demo_common/models/demo_data_generator.py index a2abdffc0..742834dbb 100644 --- a/spp_demo_common/models/demo_data_generator.py +++ b/spp_demo_common/models/demo_data_generator.py @@ -52,6 +52,11 @@ def _default_locale_origin(self): locked = fields.Boolean(string="Locked", default=False) locked_reason = fields.Text(string="Locked Reason") + queue_job_minimum_size = fields.Integer( + string="Queue Job Minimum Size", + compute="_compute_queue_job_minimum_size", + ) + def generate_demo_data(self): self.ensure_one() @@ -61,3 +66,9 @@ def refresh_page(self): "type": "ir.actions.client", "tag": "reload", } + + def _compute_queue_job_minimum_size(self): + default_settings = self.env["ir.config_parameter"].sudo() + queue_job_minimum_size = int(default_settings.get_param("spp_demo_common.queue_job_minimum_size", 100)) + for record in self: + record.queue_job_minimum_size = queue_job_minimum_size diff --git a/spp_demo_common/models/res_config_settings.py b/spp_demo_common/models/res_config_settings.py index 0d347646c..9815d1fcd 100644 --- a/spp_demo_common/models/res_config_settings.py +++ b/spp_demo_common/models/res_config_settings.py @@ -20,3 +20,7 @@ class RegistryConfig(models.TransientModel): string="Batch Size", config_parameter="spp_demo_common.batch_size", ) + queue_job_minimum_size = fields.Integer( + string="Queue Job Minimum Size", + config_parameter="spp_demo_common.queue_job_minimum_size", + ) diff --git a/spp_demo_common/views/demo_data_generator_view.xml b/spp_demo_common/views/demo_data_generator_view.xml index 4ffc8aa24..a06bc7518 100644 --- a/spp_demo_common/views/demo_data_generator_view.xml +++ b/spp_demo_common/views/demo_data_generator_view.xml @@ -62,6 +62,7 @@
+
@@ -70,7 +71,7 @@
-

@@ -92,6 +93,7 @@
+

Other Details


@@ -111,6 +113,24 @@
+
+
+
+

Warning

+

The number of groups you are trying to generate are greater than the minimum + size for Job Queues. This operation will use Job Queues to process the request in + the background. You can choose the batch size you want to batch this generation.

+
+
+

+ +
+
+
@@ -129,7 +149,7 @@ []

- Generate Dempo Data + Generate Demo Data

Click the create button to enter the new record.

From 70f5f71316253e734cc3bc3dab2f0c6aca2e1b3a Mon Sep 17 00:00:00 2001 From: emjay0921 Date: Tue, 30 Sep 2025 17:14:39 +0800 Subject: [PATCH 05/16] [IMP] fields for job queue --- .../views/demo_data_generator_view.xml | 15 +++++++++------ spp_demo_common/views/res_config_view.xml | 10 +++++++++- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/spp_demo_common/views/demo_data_generator_view.xml b/spp_demo_common/views/demo_data_generator_view.xml index a06bc7518..98bf6ce36 100644 --- a/spp_demo_common/views/demo_data_generator_view.xml +++ b/spp_demo_common/views/demo_data_generator_view.xml @@ -118,12 +118,15 @@ invisible="number_of_groups < queue_job_minimum_size" >
-
-

Warning

-

The number of groups you are trying to generate are greater than the minimum - size for Job Queues. This operation will use Job Queues to process the request in - the background. You can choose the batch size you want to batch this generation.

+
+

Job Queue will be used in this Generation

+
+
+

+

diff --git a/spp_demo_common/views/res_config_view.xml b/spp_demo_common/views/res_config_view.xml index 687e49ee5..fbfa86eb5 100644 --- a/spp_demo_common/views/res_config_view.xml +++ b/spp_demo_common/views/res_config_view.xml @@ -31,12 +31,20 @@ > + + + + + From f896e433badfdc415d0d005b2ace189227c6a5ec Mon Sep 17 00:00:00 2001 From: emjay0921 Date: Tue, 30 Sep 2025 17:18:00 +0800 Subject: [PATCH 06/16] [IMP] fields for job queue --- spp_demo_common/models/demo_data_generator.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/spp_demo_common/models/demo_data_generator.py b/spp_demo_common/models/demo_data_generator.py index 742834dbb..0c4cd0a1c 100644 --- a/spp_demo_common/models/demo_data_generator.py +++ b/spp_demo_common/models/demo_data_generator.py @@ -33,6 +33,10 @@ def _default_locale_origin(self): if lang: return lang return self.env.ref("base.lang_en") + + def _default_queue_job_minimum_size(self): + default_settings = self.env["ir.config_parameter"].sudo() + return int(default_settings.get_param("spp_demo_common.queue_job_minimum_size", 500)) name = fields.Char(string="Name", required=True) remember_settings = fields.Boolean(string="Remember Settings", default=False) @@ -54,7 +58,7 @@ def _default_locale_origin(self): queue_job_minimum_size = fields.Integer( string="Queue Job Minimum Size", - compute="_compute_queue_job_minimum_size", + default=_default_queue_job_minimum_size, ) def generate_demo_data(self): @@ -67,8 +71,3 @@ def refresh_page(self): "tag": "reload", } - def _compute_queue_job_minimum_size(self): - default_settings = self.env["ir.config_parameter"].sudo() - queue_job_minimum_size = int(default_settings.get_param("spp_demo_common.queue_job_minimum_size", 100)) - for record in self: - record.queue_job_minimum_size = queue_job_minimum_size From 00e06792d58eced85953b54028caf6bcd8f74fc6 Mon Sep 17 00:00:00 2001 From: emjay0921 Date: Wed, 1 Oct 2025 11:51:52 +0800 Subject: [PATCH 07/16] [ADD] demo data generator function --- spp_demo_common/models/demo_data_generator.py | 152 +++++++++++++++++- 1 file changed, 151 insertions(+), 1 deletion(-) diff --git a/spp_demo_common/models/demo_data_generator.py b/spp_demo_common/models/demo_data_generator.py index 0c4cd0a1c..4e4d3cb1d 100644 --- a/spp_demo_common/models/demo_data_generator.py +++ b/spp_demo_common/models/demo_data_generator.py @@ -1,5 +1,8 @@ # Part of OpenSPP. See LICENSE file for full copyright and licensing details. import logging +import random + +from faker import Faker from odoo import fields, models @@ -33,11 +36,26 @@ def _default_locale_origin(self): if lang: return lang return self.env.ref("base.lang_en") - + def _default_queue_job_minimum_size(self): default_settings = self.env["ir.config_parameter"].sudo() return int(default_settings.get_param("spp_demo_common.queue_job_minimum_size", 500)) + ID_TYPES_INDIVIDUAL = [ + "Passport", + "National ID", + ] + + ID_TYPES_GROUP = [ + "Business Permit", + "Registration Certificate", + ] + + GENDERS = [ + "Male", + "Female", + ] + name = fields.Char(string="Name", required=True) remember_settings = fields.Boolean(string="Remember Settings", default=False) number_of_groups = fields.Integer(string="Number of Groups", default=_default_number_of_groups, required=True) @@ -60,9 +78,138 @@ def _default_queue_job_minimum_size(self): string="Queue Job Minimum Size", default=_default_queue_job_minimum_size, ) + use_job_queue = fields.Boolean( + string="Use Job Queue", + compute="_compute_use_job_queue", + ) def generate_demo_data(self): self.ensure_one() + fake = Faker(self.locale_origin.code) + if not self.use_job_queue: + self.state = "in_progress" + self.locked = True + self.locked_reason = "Data generation in progress..." + for _ in range(self.number_of_groups): + group_vals = self.get_group_vals(fake) + group = self.env["res.partner"].create(group_vals) + self.create_ids(fake, group) + num_members = fake.random_int(self.members_range_from, self.members_range_to) + members = [] + have_head_member = False + for _ in range(num_members): + is_head_member = random.choice([True, False]) if not have_head_member else False + individual_vals = self.get_individual_vals(fake) + individual = self.env["g2p.individual"].create(individual_vals) + self.create_ids(fake, individual) + membership_vals = self.get_group_membership_vals(group, individual) + if is_head_member: + have_head_member = True + membership_vals["kind"] = self.env.ref("g2p_group_membership.group_membership_kind_head").id + members.append((4, membership_vals)) + if members: + self.env["g2p.group.membership"].create(members) + + self.state = "completed" + self.locked = False + self.locked_reason = "Data generation completed." + + def get_group_vals(self, fake): + registration_date = self.get_random_date( + datefrom=fields.Date.today().replace(year=fields.Date.today().year - 5), + dateto=fields.Date.today(), + ) + + group_vals = { + "name": fake.company(), + "is_registrant": True, + "is_group": True, + "registration_date": registration_date, + "create_date": registration_date, + } + + return group_vals + + def get_individual_vals(self, fake): + birth_date = self.get_random_date( + datefrom=fields.Date.today().replace(year=fields.Date.today().year - 70), + dateto=fields.Date.today().replace(year=fields.Date.today().year - 1), + ) + registration_date = self.get_random_date( + datefrom=birth_date.replace(year=birth_date.year + 1), + dateto=fields.Date.today(), + ) + gender = random.choice(self.GENDERS) + gender_id = self.get_gender_id(gender) + first_name = fake.first_name_male() if gender == "Male" else fake.first_name_female() + last_name = fake.last_name() + name = f"{first_name} {last_name}" + + individual_vals = { + "name": name, + "family_name": last_name, + "given_name": first_name, + "is_registrant": True, + "is_group": False, + "gender": gender_id, + "birthdate": birth_date, + "registration_date": registration_date, + } + return individual_vals + + def get_group_membership_vals(self, group, individual): + start_date = self.get_random_date( + datefrom=group.registration_date, + dateto=fields.Date.today(), + ) + return { + "group": group.id, + "individual": individual.id, + "start_date": start_date, + } + + def get_gender_id(self, gender): + gender_id = self.env["gender.type"].search(["|", ("value", "=", gender), ("code", "=", gender)], limit=1) + if not gender_id: + gender_id = self.env["gender.type"].create({"value": gender, "code": gender}) + return gender_id.id + + def get_gender(self, gender): + return self.env["gender.type"].search([("name", "=", gender)], limit=1).id + + def get_random_date(self, fake, datefrom, dateto): + return fake.date_between_dates(datefrom=datefrom, dateto=dateto) + + def get_id_type(self, id_type): + id_type_id = self.env["g2p.id.type"].search([("name", "=", id_type)], limit=1) + if not id_type_id: + id_type_id = self.env["g2p.id.type"].create( + { + "name": id_type, + } + ) + return id_type_id.id + + def create_ids(self, fake, registrant): + id_type = random.choice(self.ID_TYPES_GROUP if registrant.is_group else self.ID_TYPES_INDIVIDUAL) + id_type_id = self.get_id_type(id_type) + id_number = fake.bothify(text="??######") + issue_date = self.get_random_date( + datefrom=registrant.registration_date, + dateto=fields.Date.today(), + ) + id_expiry_date = self.get_random_date( + datefrom=issue_date.replace(year=issue_date.year + 1), + dateto=issue_date.replace(year=issue_date.year + 10), + ) + + id_vals = { + "partner_id": registrant.id, + "id_type": id_type_id, + "value": id_number, + "expiry_date": id_expiry_date, + } + self.env["g2p.identification"].create(id_vals) def refresh_page(self): self.ensure_one() @@ -71,3 +218,6 @@ def refresh_page(self): "tag": "reload", } + def _compute_use_job_queue(self): + for rec in self: + rec.use_job_queue = rec.number_of_groups >= rec.queue_job_minimum_size From e9b0700ac9421826a468c12e1a93643568e17147 Mon Sep 17 00:00:00 2001 From: emjay0921 Date: Wed, 1 Oct 2025 11:55:26 +0800 Subject: [PATCH 08/16] [FIX] demo data generator function --- spp_demo_common/models/demo_data_generator.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/spp_demo_common/models/demo_data_generator.py b/spp_demo_common/models/demo_data_generator.py index 4e4d3cb1d..337c67691 100644 --- a/spp_demo_common/models/demo_data_generator.py +++ b/spp_demo_common/models/demo_data_generator.py @@ -102,7 +102,7 @@ def generate_demo_data(self): individual_vals = self.get_individual_vals(fake) individual = self.env["g2p.individual"].create(individual_vals) self.create_ids(fake, individual) - membership_vals = self.get_group_membership_vals(group, individual) + membership_vals = self.get_group_membership_vals(fake, group, individual) if is_head_member: have_head_member = True membership_vals["kind"] = self.env.ref("g2p_group_membership.group_membership_kind_head").id @@ -116,6 +116,7 @@ def generate_demo_data(self): def get_group_vals(self, fake): registration_date = self.get_random_date( + fake, datefrom=fields.Date.today().replace(year=fields.Date.today().year - 5), dateto=fields.Date.today(), ) @@ -132,10 +133,12 @@ def get_group_vals(self, fake): def get_individual_vals(self, fake): birth_date = self.get_random_date( + fake, datefrom=fields.Date.today().replace(year=fields.Date.today().year - 70), dateto=fields.Date.today().replace(year=fields.Date.today().year - 1), ) registration_date = self.get_random_date( + fake, datefrom=birth_date.replace(year=birth_date.year + 1), dateto=fields.Date.today(), ) @@ -157,8 +160,9 @@ def get_individual_vals(self, fake): } return individual_vals - def get_group_membership_vals(self, group, individual): + def get_group_membership_vals(self, fake, group, individual): start_date = self.get_random_date( + fake, datefrom=group.registration_date, dateto=fields.Date.today(), ) @@ -195,10 +199,12 @@ def create_ids(self, fake, registrant): id_type_id = self.get_id_type(id_type) id_number = fake.bothify(text="??######") issue_date = self.get_random_date( + fake, datefrom=registrant.registration_date, dateto=fields.Date.today(), ) id_expiry_date = self.get_random_date( + fake, datefrom=issue_date.replace(year=issue_date.year + 1), dateto=issue_date.replace(year=issue_date.year + 10), ) From e6f55b0b82a962fa417efa4d42f9b4b0a200eff5 Mon Sep 17 00:00:00 2001 From: emjay0921 Date: Wed, 1 Oct 2025 11:58:07 +0800 Subject: [PATCH 09/16] [FIX] demo data generator function --- spp_demo_common/models/demo_data_generator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spp_demo_common/models/demo_data_generator.py b/spp_demo_common/models/demo_data_generator.py index 337c67691..41f466f79 100644 --- a/spp_demo_common/models/demo_data_generator.py +++ b/spp_demo_common/models/demo_data_generator.py @@ -182,7 +182,7 @@ def get_gender(self, gender): return self.env["gender.type"].search([("name", "=", gender)], limit=1).id def get_random_date(self, fake, datefrom, dateto): - return fake.date_between_dates(datefrom=datefrom, dateto=dateto) + return fake.date_between_dates(date_start=datefrom, date_end=dateto) def get_id_type(self, id_type): id_type_id = self.env["g2p.id.type"].search([("name", "=", id_type)], limit=1) From ef4a3a30b409c81e9ab3c88dc09cadb16b9f65d6 Mon Sep 17 00:00:00 2001 From: emjay0921 Date: Wed, 1 Oct 2025 11:59:14 +0800 Subject: [PATCH 10/16] [FIX] demo data generator function --- spp_demo_common/models/demo_data_generator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spp_demo_common/models/demo_data_generator.py b/spp_demo_common/models/demo_data_generator.py index 41f466f79..4fc93b67e 100644 --- a/spp_demo_common/models/demo_data_generator.py +++ b/spp_demo_common/models/demo_data_generator.py @@ -215,7 +215,7 @@ def create_ids(self, fake, registrant): "value": id_number, "expiry_date": id_expiry_date, } - self.env["g2p.identification"].create(id_vals) + self.env["g2p.reg.id"].create(id_vals) def refresh_page(self): self.ensure_one() From a465a5414541cd096a2461178caaa58aacc49f1f Mon Sep 17 00:00:00 2001 From: emjay0921 Date: Wed, 1 Oct 2025 12:00:13 +0800 Subject: [PATCH 11/16] [FIX] demo data generator function --- spp_demo_common/models/demo_data_generator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spp_demo_common/models/demo_data_generator.py b/spp_demo_common/models/demo_data_generator.py index 4fc93b67e..234c8f2ec 100644 --- a/spp_demo_common/models/demo_data_generator.py +++ b/spp_demo_common/models/demo_data_generator.py @@ -100,7 +100,7 @@ def generate_demo_data(self): for _ in range(num_members): is_head_member = random.choice([True, False]) if not have_head_member else False individual_vals = self.get_individual_vals(fake) - individual = self.env["g2p.individual"].create(individual_vals) + individual = self.env["res.partner"].create(individual_vals) self.create_ids(fake, individual) membership_vals = self.get_group_membership_vals(fake, group, individual) if is_head_member: From 29a4519bb49e2986c95b6bb897cd9d22efb58f76 Mon Sep 17 00:00:00 2001 From: emjay0921 Date: Wed, 1 Oct 2025 12:02:40 +0800 Subject: [PATCH 12/16] [FIX] demo data generator function --- spp_demo_common/models/demo_data_generator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spp_demo_common/models/demo_data_generator.py b/spp_demo_common/models/demo_data_generator.py index 234c8f2ec..066f0cb4b 100644 --- a/spp_demo_common/models/demo_data_generator.py +++ b/spp_demo_common/models/demo_data_generator.py @@ -105,7 +105,7 @@ def generate_demo_data(self): membership_vals = self.get_group_membership_vals(fake, group, individual) if is_head_member: have_head_member = True - membership_vals["kind"] = self.env.ref("g2p_group_membership.group_membership_kind_head").id + membership_vals["kind"] = [(4, self.env.ref("g2p_registry_membership.group_membership_kind_head").id)] members.append((4, membership_vals)) if members: self.env["g2p.group.membership"].create(members) From 8060a93a90470eefc84c200a57b7e5b9e0006ac7 Mon Sep 17 00:00:00 2001 From: emjay0921 Date: Wed, 1 Oct 2025 12:07:18 +0800 Subject: [PATCH 13/16] [FIX] demo data generator function --- spp_demo_common/models/demo_data_generator.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/spp_demo_common/models/demo_data_generator.py b/spp_demo_common/models/demo_data_generator.py index 066f0cb4b..adb44fd18 100644 --- a/spp_demo_common/models/demo_data_generator.py +++ b/spp_demo_common/models/demo_data_generator.py @@ -95,7 +95,6 @@ def generate_demo_data(self): group = self.env["res.partner"].create(group_vals) self.create_ids(fake, group) num_members = fake.random_int(self.members_range_from, self.members_range_to) - members = [] have_head_member = False for _ in range(num_members): is_head_member = random.choice([True, False]) if not have_head_member else False @@ -106,9 +105,7 @@ def generate_demo_data(self): if is_head_member: have_head_member = True membership_vals["kind"] = [(4, self.env.ref("g2p_registry_membership.group_membership_kind_head").id)] - members.append((4, membership_vals)) - if members: - self.env["g2p.group.membership"].create(members) + self.env["g2p.group.membership"].create(membership_vals) self.state = "completed" self.locked = False From 38f0b83ef31f88a6e3545875d436b26aa9c2541d Mon Sep 17 00:00:00 2001 From: emjay0921 Date: Wed, 1 Oct 2025 12:15:11 +0800 Subject: [PATCH 14/16] [FIX] add address --- spp_demo_common/models/demo_data_generator.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spp_demo_common/models/demo_data_generator.py b/spp_demo_common/models/demo_data_generator.py index adb44fd18..a8d9dcbb4 100644 --- a/spp_demo_common/models/demo_data_generator.py +++ b/spp_demo_common/models/demo_data_generator.py @@ -117,6 +117,7 @@ def get_group_vals(self, fake): datefrom=fields.Date.today().replace(year=fields.Date.today().year - 5), dateto=fields.Date.today(), ) + address = fake.address() group_vals = { "name": fake.company(), @@ -124,6 +125,7 @@ def get_group_vals(self, fake): "is_group": True, "registration_date": registration_date, "create_date": registration_date, + "address": address, } return group_vals @@ -145,6 +147,8 @@ def get_individual_vals(self, fake): last_name = fake.last_name() name = f"{first_name} {last_name}" + address = fake.address() + individual_vals = { "name": name, "family_name": last_name, @@ -154,6 +158,8 @@ def get_individual_vals(self, fake): "gender": gender_id, "birthdate": birth_date, "registration_date": registration_date, + "create_date": registration_date, + "address": address, } return individual_vals From bea9dd945005fcb022c1f156c5b7bef3b10e7503 Mon Sep 17 00:00:00 2001 From: emjay0921 Date: Wed, 1 Oct 2025 12:23:35 +0800 Subject: [PATCH 15/16] [FIX] add phone numbers --- spp_demo_common/models/demo_data_generator.py | 38 +++++++++++++++---- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/spp_demo_common/models/demo_data_generator.py b/spp_demo_common/models/demo_data_generator.py index a8d9dcbb4..8e8af2bdd 100644 --- a/spp_demo_common/models/demo_data_generator.py +++ b/spp_demo_common/models/demo_data_generator.py @@ -91,16 +91,12 @@ def generate_demo_data(self): self.locked = True self.locked_reason = "Data generation in progress..." for _ in range(self.number_of_groups): - group_vals = self.get_group_vals(fake) - group = self.env["res.partner"].create(group_vals) - self.create_ids(fake, group) + group = self.generate_groups(fake) num_members = fake.random_int(self.members_range_from, self.members_range_to) have_head_member = False for _ in range(num_members): is_head_member = random.choice([True, False]) if not have_head_member else False - individual_vals = self.get_individual_vals(fake) - individual = self.env["res.partner"].create(individual_vals) - self.create_ids(fake, individual) + individual = self.generate_individuals(fake) membership_vals = self.get_group_membership_vals(fake, group, individual) if is_head_member: have_head_member = True @@ -111,6 +107,20 @@ def generate_demo_data(self): self.locked = False self.locked_reason = "Data generation completed." + def generate_groups(self, fake): + group_vals = self.get_group_vals(fake) + group = self.env["res.partner"].create(group_vals) + self.create_ids(fake, group) + self.create_phone_numbers(fake, group) + return group + + def generate_individuals(self, fake): + individual_vals = self.get_individual_vals(fake) + individual = self.env["res.partner"].create(individual_vals) + self.create_ids(fake, individual) + self.create_phone_numbers(fake, individual) + return individual + def get_group_vals(self, fake): registration_date = self.get_random_date( fake, @@ -148,7 +158,7 @@ def get_individual_vals(self, fake): name = f"{first_name} {last_name}" address = fake.address() - + individual_vals = { "name": name, "family_name": last_name, @@ -219,6 +229,20 @@ def create_ids(self, fake, registrant): "expiry_date": id_expiry_date, } self.env["g2p.reg.id"].create(id_vals) + + def create_phone_numbers(self, fake, registrant): + phone_number = fake.phone_number() + date_collected = self.get_random_date( + fake, + datefrom=registrant.registration_date, + dateto=fields.Date.today(), + ) + phone_vals = { + "partner_id": registrant.id, + "phone_no": phone_number, + "date_collected": date_collected, + } + self.env["g2p.phone.number"].create(phone_vals) def refresh_page(self): self.ensure_one() From c1628f9827a3eccf2675f97862f14f5eda199e4c Mon Sep 17 00:00:00 2001 From: emjay0921 Date: Thu, 2 Oct 2025 11:04:33 +0800 Subject: [PATCH 16/16] [FIX] demo data generator --- spp_demo_common/models/demo_data_generator.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/spp_demo_common/models/demo_data_generator.py b/spp_demo_common/models/demo_data_generator.py index 8e8af2bdd..e2dcb10be 100644 --- a/spp_demo_common/models/demo_data_generator.py +++ b/spp_demo_common/models/demo_data_generator.py @@ -100,7 +100,9 @@ def generate_demo_data(self): membership_vals = self.get_group_membership_vals(fake, group, individual) if is_head_member: have_head_member = True - membership_vals["kind"] = [(4, self.env.ref("g2p_registry_membership.group_membership_kind_head").id)] + membership_vals["kind"] = [ + (4, self.env.ref("g2p_registry_membership.group_membership_kind_head").id) + ] self.env["g2p.group.membership"].create(membership_vals) self.state = "completed" @@ -113,7 +115,7 @@ def generate_groups(self, fake): self.create_ids(fake, group) self.create_phone_numbers(fake, group) return group - + def generate_individuals(self, fake): individual_vals = self.get_individual_vals(fake) individual = self.env["res.partner"].create(individual_vals) @@ -229,7 +231,7 @@ def create_ids(self, fake, registrant): "expiry_date": id_expiry_date, } self.env["g2p.reg.id"].create(id_vals) - + def create_phone_numbers(self, fake, registrant): phone_number = fake.phone_number() date_collected = self.get_random_date(