Document stores: the kind's name follows whoever triggers the send, so one kind is filed under several names #605

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

Found on 2026-09-29 in a read-only review of postulo at 95348908d and postulo-paperless at 973969bb7, following DocumentMetadata.kind_label from where it is resolved to where the Paperless store uses it.

Checked again on 2026-10-01 against main at 0a5cad587: still present. The code is now at documents/kinds.py:128 (label_for), with the labels declared at documents/kinds.py:155-182, and the scheduler's call at notifications/management/commands/send_due_reminders.py:196; the other locations are unchanged.

A store is handed the document's kind in words (kind_label), and those words are resolved in whatever language happens to be active when the copy is sent. The scheduler has no language, so it uses LANGUAGE_CODE; Send to stores now runs inside a request, so it uses the person's interface language. A store that files by that name files the same kind under two names.

  • Where: documents/stores.py:89 (kind_label=kinds.label_for(document.kind)) and documents/kinds.py:109 (return str(kind.label) if kind else key), with the labels declared through gettext_lazy (documents/kinds.py:137-164). metadata_for is called from send_copy (documents/archiving.py:136), which sets no language; send_copy is reached from the scheduler (notifications/management/commands/send_due_reminders.py:194) and from the Send to stores now view (documents/views.py:714). documents/archiving.py contains no translation.override. In postulo-paperless, src/postulo_paperless/store.py:319 creates or finds the Paperless document type by that name, and compose_title (src/postulo_paperless/store.py:100) puts it in the title of every render.
  • What happens: a person reads Postulo in French on an instance whose LANGUAGE_CODE is en-gb. The cover letters the scheduler sends are filed in Paperless under the document type "Cover letter". One sent with Send to stores now is filed under "Lettre de motivation", which Archive.ensure creates because no type of that name exists. Filtering by document type in Paperless then shows part of the letters under each, and the split grows with every manual send. The sentences send_copy stores in last_error (documents/archiving.py:124-131) and the plugin's own error sentences vary in the same way.
  • Why it matters: the copy exists so that a document can be found again, and the document type is what a Paperless user filters by. The WebDAV store planned in postulo/postulo-dav#5 intends to name folders from kind_label and would split them the same way.
  • Fix: resolve everything a store is told in one fixed language per person. In send_copy, wrap the call to plugin.put(...) and metadata_for(document) in translation.override(language_for(document.owner)), as notify already does (notifications/service.py:49-50). That makes the name the same whichever path sends the copy, and puts the error sentences in the owner's language as well.

Related to #223 (closed), which moved DocumentMetadata.language to the document's own language and made notifications speak the recipient's language, but left the kind's label and the store's sentences following the request.

Done when

  • A test in tests/test_stores.py sends one copy with send_pending() and another of the same kind with send_now() while a different language is active, for an owner whose profile language is French, and asserts that the store received the same kind_label both times, in the owner's language. It fails today.
Found on 2026-09-29 in a read-only review of postulo at 95348908d and postulo-paperless at 973969bb7, following `DocumentMetadata.kind_label` from where it is resolved to where the Paperless store uses it. Checked again on 2026-10-01 against `main` at `0a5cad587`: still present. The code is now at `documents/kinds.py:128` (`label_for`), with the labels declared at `documents/kinds.py:155-182`, and the scheduler's call at `notifications/management/commands/send_due_reminders.py:196`; the other locations are unchanged. A store is handed the document's kind in words (`kind_label`), and those words are resolved in whatever language happens to be active when the copy is sent. The scheduler has no language, so it uses `LANGUAGE_CODE`; *Send to stores now* runs inside a request, so it uses the person's interface language. A store that files by that name files the same kind under two names. - **Where:** `documents/stores.py:89` (`kind_label=kinds.label_for(document.kind)`) and `documents/kinds.py:109` (`return str(kind.label) if kind else key`), with the labels declared through `gettext_lazy` (`documents/kinds.py:137-164`). `metadata_for` is called from `send_copy` (`documents/archiving.py:136`), which sets no language; `send_copy` is reached from the scheduler (`notifications/management/commands/send_due_reminders.py:194`) and from the *Send to stores now* view (`documents/views.py:714`). `documents/archiving.py` contains no `translation.override`. In postulo-paperless, `src/postulo_paperless/store.py:319` creates or finds the Paperless document type by that name, and `compose_title` (`src/postulo_paperless/store.py:100`) puts it in the title of every render. - **What happens:** a person reads Postulo in French on an instance whose `LANGUAGE_CODE` is `en-gb`. The cover letters the scheduler sends are filed in Paperless under the document type "Cover letter". One sent with *Send to stores now* is filed under "Lettre de motivation", which `Archive.ensure` creates because no type of that name exists. Filtering by document type in Paperless then shows part of the letters under each, and the split grows with every manual send. The sentences `send_copy` stores in `last_error` (`documents/archiving.py:124-131`) and the plugin's own error sentences vary in the same way. - **Why it matters:** the copy exists so that a document can be found again, and the document type is what a Paperless user filters by. The WebDAV store planned in postulo/postulo-dav#5 intends to name folders from `kind_label` and would split them the same way. - **Fix:** resolve everything a store is told in one fixed language per person. In `send_copy`, wrap the call to `plugin.put(...)` and `metadata_for(document)` in `translation.override(language_for(document.owner))`, as `notify` already does (`notifications/service.py:49-50`). That makes the name the same whichever path sends the copy, and puts the error sentences in the owner's language as well. Related to #223 (closed), which moved `DocumentMetadata.language` to the document's own language and made notifications speak the recipient's language, but left the kind's label and the store's sentences following the request. ## Done when - A test in `tests/test_stores.py` sends one copy with `send_pending()` and another of the same kind with `send_now()` while a different language is active, for an owner whose profile language is French, and asserts that the store received the same `kind_label` both times, in the owner's language. It fails today.
tiagoagueda added this to the 0.6.0 milestone 2026-10-01 10:48:20 +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#605
No description provided.