Repository navigation
feat(promotions): store attribution, shareable code and availability on public promotions - #116
Merged
Merged
Conversation
…on public promotions
- Public promotions name the store or network running them (owner: type, id,
name, logo_url) and list applies_to targets by public id instead of uuid.
- Code promotions show their code publicly when they have one reusable,
unassigned, unexpired code; single-use batch codes are never exposed.
- Every promotion reports availability (live, scheduled, ended) and, when
scheduled, next_starts_at from its date range and weekly hours.
- GET promotions?include=scheduled also lists promotions outside their weekly
hours or before their start; GET promotions/{id} opens scheduled and ended
promotions so links from notifications keep working.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #116 +/- ##
===========================================
Coverage 100.00% 100.00%
- Complexity 2282 2321 +39
===========================================
Files 182 182
Lines 9082 9168 +86
===========================================
+ Hits 9082 9168 +86
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This was referenced Oct 6, 2026
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The customer app redesign adds an Offers list and an offer detail screen, linked from home, store pages and campaign notifications. The public promotion API couldn't support them:
applies_toheld internal uuids, so "Shop the offer" couldn't link to products, categories or stores.This PR adds those fields to the public promotion resource. It also lets the list and detail endpoints return scheduled and ended promotions; the list does this only on request.
Related Issue
Part of the storefront-app redesign (Offers list, offer detail and campaign deep links).
Type of Change
Implementation Notes
PromotionmodelavailabilityAt()returns one of:live: running now;scheduled: active, but beforestarts_ator outside its weekly hours;ended: status ended, or pastends_at;inactive: draft or paused.nextLiveAt()applies to scheduled promotions only. It returns the next moment the promotion applies, using the later of now andstarts_at, the weekly windows in the promotion's timezone (including windows past midnight), andends_at. It looks up to a week ahead; a futurestarts_atwith no weekly hours is returned whatever its distance.shareableCode()applies to code promotions only. It returns the newest code that is all of these:usage_limitnull or > 1).So batches of single-use codes are never exposed. Codes are read from the eager-loaded relation when present.
ownerSummary()returns{type: store|network, id, name, logo_url}.logo_urlis null when there is no logo, so the app can draw its monogram instead of the generic file icon.publicAppliesTo()mapsproducts,exclude_products,stores,categoriesandexclude_categoriesto public ids. It accepts either uuids or public ids, likePromotionLine::matches*, and drops ids that no longer resolve.Public resource
On public routes it adds
owner,code,availabilityandnext_starts_at, and returnsapplies_towith public ids. Internal (Console) responses keep rawapplies_toand don't includeownerorcode.availabilityandnext_starts_atappear on both, because they only need the promotion's own fields.v1
PromotionControllerGET promotionsis unchanged by default: live promotions only.include=scheduledadds scheduled ones. Ended, draft and paused promotions are never listed.GET promotions/{id}now returns scheduled and ended public promotions, so links from notifications keep working. It still returns 404 for draft, paused, non-public and out-of-context promotions.Docs:
docs/promotions.mdexplains when a code appears in the customer app and that scheduled offers stay visible.Validation
Command output / summary:
New
server/tests/Unit/Promotions/PublicPromotionDetailsTest.phpcovers:starts_at; astarts_atinside a window that runs past midnight; a non-UTC timezone; anends_atbefore the next window; a window with no days;applies_tomapping, including unknown and non-string ids;include=scheduled, and detail for scheduled, ended, paused and draft promotions;Existing promotion, campaign and cart tests pass unchanged.
Documentation Impact
fleetbase/fleetbase.io(repodocs/promotions.mdhere; the site copy is a follow-up)API Reference Impact
fleetbase/postmanAPI reference notes:
GET storefront/v1/promotions:include=scheduled.GET storefront/v1/promotions/{id}now also returns scheduled and ended promotions.owner,code,availabilityandnext_starts_at.applies_tonow contains public ids on public routes.Documentation Notes
The storefront API docs and the Postman collection need the fields and parameter above.
Risk
GET promotions/{id}meant "live now" should now readavailability. The current storefront-app doesn't call this endpoint.applies_tomapping adds up to five smallwhereInlookups per promotion that has targets. Public lists are short.