From 406f353b98843a2d5330e7cff12c4610b53027d0 Mon Sep 17 00:00:00 2001 From: Suherdy Yacob Date: Sun, 31 May 2026 22:24:55 +0700 Subject: [PATCH] refactor: replace custom employee_pin field with Odoo's standard pin field and update UI for inline regeneration --- README.md | 41 ++++++++++++--------------------- models/hr_employee.py | 22 ++++++------------ views/hr_employee_views.xml | 12 +++++----- wizard/regenerate_pin_wizard.py | 2 +- 4 files changed, 29 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index a96261d..713cf39 100644 --- a/README.md +++ b/README.md @@ -1,52 +1,41 @@ Employee PIN Generator ====================== -.. contents:: - :local: - :depth: 1 - -Overview --------- - -This Odoo 19 module automatically assigns a unique, randomly generated 6-digit PIN to every employee record. The PIN is enforced to be globally unique across **all companies** in the same Odoo database via a SQL UNIQUE constraint. +This Odoo 19 module automatically assigns a unique, randomly generated 6-digit PIN to every employee record using Odoo's standard PIN Code field. The PIN is enforced to be globally unique across all companies in the database via a SQL UNIQUE constraint. Features -------- -- Auto-generates a 6-digit numeric PIN when a new employee is created. -- PIN uniqueness is enforced at the database level (UNIQUE constraint on ``employee_pin``). -- No two employees — even in different companies — can share the same PIN. -- A **Regenerate PIN** button is available on the employee form (Private Information tab) for HR managers and users. -- A confirmation wizard is shown before replacing the current PIN, displaying the existing value. +- Auto-generates a unique 6-digit numeric PIN when a new employee is created. +- Reuses Odoo's standard PIN Code field (used in Point of Sale and HR Attendance). +- PIN uniqueness is enforced at the database level across all companies. +- A Regenerate PIN button is available inline with the PIN Code field on the employee form. +- A confirmation wizard is shown before replacing the current PIN. Technical Details ----------------- -- Model extended: ``hr.employee`` -- New field: ``employee_pin`` (Char, size 6, unique) -- New transient model: ``hr.employee.regenerate.pin.wizard`` -- PIN generation retries up to 1,000 times to avoid collision in a crowded pool. +- Model extended: hr.employee +- Field modified: pin (Odoo's standard PIN Code) +- New transient model: hr.employee.regenerate.pin.wizard +- PIN generation retries up to 1,000 times to avoid collision. Installation ------------ -1. Copy ``hr_employee_pin`` into your custom addons path. -2. Update the addons list in Odoo (Settings → Activate Developer Mode → Update App List). -3. Install **Employee PIN Generator** from the Apps menu. -4. Existing employees will NOT receive a PIN automatically — use the **Regenerate PIN** button on each record, or run a one-time migration script. +1. Copy hr_employee_pin into your custom addons path. +2. Update the addons list in Odoo. +3. Install Employee PIN Generator. Usage ----- -When creating a new employee the PIN is generated automatically and shown in the **Private Information** tab under the *Employee PIN* section. - To regenerate the PIN: 1. Open an employee record. -2. Go to the **Private Information** tab. -3. Find the *Employee PIN* section and click **Regenerate PIN**. +2. Go to the Settings tab under the Attendance/Point of Sale section. +3. Click the Regenerate PIN button inline with the PIN Code field. 4. Confirm in the dialog. -5. A success notification will show the new PIN. Author ------ diff --git a/models/hr_employee.py b/models/hr_employee.py index 82baba9..f4cbc8e 100644 --- a/models/hr_employee.py +++ b/models/hr_employee.py @@ -10,19 +10,11 @@ _logger = logging.getLogger(__name__) class HrEmployee(models.Model): _inherit = 'hr.employee' - employee_pin = fields.Char( - string='Employee PIN', - size=6, - copy=False, - help='Unique 6-digit PIN for this employee. ' - 'Globally unique across all companies.', - ) - _sql_constraints = [ ( - 'employee_pin_unique', - 'UNIQUE(employee_pin)', - 'The Employee PIN must be unique across all employees and companies.', + 'pin_unique', + 'UNIQUE(pin)', + 'The Employee PIN Code must be unique across all employees and companies.', ) ] @@ -34,7 +26,7 @@ class HrEmployee(models.Model): def _generate_unique_pin(self): """Return a random 6-digit string that is not yet used by any employee.""" existing = set( - self.sudo().search([('employee_pin', '!=', False)]).mapped('employee_pin') + self.sudo().search([('pin', '!=', False)]).mapped('pin') ) for _attempt in range(1000): pin = '{:06d}'.format(random.randint(0, 999999)) @@ -52,8 +44,8 @@ class HrEmployee(models.Model): @api.model_create_multi def create(self, vals_list): for vals in vals_list: - if not vals.get('employee_pin'): - vals['employee_pin'] = self._generate_unique_pin() + if not vals.get('pin'): + vals['pin'] = self._generate_unique_pin() return super().create(vals_list) # ------------------------------------------------------------------ @@ -64,7 +56,7 @@ class HrEmployee(models.Model): """Regenerate a new unique PIN for this employee (called from button).""" self.ensure_one() new_pin = self._generate_unique_pin() - self.employee_pin = new_pin + self.pin = new_pin return { 'type': 'ir.actions.client', 'tag': 'display_notification', diff --git a/views/hr_employee_views.xml b/views/hr_employee_views.xml index 26554a1..57a0cff 100644 --- a/views/hr_employee_views.xml +++ b/views/hr_employee_views.xml @@ -8,16 +8,16 @@ - - - -
+ + + diff --git a/wizard/regenerate_pin_wizard.py b/wizard/regenerate_pin_wizard.py index d299bdc..1b48652 100644 --- a/wizard/regenerate_pin_wizard.py +++ b/wizard/regenerate_pin_wizard.py @@ -15,7 +15,7 @@ class RegeneratePinWizard(models.TransientModel): ) current_pin = fields.Char( string='Current PIN', - related='employee_id.employee_pin', + related='employee_id.pin', readonly=True, )