Skip to content

spp_registry: future birthdate accepted via ORM/import/API, yields negative computed age #362

Description

@gonzalesedwin1123

Problem

res.partner.birthdate (spp_registry/models/individual.py) accepts dates in the future when set through any path other than the web form:

  • direct ORM calls — partner.write({"birthdate": date(2030, 1, 1)})
  • create() vals
  • CSV/Excel import
  • API calls (XML-RPC, API v2, DCI endpoints)

The only existing guard is _birthdate_onchange, which runs exclusively in the form UI (it resets the field and shows a warning). Onchange never executes for ORM/import/API writes, so a future birthdate persists.

Once stored, the non-stored computed age field (compute_age_from_dates: relativedelta(now, dob)) yields negative years and renders as a negative string such as "-3" in views, exports, and anything else reading age.

Background

Pre-existing behavior, documented as out of scope in PR #357. That PR removed a dead @api.constrains("age") guard that looked like it covered this but never executed (constrains hooks don't fire on non-stored computes — the removal is behavior-preserving). No @api.constrains on birthdate exists anywhere in the repo; the only related check is registration_date >= birthdate in spp_registry/models/registrant.py, which does not reject future birthdates.

Proposed fix

Add to spp_registry/models/individual.py:

@api.constrains("birthdate")
def _check_birthdate_not_future(self):
    for record in self:
        if record.birthdate and record.birthdate > fields.Date.today():
            raise ValidationError(_("Date of birth cannot be in the future."))

birthdate is a stored, writeable field, so the constraint fires on every create/write path and produces no registry-load warning.

Considerations

  • Existing bad data: a constraint only validates on write; records that already hold a future birthdate stay invalid until touched — and would then block otherwise-unrelated writes. Pair the fix with a data-quality check (or migration note) for deployed databases.
  • birthdate_not_exact ("Approximate Birthdate"): presumably even an approximate birthdate must not be in the future, but confirm as a product decision.
  • _birthdate_onchange: keep it — the silent-reset UX in the form is friendlier than a raised ValidationError; the constraint is the server-side backstop.
  • Follow the standard fix process: version bump + readme/HISTORY.md fragment + README regen, and tests covering create/write/import paths (TDD: failing test first).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions