Skip to content

fix(orders): allow partial payload edits and keep addresses sent with coordinates - #411

Merged
roncodes merged 1 commit into
release/v0.6.75from
fix/order-edit-partial-payload-and-place-coordinates
Oct 23, 2026
Merged

roncodes merged 1 commit into
release/v0.6.75from
fix/order-edit-partial-payload-and-place-coordinates

Conversation

@roncodes

Copy link
Copy Markdown
Member

Problem

Integrations (the WooCommerce plugin and the new Shopify app) cannot safely edit an order after creating it:

  1. Partial payload edits are rejected. UpdateOrderRequest extends CreateOrderRequest unchanged, so any PUT /v1/orders/{id} with a payload object must resend pickup, dropoff or waypoints. Sending only new entities (entities_mode=replace) or only a new dropoff returns The payload.pickup field is required.
  2. Addresses sent with coordinates are replaced. Place::createFromMixed() checks Utils::isCoordinatesStrict() before the structured-array branch. Any array with latitude/longitude matches, so {street1: "1100 4th Ave", latitude, longitude} goes to createFromCoordinates(), which drops the street and reverse-geocodes. Reproduced locally: an order created with 1100 4th Ave stored 909 5TH AVENUE; an edit to 500 Pine St stored 400 PINE STREET. This affects order creation as well as updates.

Changes

  • UpdateOrderRequest::rules(): when payload is an object, payload.pickup/payload.dropoff are nullable and payload.waypoints is array (an empty list is how the controller removes intermediate stops). A payload id and top-level fields keep the create contract. The controller already handled partial payloads correctly.
  • Place::createFromMixed(): the bare-coordinates branch only applies when the array has no address fields (street1, address, city, postal_code). Structured arrays turn latitude/longitude (or lat/lng) into location, and skip the geocoding lookup when both a street and a usable location are present. Addresses without coordinates and bare coordinates behave as before.
  • New helpers Place::hasStructuredAddress(), withProvidedLocation(), hasProvidedLocationAndStreet().

Replace semantics for entities stay opt-in through the existing entities_mode=replace, so current API clients that rely on append are unaffected.

Verification

  • New tests in RequestContractsTest (partial update rules) and Unit/Models/PlaceCreationAndImportTest (structured address + coordinates keeps street and location without any geocoder call; bare coordinates still reverse-geocode; address-only still geocodes; helper edge cases).
  • The 40 test files that touch orders, payloads, places or quotes pass locally (PHP 8.4, Pest). php-cs-fixer clean. CI will report coverage.
  • End to end on a local stack (fleetops-api patched in place, Octane reloaded): created an order with 1100 4th Ave + coordinates and it kept 1100 4TH AVE; PUT with entities_mode=replace and only entities returned no errors and left exactly the two sent items; a dropoff-only PUT stored 500 PINE ST at exactly the sent coordinates.

… coordinates

- UpdateOrderRequest no longer applies creation's route requirements to a payload
  object: an update may send only entities (with entities_mode=replace), only a
  new dropoff, or an empty waypoints list.
- Place::createFromMixed treats an array as bare coordinates only when it has no
  address fields. A structured address sent with latitude/longitude keeps its
  street and uses those coordinates as its location, with no geocoding lookup.
  Previously the coordinates sent the place down the reverse-geocoding path,
  which discarded the street and stored a nearby address instead.
@codecov

codecov Bot commented Oct 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (33032e5) to head (b7dffb4).

Additional details and impacted files
@@             Coverage Diff             @@
##                main      #411   +/-   ##
===========================================
  Coverage     100.00%   100.00%           
- Complexity     13596     13616   +20     
===========================================
  Files            634       635    +1     
  Lines          49342     49370   +28     
===========================================
+ Hits           49342     49370   +28     
Flag Coverage Δ
backend 100.00% <100.00%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@roncodes roncodes mentioned this pull request Oct 23, 2026
@roncodes
roncodes changed the base branch from main to release/v0.6.75 October 23, 2026 03:21
@roncodes

Copy link
Copy Markdown
Member Author

Review: looks good.

  • UpdateOrderRequest only relaxes the route-endpoint rules when payload is an object. A payload id, and creation, keep the create contract.
  • In Place::createFromMixed(), a structured address that has coordinates now skips the bare-coordinates branch. mergeStructuredPlaceAttributes() merges array_merge($geocoded, $place), so the location the caller sent still wins when only a city or postal code triggers a lookup.
  • Follow-up, not blocking: Place::insertFromMixed() still checks isCoordinatesStrict() first. Its callers are Payload::insertWaypoints() and Order::insertPayload(), which only the console's internal order create uses. The public API goes through setWaypoints() → createFromMixed(), so integrations are covered by this PR.

Retargeted to release/v0.6.75 (#415).

@roncodes
roncodes merged commit 1884225 into release/v0.6.75 Oct 23, 2026
11 checks passed
@roncodes
roncodes deleted the fix/order-edit-partial-payload-and-place-coordinates branch October 23, 2026 04:06
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