Skip to content

#11288 Ancillary item service + GraphQL layers#11333

Merged
ria8651 merged 3 commits intov2.19.0-RCfrom
11288-ancillary-item-graphql
May 4, 2026
Merged

#11288 Ancillary item service + GraphQL layers#11333
ria8651 merged 3 commits intov2.19.0-RCfrom
11288-ancillary-item-graphql

Conversation

@ria8651
Copy link
Copy Markdown
Contributor

@ria8651 ria8651 commented Apr 21, 2026

Fixes #11288

Stacked on #11332 — please merge that first. #11289 and #11290 will follow stacked on this.

👩🏻‍💻 What does this PR do?

Adds the service and GraphQL layers on top of the schema from #11287, exposing the ancillary-item CRUD surface the frontend will drive.

Service layer (server/service/src/item/ancillary_item/):

  • upsert_ancillary_item — handles both insert and update; validates central-only authz, item_quantity > 0 and ancillary_quantity > 0, both item_link_id FKs, duplicate (principal, ancillary) pairs, and reuses validate_ancillary_item_link from Ancillary items: schema + sync for ancillary_item table #11287 for self-link / cycle / max-depth.
  • delete_ancillary_item — soft delete with central-only guard.
  • get_ancillary_items — paginated list query.
  • Wired into ItemServiceTrait alongside existing bundled-item / item-variant CRUD.

GraphQL layer (new graphql_ancillary_item crate, matches the bundled_item pattern):

  • Mutations: centralServer.ancillaryItem.upsertAncillaryItem and .deleteAncillaryItem.
  • Input type uses itemQuantity / ancillaryQuantity directly (not a derived ratio) so the client sends the user's original x:y.
  • AncillaryItemNode type: exposes id, itemQuantity, ancillaryQuantity, itemLinkId, ancillaryItemLinkId, plus nested item / ancillaryItem resolved via the existing ItemLoader.
  • ItemNode.ancillaryItems and ItemNode.ancillaryFor fields: backed by two new DataLoaders so the frontend can fetch an item's ancillary links (as principal or as ancillary) in one round-trip.

Tests: one consolidated service-layer test covering CRUD + every error variant (central-only, FK, ratio, self-link, cycle, duplicate, update-excludes-self), plus two GraphQL mutation tests covering success + error-bucket mapping.

💌 Any notes for the reviewer?

Known limitation (same as bundled_item): the loaders treat item_link_id as item_id, which is the common case for newly-created items but breaks for items that have been merged (multiple link IDs pointing at the same item). Documented inline at graphql/core/src/loader/ancillary_item.rs. Follow-up if/when it becomes a real issue.

Service-layer central-only check is belt-and-suspenders with the GraphQL central_server wrapper — both reject non-central mutations, the service-layer variant just produces a cleaner NotCentralServer service error for future callers (e.g. sync-triggered paths).

Tests use a process-wide central-server flag. The service test consolidates all sub-cases into a single #[actix_rt::test] to avoid races with cargo's parallel runner since other test modules set the same flag. Covered inline at service/src/item/ancillary_item/test/mod.rs.

No divergence from the issue scope. All four items in the issue's Scope section (queries, mutations, validation, tests) implemented.

🧪 Testing

Prerequisite: #11287 merged (or running this branch which includes it).

  • Run cargo test --package service ancillary_item — expect 1 test (consolidated, covers all scenarios).
  • Run cargo test --package graphql_ancillary_item — expect 2 tests (upsert + delete happy/error paths).
  • Via GraphQL (on an oMS central server):
    • upsertAncillaryItem with valid input → AncillaryItemNode with both quantities returned.
    • Repeat with same (itemLinkId, ancillaryItemLinkId) pair but different idDuplicateAncillaryItem (BadUserInput).
    • Same but itemLinkId == ancillaryItemLinkIdCanNotLinkItemWithItself (BadUserInput).
    • Create A→B, then try B→ACycleDetected.
    • itemQuantity: 0RatioMustBePositive.
    • deleteAncillaryItemDeleteResponse on success; check DB: deleted_datetime populated.
  • On a remote (non-central) site: same mutations return Forbidden (via the central_server wrapper).
  • Query ItemNode.ancillaryItems and ancillaryFor for a linked item → returns the expected AncillaryItemNodes with nested item / ancillaryItem.

Note that this testing with manual graphql queries can be skipped and just wait for the next two PRs which will add UI for this.

📃 Documentation

  • Part of an epic: documentation will be completed for the feature as a whole (Ancillary Items for ordering #11232)
  • No documentation required: no user facing changes or a bug fix which isn't a change in behaviour
  • These areas should be updated or checked:
    1.
    2.

📃 Reviewer Checklist

The PR Reviewer(s) should fill out this section before approving the PR

Breaking Changes

  • No Breaking Changes in the Graphql API
  • Technically some Breaking Changes but not expected to impact any integrations

Issue Review

  • All requirements in original issue have been covered
  • A follow up issue(s) have been created to cover additional requirements

Tests Pass

  • Postgres
  • SQLite
  • Frontend

Service layer wraps the schema/repo work from #11287 with insert/update
(via upsert) and soft-delete operations, validating central-only authz,
item_quantity > 0 and ancillary_quantity > 0, both item_link FKs,
duplicate (principal, ancillary) pairs, and reusing
validate_ancillary_item_link for self-link/cycle/depth.

GraphQL layer exposes upsertAncillaryItem and deleteAncillaryItem under
centralServer.ancillaryItem (matching the bundledItem pattern), plus
ancillaryItems and ancillaryFor fields on ItemNode backed by two new
DataLoaders. AncillaryItemNode exposes the pair directly as
itemQuantity and ancillaryQuantity (not a derived ratio) plus nested
item and ancillaryItem resolved via the ItemLoader. Loaders currently
treat item_link_id as item_id -- merged items aren't supported yet,
matching bundled_item's existing limitation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added this to the V2.18.0 milestone Apr 21, 2026
@github-actions github-actions Bot added Priority: Must Have The product will not work without this Team Whio Brian, Carl, Esme, James & Ravi [P] AFG [M] Adam labels Apr 21, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 21, 2026

Test report (sqlite)

1 007 tests   1 006 ✅  7m 31s ⏱️
   24 suites      0 💤
    1 files        1 ❌

For more details on these failures, see this check.

Results for commit e352c74.

♻️ This comment has been updated with latest results.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 21, 2026

Test report (postgres)

1 008 tests   1 007 ✅  49m 55s ⏱️
   24 suites      0 💤
    1 files        1 ❌

For more details on these failures, see this check.

Results for commit e352c74.

♻️ This comment has been updated with latest results.

@ria8651 ria8651 linked an issue Apr 21, 2026 that may be closed by this pull request
@mark-prins mark-prins modified the milestones: v2.18.0, v2.19.0 Apr 22, 2026
Base automatically changed from 11287-ancillary-item-schema to develop May 4, 2026 02:25
Comment thread server/graphql/ancillary_item/Cargo.toml
Comment thread server/graphql/core/src/loader/ancillary_item.rs Outdated
Copy link
Copy Markdown
Contributor

@jmbrunskill jmbrunskill left a comment

Choose a reason for hiding this comment

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

Looks good, lets just remove the link_id from the graphql response...

Comment thread server/graphql/types/src/types/ancillary_item.rs Outdated
Comment thread server/service/src/item/ancillary_item/delete.rs Outdated
@jmbrunskill jmbrunskill self-assigned this May 4, 2026
ria8651 added 2 commits May 4, 2026 17:07
Mainly just changing item link to item now that repository layer hides item link
@ria8651 ria8651 requested a review from jmbrunskill May 4, 2026 05:18
@ria8651
Copy link
Copy Markdown
Contributor Author

ria8651 commented May 4, 2026

Updated with repository layer item link changes. Should handle merging properly now. Addressed other comments too.

Copy link
Copy Markdown
Contributor

@jmbrunskill jmbrunskill left a comment

Choose a reason for hiding this comment

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

Updates look fine, feel free to merge when tests pass

@jmbrunskill jmbrunskill changed the base branch from develop to v2.19.0-RC May 4, 2026 05:19
@ria8651 ria8651 merged commit 2e48195 into v2.19.0-RC May 4, 2026
2 of 6 checks passed
@ria8651 ria8651 deleted the 11288-ancillary-item-graphql branch May 4, 2026 21:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[P] AFG [M] Adam Priority: Must Have The product will not work without this Team Whio Brian, Carl, Esme, James & Ravi

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Ancillary items: GraphQL + service layer for links

3 participants