Skip to content

refactor(order-detail): split OrderDetail into Vue-native components with parity to main - #534

Merged
dt2patel merged 10 commits into
mainfrom
order-detail-architecture
Sep 25, 2026
Merged

dt2patel merged 10 commits into
mainfrom
order-detail-architecture

Conversation

@dt2patel

@dt2patel dt2patel commented Sep 20, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Splits the 4,081-line OrderDetail.vue into a composition shell plus focused, Vue-native pieces, with no behaviour change from main apart from the bug fixes listed below.

Piece Owns
views/OrderDetail.vue (364 lines) Loading, selection state, Shopify link, exchange lineage, wiring
components/orders/OrderSummaryHeader.vue Header, timeline, customer/source/identification/attribute/risk cards
components/orders/OrderItemsSegment.vue Items tab, payments and totals
components/orders/OrderShipGroupCard.vue One ship group: lifecycle, options, fulfillment, and the inline editors' drafts (saves are emitted)
components/orders/OrderHoldsSegment.vue, OrderCommsSegment.vue Holds and Comms tabs
composables/useOrderActions.ts Every page action, and the one validator path that gates them
composables/useOrderDistances.ts Ship-to distance per brokered group
utils/orderDetailEnrichment.ts The page view model, built on the store's existing getters

Children take order/shipGroup props, derive with computed, report intent with defineEmits, and import translate and the formatters. Selection flows through v-model. Date, adjustment and product-identity helpers each live in one module (utils/orderDetailDates.ts, utils/orderAdjustments.ts, composables/useProductIdentity.ts), and the card-header grid is shared via <style scoped src>.

src/ goes from 36,347 lines on main to 34,987.

Deliberate differences from main (bug fixes)

  • POS issuance badge works:
    • Main asked oms/inventoryItem/detail?orderId=, which is not mounted (405), so a POS-completed item never showed whether inventory left the books.
    • The page now reads each line's inventory item from oms/productFacilities, then its issuance rows from oms/inventoryItem/{id}/detail?orderId=. No backend change is needed.
    • On rails-uat, 159552 shows "Inventory issued, On hand at sale 0 → -1" and 159415 shows "-36 → -37".
  • One Shopify link path:
    • The oms/orders/{id}/shopifyShopOrder lookup 404'd on every order load: hotwax/oms#798 and #800 closed unmerged, and hotwax/mantle-shopify-connector#381 is open.
    • It is removed. The Admin link comes only from the product-store inference, which already produced every link main shows.
  • Timeline scope: "First Brokered" and the exchange sources read this order's own data. Main read whichever order was loaded last, so a cached page could show another order's dates.
  • Timeline refresh: the fulfillment timeline now refreshes after an action (broker, release, …), not only on first load.
  • Facility lookups: each facility's address is requested once per session, misses included. Main re-requested it on every recompute, 4 times per load on rails-uat.
  • Carrier selection: a carrier picked while choosing a method now resets only when the saved carrier or method changes, not on any unrelated data refresh.
  • UI text: · is removed from the ship group summary and the hold-task ship group labels, per the AccxUI rules. Time-difference units and the "Customer name" placeholder are now translated.

Removed: unreachable footer actions and dead code

  • Return, Appeasement, Reship and Clone:
  • Validator: the unused discovery helpers are gone (getFooterActions, getShipGroupActions, getItemActions, getBulkSelectableItems, isItemSelectable, hasAnyCompletedItem, ctx.allItems).
  • Store: the "current order" layer is gone (currentOrderId and 22 unscoped getters that only tests read), plus the order work-effort fetch, the commEvents mirror and the unread risk error state.
  • Park, pull back and release share one flow in useOrderActions (validate, pick the eligible items, prompt, call, clear the selection, toast, reload). The allocation call and the task payload are shared too.
  • Item rows: each item row's props and listeners are bound from one object, so the single-item row and the rolled-up child rows no longer repeat 13 bindings. The Request transfer and Cancel buttons stay in the row's actions slot.
  • Ship group edits: the card no longer writes. It keeps its drafts and emits save-fields / save-address; useOrderActions saves, toasts and reloads like every other action, and owns which editor is open (v-model:editor), so an editor closes only when its save succeeds and a failed save keeps the draft on screen, as on main. The address save re-checks the validator like the other handlers, and each editor's Save button is disabled while a save is in flight.
  • Store reads go through getters: the page no longer reads the order detail store's state directly. New pendingById gives one definition of "not answered yet" (the exchange Source card had its own inline version, which differed from loadingById); commEventsForOrder and riskAssessmentsForOrder return [] when nothing is loaded; the exchange return links use the existing orderById.

Behaviour compared against main on rails-uat

The same 16 orders were loaded in both builds side by side and compared section by section (header, Items, Shipgroups, Holds, Comms, footer, and the enabled/disabled state of every control). Every section matched except the · separator. The orders covered:

  • approved orders, brokered and parked
  • completed orders with returns
  • open orders with cancelled items
  • POS orders
  • exchanges and their originals
  • a Created order
  • risk-flagged orders
  • orders with hold, swap and fraud tasks
  • the brokering queue

Also verified:

  • Layout: computed layout is identical at 1440 px and 390 px.
  • Actions: every action button opens the same modal or alert with the same props as main. Modals were stubbed, so nothing was submitted.
  • Card interactions: expand, item selection and carrier change match main.
  • Network: a Web order makes 12 API calls vs 15 on main. There's no issuance call (a 405 on rails-uat) and no duplicate facility lookups.
  • Second pass (this update): 10 orders were compared again, including POS orders 159552 and 159415. The only differences are the separator, the working issuance badge, and the two failing calls (404 and 405) that are now gone. The Shopify Admin link resolves to the same URL on both, for example admin.shopify.com/store/rails-25/orders/7163180122281 for 115548.
  • Ship group editors: with every write faked in the browser (nothing reached rails-uat), gift message, shipping dates and address behave the same as main on 104848: identical request payloads, a failed save keeps the editor and draft open with the failure toast, a successful save closes it. The Items tab rows are byte-identical to main on 104821, 115548, 157940 and 159552.
  • Store getters: Comms (160791, 160806) and the risk details modal's data (160791: 1 assessment / 9 facts; 160802: 1 / 2) match main. The exchange Source card cannot be exercised on rails-uat, whose order document carries no itemAssocs; pendingById is equivalent to the inline check it replaces because every store entry is created with a status.
  • Selection actions: park, pull back and release have a new spec that mocks the API and modals. It asserts the exact requests, and it passes unchanged against the previous implementation too.

Checks

  • vitest: 85 files / 495 tests pass. The count dropped because the Clone spec was removed with the feature; new specs cover the issuance lookup and the selection actions.
  • vue-tsc --ignoreDeprecations 6.0: 34 errors (main: 50), none in the files this PR touches.
  • vite build passes.

Not verifiable on rails-uat: distances, because no facility there has a postal address. The new unit test covers it.

🤖 Generated with Claude Code

- Introduce domain models in src/types/orderDetail.ts
- Create pure enrichment pipeline in src/utils/orderDetailEnrichment.ts
- Add enrichedOrderByOrderId and loadOrderAggregate to orderDetail store
- Extract distance and geocoding logic to src/composables/useOrderDistances.ts
- Extract order mutation actions and workflows to src/composables/useOrderActions.ts
- Streamline OrderDetail.vue to focus on rendering (-746 lines)
- Fix missing IonNote import in OrderItemListRow.vue
- Add unit tests for enriched store getters
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 20, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-20T05:41:19.641533Z 6fbd21d PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6fbd21d0a5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/composables/useOrderActions.ts Outdated
Comment thread src/views/OrderDetail.vue Outdated
Comment thread src/utils/orderDetailEnrichment.ts Outdated
Comment thread src/utils/orderDetailEnrichment.ts Outdated
Comment thread src/composables/useOrderActions.ts Outdated
Comment thread src/views/OrderDetail.vue Outdated
Comment thread src/utils/orderDetailEnrichment.ts Outdated
Comment thread src/store/orderDetail.ts Outdated
Comment thread src/utils/orderDetailEnrichment.ts Outdated
Comment thread src/utils/orderDetailEnrichment.ts Outdated
dt2patel and others added 4 commits September 20, 2026 00:53
Resolve the OrderDetail.vue header conflict with #551 by keeping the
OrderSummaryHeader component and porting its anchor-to-ion-button change
into that component.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tive

The decomposition copied logic between files instead of consolidating it and
drifted from main in several places. This reworks it so each fact has one
owner and the page behaves exactly as main does.

Behaviour restored to main:
- Carrier and shipping method selects were always disabled: the precomputed
  ship group capabilities called the validator with action ids it does not
  define. Gating now has one path (useOrderActions), used by both the
  disabled state and the click handler, with selection narrowing restored.
- Ship group distances never computed: the composable could not read the
  getter it was given. It now takes MaybeRefOrGetter and reads coordinates
  from the enriched ship-to address.
- Timeline: item cancellation/rejection and First Brokered entries are back,
  approved/completed use the earliest status, return links respect the
  return-view permission, exchange links keep the current route prefix.
- Inventory transfer requests pass productStoreId, destinationFacilityId and
  the open quantity again, honour the selection, and toast on confirm.
- Ship group edits surface failures instead of reporting success; the
  unavailable-action notice is a toast again; customer contact fallback
  matches purposeTypeIds; brokered dates fall back to the raw facility
  change rows; attribute rows and the totals card markup match main.
- Styles moved with the markup (the parent's scoped CSS no longer reached
  the children), unchanged from main; the card header grid is shared via a
  scoped style src.
- Issuance labels stay untranslated keys until render, so es-ES keeps the
  "On hand at sale" note.
- Loading fetches issuance only for POS orders and risk only for risk-flagged
  orders, and no longer blocks product data on the auxiliary sources.

Structure:
- Children take order/shipGroup props, derive with computed, report intent
  with defineEmits, and import translate and the formatters.
- Selection flows through v-model instead of accessor objects mutated by
  children; card modal state is per card.
- The enrichment builds on the store's existing getters (totals, statuses,
  events, adjustments) and drops unused dual fields; date, adjustment and
  product-identity helpers each live in one module.
- Dead code, unused imports and the unscoped timeline duplicates are gone.

src: 37,722 -> 35,822 lines (main is 36,347). vue-tsc: 57 -> 34 errors
(main: 50). Tests: 84 files / 495 passing, with behavioural specs for the
enrichment, gating and distances.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dt2patel dt2patel changed the title refactor(order-detail): decompose store and view architecture refactor(order-detail): split OrderDetail into Vue-native components with parity to main Sep 24, 2026
dt2patel and others added 3 commits September 24, 2026 11:55
…ions and dead code

- POS issuance: read each line's inventory item from oms/productFacilities, then
  its issuance rows from oms/inventoryItem/{id}/detail?orderId=. The order-wide
  list main called is not mounted (405), so the badge never rendered.
- Shopify Admin link: drop the oms/orders/{id}/shopifyShopOrder lookup, which
  404s on every load (hotwax/oms#798 and #800 closed unmerged). The product-store
  inference is now the only path.
- Footer: remove the Return, Appeasement, Reship and Clone modelling. None of
  them could render. CloneOrderModal, utils/cloneOrder and its spec go too.
  Tracked in #6, #554, #555 and #556.
- Validator: remove the unused discovery helpers and ctx.allItems.
- Store: remove the unused current-order getters, currentOrderId, the
  work-effort fetch, the commEvents mirror and the unread risk error state.
- useOrderActions: park, pull back and release share one selection flow; the
  allocation call and the task payload are shared too.
- Items tab: item rows bind from one object and the row renders its own
  Request transfer and Cancel buttons.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…re the row actions slot

- OrderShipGroupCard no longer saves. It keeps its drafts and emits
  save-fields / save-address; useOrderActions performs the write, shows the
  toast and reloads, like every other action on the page.
- useOrderActions owns which ship group editor is open (v-model:editor on the
  card), so an editor closes only once its save succeeds and a failed save
  keeps the draft on screen, as on main. The address save now asks the
  validator again, like the other handlers.
- Every editor's save button is disabled while a save from that card is in
  flight; the card's close buttons go through one closeEditor method.
- OrderItemListRow goes back to its actions slot instead of carrying
  canTransfer / canCancel props; the items segment still binds each row's
  props and listeners from one object.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The page read the store's state directly in four places. They now go through
getters, so the page no longer depends on how the store lays out its entries:

- pendingById: one definition of "not answered yet" (never requested, idle
  or in flight). The Source card used its own inline version of this, which
  differed from loadingById.
- commEventsForOrder / riskAssessmentsForOrder: the lists, defaulting to [].
- The exchange return links use the existing orderById.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dt2patel
dt2patel merged commit 362f6d4 into main Sep 25, 2026
2 checks passed
dt2patel added a commit to AmoghParmar/order-manager that referenced this pull request Sep 26, 2026
main split OrderDetail.vue into components (hotwax#534), so the conflict resolves to
main's version; the change is re-applied in the new components in the next
commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

1 participant