Skip to content

T3178 biennial picture date - #2165

Open
danpa32 wants to merge 8 commits into
18.0from
T3178-biennial-picture-date
Open

danpa32 wants to merge 8 commits into
18.0from
T3178-biennial-picture-date

Conversation

@danpa32

@danpa32 danpa32 commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

T3178 — Biennial report not generated

Branch: T3178-biennial-picture-date (repo: compassion-modules, modules child_compassion and partner_communication_compassion, off origin/18.0). v18 only.

Original report

Some new child photos were not handled as a biennial: the photo was not ordered and no communication was generated to send it to the sponsor. Example: child KE073400410 (sponsor ref 1551364).

A "biennial" is the new photo Compassion International takes of each child about every two years. When it arrives, new_photo() prepares the "New Biennial" communication for the sponsor and marks the sponsorship "new picture" so the printed photo is ordered for sponsors receiving photos by post.

Root cause

update_child_pictures() (child_compassion/models/child_compassion.py) only calls new_photo() when the latest picture is at least 6 months after the previous one (and at most 6 months old).

A picture is dated with the child's photo date, or with today if it is not known yet (child_pictures._get_picture). When a child is fetched for the first time, its pictures are fetched before the child details, on purpose ("directly fetch picture to have it before get_infos"), so the first picture of every child gets its download date.

For KE073400410:

Picture Stored date Publish date (from the picture URL)
1st 2025-12-02 (download, child taken for sponsorship) 2024-08-06 (.../v1722936507/...)
2nd 2026-05-06 2026-05-06 (.../v1778056903/...)

Real gap about 21 months, stored gap 5 months: no biennial. On the v14 database, about 710 children with a latest picture since 2025 were affected this way (479 currently sponsored).

Fix

  1. child_compassion: when the photo date is not known, a picture is dated with the publish date contained in its URL (the media server URL holds the upload timestamp), and only then with today. The new photo check is split from update_child_pictures() into _check_new_photo(), so it can run without fetching pictures.

  2. partner_communication_compassion 18.0.1.0.7, end migration (catch-up):

    • pictures dated with their download day but published before are dated with their publish date
    • children already in a "New Biennial" communication (sent, pending or failed) since their last picture came are skipped, so the sponsor does not receive the same picture twice
    • for the other children, the biennials still due (new photo at most 6 months old on the day of the upgrade, not handled yet) are prepared
    • the communications are created pending, without automatic sending (default_auto_send=False), so that the sponsor service reviews them before they reach the sponsors. Without it, sponsors with an automatic digital preference would receive the email during the upgrade. A caught-up child is only merged into an existing pending biennial of the same sponsor if that one is not sent automatically either.
    • it is an end migration because the communications need the Swiss modules loaded (their templates use the company commercial name from report_compassion, loaded after partner_communication_compassion).
  3. partner_communication_compassion: new_photo() used the first sponsorship of the child (sponsorship_ids[0]) to check it is active and to mark the printed photo. A child with a cancelled sponsorship listed before the active one got no biennial (e.g. HA075400821). It now uses the active sponsorship. Sending or cancelling a biennial clears the "new picture" mark of the child's sponsorships with the sponsor the communication is addressed to (also an ended one), and leaves the other sponsorships alone: when the child was sponsored again, the old sponsor's biennial no longer hides the new sponsor's picture from the order.

Review (Greptile)

Both findings verified and fixed: the 30 days margin on the re-dating could still leave a due biennial missed, and merging a caught-up child into an existing pending auto-send job would have sent it during the upgrade.

Review (ecino, 2026-10-29)

  • Clearing the "new picture" mark on all the child's sponsorships (Greptile's later finding, confirmed by ecino): fixed as described in point 3. Clearing only the active sponsorship, as suggested, would leave the mark on the old sponsor's ended sponsorship, and the Swiss order wizard does not exclude ended sponsorships (its state filter is malformed, see "Not changed").
  • Version: 18.0 now has its own 18.0.1.0.5 and 18.0.1.0.6 migrations; the branch is merged with 18.0 and the catch-up moved to 18.0.1.0.7.

Commits

  • 12602bb9 — Date the first child picture with its publish date
  • 48b29ccc — Catch up the biennials missed because of the picture dates
  • e9eab26f — Address review: never send the catch-up, skip handled photos
  • a5040bdd — merge of 18.0
  • 8286df59 — Address review: a biennial clears only its sponsor's picture flag
  • db88ba24 — Address review: version after 18.0 (18.0.1.0.7)

What happens in production when this is deployed

  • About 36,000 first pictures get their publish date (only the date changes).
  • The missed biennials still due at that date are prepared as pending "New Biennial" communications; nothing is sent automatically.
  • The sponsorships of sponsors receiving photos by post are marked "new picture" and appear in Sponsorship > Track sponsorships > Order Child Pictures.
  • Sponsors who already received the photo manually (e.g. KE073400410, manual message on 2026-05-18) also get a pending biennial: to cancel during the review.
  • From then on, new photos are dated correctly and biennials are generated (and sent according to the sponsor preferences) as intended.

How to test manually

After -u partner_communication_compassion on a copy of production:

  1. Sponsorship > Communications > Partner Communications, filter status Pending and communication "New Biennial": the prepared biennials, not sent.
  2. Sponsorship > Track sponsorships > Order Child Pictures: the sponsorships whose printed photo must be ordered.
  3. Sponsorship > Sponsorship > Children, KE073400410: first picture dated 2024-08-06, pending biennial "Neues Bild von Damaris (KE073400410)".

Verification log

Manual test (after the Greptile review fixes): 37,303 pictures re-dated; 9,243 children skipped because already in a biennial; 143 new pending biennial communications prepared plus 1 child merged into an existing pending one (144 jobs, 149 children), none sent automatically; 136 sponsorships marked "new picture"; 0 other communications created. KE073400410 and HA075400821 both get their biennial. The list was exported for the sponsor service (T3178_biennial_catchup.csv; the production list will differ at deployment).

Manual test (after ecino's review): for a child sponsored by two sponsors in turn, cancelling the old sponsor's biennial clears only the mark of the old (ended) sponsorship; the active sponsorship keeps its mark until the current sponsor's biennial is sent or cancelled.

Not changed

  • partner_communication_switzerland order wizard (child_order_picture.py): its filter ("state", "not in", [("terminated", "cancelled")]) holds a tuple inside the list, so ended sponsorships are not excluded. Separate issue.

  • v14 (production) is not fixed, by decision: biennials keep being missed there until v18 is live, and the catch-up only covers photos at most 6 months old at deployment.

🤖 Generated with Claude Code

The first picture of a child is fetched before the child details, so
without its photo date: it got the download date. A real new photo
received less than six months later was then not seen as a new one,
and no biennial was prepared for the sponsor.

When the photo date is not known, use the publish date contained in the
picture URL. The new photo check is split from update_child_pictures so
it can run without fetching pictures.
Date the pictures that got their download date with their publish date,
then prepare the biennials that are still due. They are created without
automatic sending, so that the sponsor service reviews them before they
reach the sponsors.

End migration: the communications need the country modules loaded.
@greptile-apps

greptile-apps Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 4/5

[Critical risk] Database migration updates picture dates and biennial communications.

Not safe to merge: resolving an older biennial can hide a newer physical photo from the printing queue.

Findings

  1. P1 Newer picture order disappears ▶

Reviews (2) · Last reviewed commit: "[T3178] Address review: never send the c..."

@greptile-apps

greptile-apps Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Comments Outside Diff

These findings could not be posted inline.

  • P1 Older biennial resolution hides a newer physical picture from the Swiss order menu ▶

    • Bug
      • After a new physical photo flags an active sponsorship and creates a pending job, sending or cancelling an older biennial for the same child clears that sponsorship’s flag. The Swiss wizard’s new_picture=True search then omits the pending picture order.
    • Cause
      • At partner_communication_compassion/models/partner_communication.py:166,174, the changed write clears every sponsorship on the older job’s child without checking whether its flag belongs to a later photo or job. The prior code cleared only the first sponsorship, which in the reproduced re-sponsorship scenario was cancelled.
    • Fix
      • Clear the flag only when the resolved biennial accounts for the outstanding picture; preserve it when a newer photo or pending picture order exists.

- Only merge a caught-up child into a pending biennial that is not sent
  automatically either, so nothing is sent during the upgrade.
- Date every picture that got its download day with its earlier publish
  date: the 30 days margin could still hide a due biennial.
- Skip the children already in a biennial since their last picture came,
  so the sponsor does not receive the same picture twice.
- Use the active sponsorship of the child instead of the first one: a
  cancelled sponsorship listed first prevented the biennial.
@ecino

ecino commented Nov 4, 2026

Copy link
Copy Markdown
Member

@danpa32 Still needs fixes.

…e-date

# Conflicts:
#	partner_communication_compassion/__manifest__.py
…flag

Sending or cancelling a biennial cleared the new_picture flag of every
sponsorship of the child, so the old sponsor's biennial of a child
sponsored again hid the new sponsor's picture from the order. It now
clears the flag of the child's sponsorships with the job's sponsor only,
including an ended one.
18.0 is at 18.0.1.0.6 and has its own 18.0.1.0.5 migration: the catch-up
moves to 18.0.1.0.7.
@danpa32
danpa32 requested a review from ecino November 4, 2026 11:28
Assisted-by: claude-sonnet-5-5, medium, claude-code

@ecino ecino left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the migration script to make it faster by using queue jobs for generating communications. We will also wait for Carole feedback before merging, for knowing whether this migration is wanted or not.

@ecino ecino removed the need review label Nov 4, 2026
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.

2 participants