Skip to content

Products

The Products navigation group in Arkana turns tour content into sellable, priced packages and tracks them all the way to a customer booking. It spans four stages: the master template, its market-specific localization, the concrete offers, and the resulting bookings.

Item Manages In navigation
Product Templates Master (source-locale) tour content Hidden — see below
Products by Market A template localized to one market + locale Yes
Offers Concrete sellable packages (date + airport + pricing) Yes
Bookings Customer bookings of an offer, with the full workflow Yes

The Product Template is the reusable master record: title, descriptions, highlights, media, itinerary, logistics and the structured “what’s included / not included” content in the source locale.

Its resource is deliberately hidden from the navigation (shouldRegisterNavigation() returns false). Templates are no longer edited as a standalone menu item — they are created and managed through Tours (SupplierTour) under the Suppliers group. The template resource remains reachable by direct URL for admin debugging only.

Once a template has at least one market product it becomes content-locked: text and images can still be edited, but the itinerary structure is frozen. See Product Templates for the content model and Products overview for how templates, tours and market products relate.

A template’s itinerary endpoints carry an integer overnight flight days count (flight_days, 0 to a small cap) — the nights a traveller sleeps aloft on the way to the destination and on the way back. Each night adds a dedicated flight-day narrative (and its own image) before or after the itinerary, so a long-haul route with a red-eye renders correctly instead of collapsing into a single day. This generalizes the legacy has_overnight_flight boolean. The full resolution rules and image fallbacks are documented in Product Templates → Overnight Flight Days.

A Product by Market ties a template to one market and locale — the actual translated, sellable product. It owns the flight search configuration (departure airports, route legs, search window derived from the tour’s travel windows) and the localized content, and it links back to its Tour.

Products have a status of draft, active or inactive; product_template_id, market_id and locale are immutable once created. Notable operator actions from the view page:

  • Auto-Generate Offers — runs the offer generator for the product’s airports and dates.
  • Diagnose missing offers — for chosen airport × date slots, runs each through the same gate sequence the auto-generator uses and reports why offers are or aren’t produced (capped at 100 slots per run). This is the operator’s first stop when a product “won’t generate offers”.
  • Translate from Tour — full AI translation of all fields from the tour content.
  • Share with client — a long-lived signed magic link so ops can send a client a private view-and-book link without publishing.
  • Duplicate, View Cached Flights, plus Preview (normal / with flight diagnostic).

A product cannot be deleted while it has offers. See Products by Market.

An Offer is a concrete sellable package: a market product + departure airport + departure date + fare group, with combined flight, land and insurance pricing. Offers are listed under Offers and also embedded on each product’s view page.

Three stored statuses (OfferStatus):

  • Draft — editable internal state, not published.
  • Approved by supplier — auto-set when the supplier signs the contract covering the offer’s tour rate. Still not published; Volāre must explicitly activate.
  • Active — published on the web.

Two states are derived, not stored: Stop sale (when a tour stop-sale covers the offer’s date) and Active · release window (an active offer kept live only because a committed booking exists while inside the release window).

Margin is editable in every status, and editing an active offer reprices it live — existing bookings keep their snapshotted price. Each offer records a margin basis (MarginBasis):

  • Sale (default for new offers) — price = cost ÷ (1 − margin/100). A 20% margin is a real 20% profit on the selling price. Capped below 100% (max 90).
  • Cost (legacy, backfilled onto older offers) — price = cost × (1 + margin/100). A 20% markup is a 16.67% profit on sale.

The basis is frozen into the checkout session and booking snapshot at purchase. See the Financial Model for the margin waterfall.

An offer’s bookability is gated by release windows — the travel-window date ranges on the supplier tour rate, plus each rate’s release_days booking cutoff and any tour stop-sale. Only active offers outside their lead-time floor, outside any covering release window, and outside a stop-sale are bookable on the web; the strictest covering rule applies. Editing and diagnostics stay available in any status. Full pricing and generation detail lives in Offers.

Bulk actions include Activate selected and Recalculate selected (re-runs flight pricing on a queue); the delete action guards offers that already have bookings so historical sales survive.

A Booking is a customer’s purchase of an offer — client, passengers, extras, payments, flight bookings and a full status history. The client’s total_amount is fixed at purchase; downstream fare drift is absorbed by margin, not passed to the customer.

Bookings move through a forward-only state machine (BookingStatus, 17 states): Draft / Checkout → quotation (for larger parties) → payment → flight booking → land confirmation → Confirmed → balance / fully paid → Completed, with Cancelled and Expired as terminal states. Any non-forward move is a manual override requiring a reason, and every transition is audited. See Booking Lifecycle for the state machine and Bookings for the data model.

The booking view shows a full cost breakdown at the actual passenger count — P&L summary, customer payment schedule, how the price was built at purchase, direct supplier costs, land-cost composition, FX position and flight-price variation, with a reconciliation footer. When a deposit exists, a payment schedule (deposit, balance due date, total paid, remaining) and the payments table are shown. The whole cost breakdown is hidden from supplier managers.

The booking view is the operational engine. Key actions, gated by status:

  • Book Flight / Book All Flights — dispatch flight-booking jobs for each leg (at PendingFlightBooking).
  • Retry Flight Booking — after a failed attempt.
  • Issue Flights / Issue Flight — queue the Aerticket ticket-issue job for each eligible flight booking (the ticketing → issued promotion).
  • Confirm Land Services / Confirm Services — advance land confirmation and payment stages.
  • Confirm Availability / Send Checkout Link — for quotation bookings (larger parties).
  • Generate Payment Link — deposit, full or balance links via the payment service.
  • Share Trip with Pax, Log Interaction, Override Attribution, Change Status.

The Diagnose missing offers action lives on Products by Market, not on Bookings; offer-level flight analysis is the per-offer “Recalculate offer” action under Offers.