New application, new listing and capture review store any three characters as the salary currency #446

Closed
opened 2026-10-01 10:46:46 +00:00 by tiagoagueda · 0 comments
Owner

Found on 2026-09-29 in a read-only review of postulo at 95348908d, following salary_currency from each form to the database and checking the result with a unit test against the snapshot.

Checked again on 2026-10-01 against main at 0a5cad587: still present.

#224 gave JobPosting.salary_currency a validator, jobs.models.currency_code ("three letters, upper case"). The forms that create most listings never run it: PostingIntakeForm declares its own plain CharField, and create_listing saves with JobPosting.objects.create(), which does not call model validators. The API's listing schema has the same gap. A value the validator refuses is therefore stored, and the listing's own edit form then refuses to save until it is corrected.

Related to #224 (closed), which asked for currency codes to be validated; the validator reached the model and JobPostingForm, not these routes.

  • Where: applications/forms.py:148-154 (PostingIntakeForm.salary_currency, no validator), applications/forms.py:208-227 (posting_data), applications/services.py:245-248 (create_listing); used by applications:create (ApplicationIntakeForm), jobs/listing_views.py:210-225 (new listing) and jobs/capture_views.py:198-200, 350 (CaptureReviewForm). Also api/schemas.py:279 (ListingIn.salary_currency, max_length=3 only), saved through api/routers/listings.py:181.
  • What happens: a person types eu1 in the currency box when recording an application. JobPosting.save upper-cases it and EU1 is stored. Checked: applications:create with salary_currency="eu1" answered with a redirect and stored EU1; posting.full_clean() then raises "EU1 is not a currency code. Use three letters, like EUR."
  • Why it matters: the listing's edit form later refuses to save on a field the person did not touch, the offer form opens pre-filled with the bad code, and the salary columns sort and group on a currency that does not exist, which is what #224 set out to stop.
  • Fix: give PostingIntakeForm.salary_currency validators=[currency_code] and a clean_salary_currency that strips and upper-cases the value before the validator runs (as OfferForm.clean_currency does); add the same check to ListingIn with a field validator. Optionally call full_clean() in create_listing so every route, including the CSV import, is held to the model.

Done when

  • tests/test_applications.py has a test that posts salary_currency="eu1" to applications:create and gets the form back with an error on the currency, and one that posts "eur" and stores EUR; tests/test_api.py has the same refusal for the listing endpoint.
Found on 2026-09-29 in a read-only review of postulo at 95348908d, following `salary_currency` from each form to the database and checking the result with a unit test against the snapshot. Checked again on 2026-10-01 against `main` at `0a5cad587`: still present. #224 gave `JobPosting.salary_currency` a validator, `jobs.models.currency_code` ("three letters, upper case"). The forms that create most listings never run it: `PostingIntakeForm` declares its own plain `CharField`, and `create_listing` saves with `JobPosting.objects.create()`, which does not call model validators. The API's listing schema has the same gap. A value the validator refuses is therefore stored, and the listing's own edit form then refuses to save until it is corrected. Related to #224 (closed), which asked for currency codes to be validated; the validator reached the model and `JobPostingForm`, not these routes. - **Where:** `applications/forms.py:148-154` (`PostingIntakeForm.salary_currency`, no validator), `applications/forms.py:208-227` (`posting_data`), `applications/services.py:245-248` (`create_listing`); used by `applications:create` (`ApplicationIntakeForm`), `jobs/listing_views.py:210-225` (new listing) and `jobs/capture_views.py:198-200, 350` (`CaptureReviewForm`). Also `api/schemas.py:279` (`ListingIn.salary_currency`, `max_length=3` only), saved through `api/routers/listings.py:181`. - **What happens:** a person types `eu1` in the currency box when recording an application. `JobPosting.save` upper-cases it and `EU1` is stored. Checked: `applications:create` with `salary_currency="eu1"` answered with a redirect and stored `EU1`; `posting.full_clean()` then raises "EU1 is not a currency code. Use three letters, like EUR." - **Why it matters:** the listing's edit form later refuses to save on a field the person did not touch, the offer form opens pre-filled with the bad code, and the salary columns sort and group on a currency that does not exist, which is what #224 set out to stop. - **Fix:** give `PostingIntakeForm.salary_currency` `validators=[currency_code]` and a `clean_salary_currency` that strips and upper-cases the value before the validator runs (as `OfferForm.clean_currency` does); add the same check to `ListingIn` with a field validator. Optionally call `full_clean()` in `create_listing` so every route, including the CSV import, is held to the model. ## Done when - `tests/test_applications.py` has a test that posts `salary_currency="eu1"` to `applications:create` and gets the form back with an error on the currency, and one that posts `"eur"` and stores `EUR`; `tests/test_api.py` has the same refusal for the listing endpoint.
tiagoagueda added this to the 0.6.0 milestone 2026-10-01 10:46:46 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo#446
No description provided.