Skip to content

Offers

Create travel offers by selecting flights from the Dynamic Flight Cache. Offers combine a MarketProduct with a departure airport, date, and price.

Offers represent bookable travel packages that combine:

  • MarketProduct - The travel product (tour, package, etc.)
  • Departure Airport - Where the flight departs from
  • Departure Date - When the flight departs
  • Price - Total offer price
  • CUG Type - Closed User Group fare type

Table: offers

ColumnTypeDescription
idBIGINTPrimary key
product_by_market_idBIGINTFK to products_by_market
departure_airport_idBIGINTFK to airports
departure_dateDATEFlight departure date
total_priceDECIMAL(10,2)Offer price
cug_typeVARCHAR(10)CUG fare type (ALL, TOP, ETH, CRU)
created_atTIMESTAMP-
updated_atTIMESTAMP-

Constraints:

  • Unique: (product_by_market_id, departure_airport_id, departure_date, total_price, cug_type)
  • Foreign keys cascade on delete
use App\Models\Offer;
// Create an offer
$offer = Offer::create([
'product_by_market_id' => 1,
'departure_airport_id' => 10,
'departure_date' => '2026-03-15',
'total_price' => 599.00,
'cug_type' => 'ALL',
]);
// Access relationships
$offer->productByMarket; // ProductByMarket model
$offer->departureAirport; // Airport model
// Query offers by market
$offers = Offer::whereHas('productByMarket', function ($query) use ($marketId) {
$query->where('market_id', $marketId);
})->get();
// Get offers with relationships
$offers = Offer::with([
'productByMarket.productTemplate',
'productByMarket.market',
'departureAirport',
])->get();
// Filter by date range
$offers = Offer::whereBetween('departure_date', [$startDate, $endDate])->get();

Location: /admin/offers

  1. Select Market Product from dropdown
  2. Select Departure Airport (filtered by product’s flight configs)
  3. View cached flights in the table
  4. Use filters: Month, Day of Week, CUG Type, Price Range
  5. Select multiple rows and click Create Offers

Duplicates are automatically skipped with a notification showing how many were created vs. skipped.

  • View all offers with filters for product, market, airport
  • Click to view offer details
  • Delete individual offers or bulk delete

Note: Offers are immutable once created (no edit functionality).

class Offer extends Model
{
public function productByMarket(): BelongsTo
{
return $this->belongsTo(ProductByMarket::class);
}
public function departureAirport(): BelongsTo
{
return $this->belongsTo(Airport::class, 'departure_airport_id');
}
}
protected $casts = [
'departure_date' => 'date',
'total_price' => 'decimal:2',
];

Closed User Group fare types:

TypeDescription
ALLAll available fare categories
TOPTour operator fares
ETHEthnic/VFR (Visiting Friends & Relatives)
CRUCruise passenger fares

Test File: tests/Feature/Models/OfferTest.php

Coverage (8 tests):

  • Model relationships
  • Date and decimal casting
  • CUG type attribute
  • Cascade delete
  • Unique constraint (duplicate prevention)
  • Different prices allowed for same date

Run Tests:

Terminal window
./vendor/bin/sail artisan test tests/Feature/Models/OfferTest.php