-
Notifications
You must be signed in to change notification settings - Fork 0
docs+fix: record the Xero-first company merge model, align the stragglers (KAN-325) #516
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
890867d
6e2370b
56330c9
2ea5b2f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| # Generated by Django 6.0.7 on 2026-08-02 02:00 | ||
|
|
||
| from django.db import migrations, models | ||
|
|
||
|
|
||
| class Migration(migrations.Migration): | ||
|
|
||
| dependencies = [ | ||
| ("company", "0012_text_unset_constraints"), | ||
| ] | ||
|
|
||
| operations = [ | ||
| migrations.AlterField( | ||
| model_name="company", | ||
| name="allow_jobs", | ||
| field=models.BooleanField( | ||
| default=True, | ||
| help_text="If False, this company cannot be selected as the company on a Job. Use for Xero contacts that must exist (tax authorities, internal accounts, etc.) but should never appear on a job. Automatically set to False when a company is archived or merged in Xero, and restored on un-archive (merged companies stay blocked).", | ||
| ), | ||
| ), | ||
| ] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -285,20 +285,31 @@ def set_company_fields(company: Company, new_from_xero: bool = False) -> None: | |
| if xero_contact_id_from_json: | ||
| company.xero_contact_id = xero_contact_id_from_json | ||
|
|
||
| # Check for archived/merged status from raw_json | ||
| contact_status = raw_json.get("_contact_status", "ACTIVE") | ||
| if contact_status == "ARCHIVED": | ||
| company.xero_archived = True | ||
| # xero_archived mirrors Xero in both directions. allow_jobs follows only | ||
| # on the transitions — archiving disables it, un-archiving restores it — | ||
| # never on a steady-state sync, so a manual block on an active company | ||
| # survives routine syncs (ADR 0034). A merged tombstone stays blocked | ||
| # regardless: its jobs belong to the winner. | ||
| # No fallback for a missing status: guessing ACTIVE would un-archive the | ||
| # company and re-open it for jobs. Malformed data fails this company's | ||
| # sync (ADR 0015 — consumers stay strict). GDPRREQUEST is deliberately | ||
| # not accepted: it should never occur on an NZ org, and treating it as | ||
| # active would re-enable jobs for an erased contact — if it ever appears, | ||
| # fail loudly and decide its handling then. | ||
| contact_status = raw_json.get("_contact_status") | ||
| if contact_status not in ("ACTIVE", "ARCHIVED"): | ||
| raise ValueError( | ||
| f"Company {company.id} raw_json has missing or unhandled " | ||
| f"_contact_status {contact_status!r}" | ||
| ) | ||
| was_archived = bool(company.xero_archived) | ||
| company.xero_archived = contact_status == "ARCHIVED" | ||
| if company.xero_archived: | ||
| company.allow_jobs = False | ||
| # FIXME: asymmetric -- un-archiving in Xero does not reset either | ||
| # flag. If a contact is archived then un-archived, `xero_archived` | ||
| # and `allow_jobs` stay in the archived state until an admin toggles | ||
| # `allow_jobs` back on via the company detail UI. The un-archive | ||
| # path is rare enough that we accepted the asymmetry rather than | ||
| # introduce a "manually set" protection flag. If un-archive becomes | ||
| # common, revisit: (a) auto-reset both flags, which overwrites any | ||
| # manual admin-set `allow_jobs=False`; or (b) track admin overrides | ||
| # separately so they survive a sync. | ||
| elif was_archived and not company.merged_into_id: | ||
|
Comment on lines
+305
to
+309
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in 2ea5b2f, taking the reject-outright option: GDPRREQUEST is removed from the accepted statuses, so it now raises like any unhandled status instead of falling through as "not archived" and re-enabling jobs. It should never occur on an NZ org; if it ever does, the sync fails loudly for that company and we decide its handling then. Test pins that an archived company stays archived and blocked. |
||
| company.allow_jobs = True | ||
| else: | ||
| pass # no archive transition; leave allow_jobs as the admin set it | ||
|
|
||
| # Check for merge information | ||
| merged_to_contact_id = raw_json.get("_merged_to_contact_id") | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.