Skip to content

release: v0.6.75 - #415

Open
roncodes wants to merge 15 commits into
mainfrom
release/v0.6.75
Open

roncodes wants to merge 15 commits into
mainfrom
release/v0.6.75

Conversation

@roncodes

@roncodes roncodes commented Oct 23, 2026 •

Copy link
Copy Markdown
Member

Release v0.6.75. Merging this PR into main tags v0.6.75 through the release workflow.

Included

#411, #412, #413, #414, #416. These fix PRs target this branch; merge them here first. #411–#414 touch separate files and merge together without conflicts, in any order. #416 is stacked on #413, so merge it after #413.

No migrations are needed.

The version files and RELEASE.md already name v0.6.75. Update RELEASE.md if anything else lands on this branch.

roncodes and others added 8 commits October 22, 2026 20:43
… 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.
…currency, expiry and preview

- POST /v1/orders honours an Idempotency-Key header: repeats within a day return
  the first order (Idempotent-Replayed: true); a concurrent duplicate gets 409.
- scheduled_at and time windows sent with a UTC offset are stored as the same
  instant in the app timezone. The datetime cast used to drop the offset. The
  schedule endpoint's company-timezone input is now stored in UTC as well.
- Service quotes: the preliminary path read currency with has(), filtering by a
  boolean; it is now the currency code. Stored quotes get expired_at (default
  48h, fleetops.service_quotes.ttl_minutes). preview=1 prices without storing
  quote rows, for display-only callers such as storefront checkouts.
Tracking numbers are generated with the first three characters of the
company name as their prefix, so a company named "Al Noor" issues
numbers like "AL 7796486490AE". The lookup pattern added in #352 has no
space in its character class, so the public tracking page and
fleet-ops/lookup now answer "not found" for those numbers.

Allow a space only when it sits between two allowed characters. Leading,
trailing and repeated spaces, tabs, newlines, quotes and other symbols
are still refused, and the 100 character limit is unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…refix

generateTrackingNumber() takes the first three characters of the company
name as they are, so names such as "Al Noor" or "A&B Logistics" produce
numbers containing a space or "&", and names in non-Latin scripts produce
partial multibyte characters. Keep only A-Z and 0-9 from those three
characters and fall back to FLB when nothing is left.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ccount

Creating a driver, customer or contact looked up the login account by email
or phone across the whole instance and linked any managed account of the same
type to the new profile, adding it to the caller's organization. Any API key
holder could reveal another tenant's driver (name, email, phone came back in
the response) by guessing a phone number, attach that login to their own
organization, and then change its email, phone or password through the
profile update and credential endpoints.

- ProfileAccountManager only reuses an account that already belongs to the
  requesting organization (or belongs to none). Another organization's
  account is refused with the generic "already in use by another account"
  error, which reveals neither its details nor its type.
- Accounts already shared with another organization only take the name from
  profile updates, and driver/customer credential and login actions refuse
  them.
- POST /v1/drivers no longer creates drivers in whatever company the
  `company` parameter names: anything but the credential's own organization
  is refused like an unknown company.
…he locked replay

toStorageDateTime() parsed every value with Carbon::parse(), which throws on a
numeric string such as "1792605600". The datetime cast it replaces accepted Unix
timestamps, so form-encoded API clients that send one would have started
getting a 500. Numeric values now go through Carbon::createFromTimestamp().

Also covers the replay found after the lock is taken (a duplicate that finished
first), the one line codecov/patch flagged.
isUnowned() only looked at users.company_uuid and company_users, so an account
with neither but a live driver or contact profile in another organization (a
customer who signed up through a storefront, for example) could still be
adopted by any organization that knew its email or phone. It now also requires
that the account holds no profile anywhere.
@codecov

codecov Bot commented Oct 23, 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 (a4cdc2d).

Additional details and impacted files
@@             Coverage Diff             @@
##                main      #415   +/-   ##
===========================================
  Coverage     100.00%   100.00%           
- Complexity     13596     13661   +65     
===========================================
  Files            634       635    +1     
  Lines          49342     49438   +96     
===========================================
+ Hits           49342     49438   +96     
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.

Two parts of a generated number could carry a space or punctuation:

- The prefix took the first three characters of the company name, then
  dropped what was not a letter or digit, so "Al Noor Transport" gave AL and
  "A&B Logistics" gave AB. It now skips those characters first and takes the
  first three letters or digits (ALN, ABL), falling back to FLB.
- The suffix appended the region as given. The region falls back to the
  pickup's province or district when it has no country, and
  POST /v1/tracking-numbers accepts any string, so a pickup in "New York"
  issued ...NEW YORK. It now keeps only letters and digits, falling back to SG.

Numbers already issued keep working through the lookup change in this PR.
…-and-place-coordinates

fix(orders): allow partial payload edits and keep addresses sent with coordinates
…nt-linking

fix(security): never link a profile to another organization's login account
…-space

Allow single inner spaces in tracking number lookup (regression from #352)
…-idempotency

fix(orders,quotes): idempotent order creation, UTC scheduling, quote currency, expiry and preview
…-alphanumeric

fix(tracking): generate tracking numbers from letters and digits only
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