Skip to content

fix(spp_registry): bound registration_date and the birthdate onchange by the user's today (#520) - #533

Open
gonzalesedwin1123 wants to merge 3 commits into
19.0from
fix-520-registration-date-user-tz
Open

gonzalesedwin1123 wants to merge 3 commits into
19.0from
fix-520-registration-date-user-tz

Conversation

@gonzalesedwin1123

@gonzalesedwin1123 gonzalesedwin1123 commented Sep 21, 2026

Copy link
Copy Markdown
Member

Fixes #520. Finishes the job #397 started when it moved _check_birthdate_not_future to fields.Date.context_today.

Problem

Three sibling sites still compared against the server's UTC date, so a registrar east of UTC (on tomorrow's date for part of each day) was refused a registrant born earlier that local day:

  • registrant.py registration_date defaulted to fields.Date.today(): the defaulted registration date was the server's yesterday relative to the birthdate, so _check_registration_date failed with "must be later than the birth date".
  • registrant.py _check_registration_date bounded the field by date.today(): entering the correct local date was refused as "future".
  • individual.py _birthdate_onchange compared to fields.Date.today(): it silently reset the valid birthdate in the form. West of UTC it did the opposite, keeping the user's tomorrow only for the Fix/362 birthdate not future #397 constraint to refuse it on save.

Fix

All three use fields.Date.context_today(record). No schema change, no migration. spp_registry 19.0.2.2.4 → 19.0.2.2.6 with a HISTORY fragment; 2.2.5 is taken by the unmerged #522, whichever lands second renumbers. README/index.html left for CI's pinned generator.

Tests (tests/test_constraints.py, new class TestUserTodayAcrossTimezones, 8 tests)

The clock is frozen with freezegun (ships with Odoo) so the tests are deterministic at any wall-clock hour; the frozen instant is derived from the real date so nothing ages. Timezone is set with with_context(tz=...), which env.tz honours. Every test first asserts that the frozen clock and tz context really shift the user's today by one day, so none can pass by collapsing onto the server date.

East of UTC (Asia/Manila at 23:00 UTC), the relaxing direction:

  1. create with birthdate = user's today and no registration_date → succeeds, registration_date == user's today;
  2. write registration_date = user's today → accepted;
  3. registration_date = user's today + 1 → still refused;
  4. onchange with birthdate = user's today → kept, no warning.

West of UTC (America/Los_Angeles at 05:00 UTC), the direction where the bound moved a day earlier:
5. the default follows the user: registration_date == user's today (a day behind the server), coexisting with a past birthdate;
6. registration_date = server's today (the user's tomorrow) → refused, by design; this is the one value accepted before and refused now;
7. onchange with birthdate = server's today → reset with warning, matching the #397 constraint;
8. onchange on a saved record restores the saved birthdate (the _origin branch).

The pre-existing TestRegistrationDateConstraint tests now anchor on context_today like the code under test, as #397 did for the birthdate tests; on the server date they were green only because the test user has no timezone.

Pre-fix: 1, 2, 4, 7 fail with exactly the errors described in the issue. Post-fix: 0 failed, 0 error(s) of 293 tests. All pre-commit hooks pass on the changed files.

Review notes (adversarial review run before marking ready)

  • No in-repo writer can hit the moved bound: the demo generators' local registration_date feeds create_date only or uses days_back ≥ 2, seeded_volume_generator backdates by 30–730 days, and no API v2 / change-request / DCI path writes registration_date. The registration_date < birthdate branch carries exactly the risk profile Fix/362 birthdate not future #397 already introduced.
  • env.tz honours a caller-supplied context['tz'] ahead of the user's profile, so an RPC caller can move the bound by up to a day (UTC+14). Inherited from Fix/362 birthdate not future #397's birthdate rule; not security-relevant, recorded as a conscious trade-off.
  • The form is unaffected by the multi-timezone asymmetry described in HISTORY because registration_date is read-only there once defaulted (views/individual_views.xml); the exposure is API/import writes.
  • The age compute still uses the server's now; relativedelta clamps at 0 so no negative age. Cosmetic, listed in Remaining "not in the future" date bounds compare against the server date, not the user's today (follow-up to #520) #534.

Noted, not changed → #534

Same-class server-date bounds elsewhere are filed as #534: phone_number.py date_collected (same module, same form), spp_programs cycle start_date, spp_dci_client_crvs event_date, spp_dci_client_dr assessment_date, plus the untranslated / boundary-inaccurate messages in _check_registration_date and the demo generators' dateto=fields.Date.today() tidy-up.

Version ordering: 2.2.5 belongs to the unmerged #522; whichever of #522/#533 lands second renumbers and re-applies CI's README diff.

… by the user's today

The registration_date default used fields.Date.today() and
_check_registration_date compared against date.today(), so a registrar
east of UTC creating a registrant born earlier that local day was
refused: the defaulted registration date was the server's yesterday,
and entering the correct date was refused as future. _birthdate_onchange
used the same server date and reset the valid birthdate in the form.
All three now use fields.Date.context_today, the rule #397 gave
_check_birthdate_not_future.

Fixes #520
@codecov

codecov Bot commented Sep 21, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 76.88%. Comparing base (1a3c591) to head (98b4af5).

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             19.0     #533      +/-   ##
==========================================
- Coverage   76.91%   76.88%   -0.03%     
==========================================
  Files         704      740      +36     
  Lines       45774    48023    +2249     
==========================================
+ Hits        35205    36922    +1717     
- Misses      10569    11101     +532     
Flag Coverage Δ
spp_analytics 93.25% <ø> (ø)
spp_api_v2 79.99% <ø> (ø)
spp_api_v2_change_request 73.37% <ø> (ø)
spp_api_v2_cycles 71.03% <ø> (ø)
spp_api_v2_data 77.77% <ø> (ø)
spp_api_v2_entitlements 70.23% <ø> (ø)
spp_api_v2_gis 74.60% <ø> (ø)
spp_api_v2_products 65.86% <ø> (ø)
spp_api_v2_programs 92.22% <ø> (ø)
spp_api_v2_service_points 71.03% <ø> (ø)
spp_api_v2_simulation 71.19% <ø> (ø)
spp_api_v2_vocabulary 57.75% <ø> (?)
spp_approval 50.85% <ø> (ø)
spp_area 80.16% <ø> (?)
spp_area_hdx 81.60% <ø> (?)
spp_audit 72.13% <ø> (?)
spp_base_common 91.07% <ø> (ø)
spp_programs 67.58% <ø> (ø)
spp_registry 88.99% <100.00%> (-0.02%) ⬇️
spp_security 69.56% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
spp_registry/models/individual.py 90.09% <100.00%> (ø)
spp_registry/models/registrant.py 97.67% <100.00%> (-0.03%) ⬇️

... and 36 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

- TestRegistrationDateConstraint anchors on context_today like the code
  under test (mirrors #397's fix to the birthdate tests)
- every timezone test asserts the frozen clock and tz context are in
  effect, so none can pass by collapsing onto the server date
- cover the west-of-UTC direction, where the bound moved a day earlier
  (server's today refused, default follows the user)
- cover the onchange's restore-previous branch on a saved record
- constraint rationale moved into a docstring; HISTORY describes the
  read-only form field accurately and adds a multi-timezone note
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

spp_registry: registration_date default and _birthdate_onchange still use the server date, refusing valid births east of UTC

1 participant