This document summarizes what has been implemented so far for the M&M bundle-pricing architecture, what changed in existing APIs, and what new APIs were introduced.
src/shared/enums/hotel-category.enum.tssrc/shared/entity/itinerary-bundle-pricing.entity.tssrc/shared/entity/itinerary-bundle-capacity-price.entity.tssrc/shared/entity/itinerary.entity.tstripTypebundlePricingsrc/shared/entity/hotel-itinerary-mapping.entity.tscategory and locationIdUpdated controller: src/modules/itinerary/itinerary.controller.ts
GET /v1/itinerary/:id/price-details — admin (jwt + TRIP permission)GET /v1/itinerary/:id/customer-price-details — customer (booking-jwt); alias GET /v1/itinerary/:id/price-details-bookingPUT /v1/itinerary/:id/pricing-table — admin pricing master updatePOST /v1/bookings with required pricingSelection — customer booking createNow supports optional query params on GET price-details:
adults, children / childrenWithoutBed (alias), extraMattressCount / childrenWithBed (alias)selectedCategoryselectedTransferIdselectedVehicleNameselectedCapacityMin, selectedCapacityMaxincludeDinnerSupplementchannel (b2b or b2c; defaults to b2b if omitted)Purpose split:
GET /price-details (channel=b2b): category locked to tripType; markup fields shown separately in summary.GET /customer-price-details (auto channel=b2c): markup folded into price; selectedCategory honored.PUT /pricing-table: updates bundle/activity pricing configuration for itinerary.POST /bookings + pricingSelection: validates channel must be b2c, snapshots computed price into booking.priceDetails.availableCategories in price-details response:
hotel_transfer and hotel_only: always returns all five HotelCategoryEnum values [1,2,3,4,5].transfer_only and activities_only: returns only categories present in bundle pricing + tripType category.Updated DTO/controller/service:
src/modules/hotel/dto/map-hotel-itinerary.dto.tssrc/modules/hotel/hotel.controller.tssrc/modules/hotel/hotel.service.tsExisting endpoint:
POST /v1/hotel/map-itineraryNew optional payload fields added:
categorylocationIdPurpose: support primary scoping and category-aware hotel mapping for itinerary bundle architecture.
Updated DTO/service:
src/modules/bookings/dto/create-booking.dto.tssrc/modules/bookings/bookings.service.tsExisting endpoint: booking create flow now requires pricingSelection (b2c), including bundle selectors:
selectedCategoryselectedCapacityMinselectedCapacityMaxincludeDinnerSupplementchildrenWithBedchildrenWithoutBedPurpose: booking calculation can be performed from bundle matrix + selected capacity bucket.
Updated service: src/modules/days/days.service.ts
Existing endpoint behavior changed to:
data.itineraryDetails.daysdata.itineraryDetails.hotelsdata.itineraryDetails.transfersinstead of embedding hotels/transfers inside each day.
All added in src/modules/itinerary/itinerary.controller.ts.
PUT /v1/itinerary/:id/pricing-tablePricingTableUpsertDto (src/modules/itinerary/dto/pricing-table.dto.ts)bundle-pricing and default-category endpoints (those were never shipped to the live controller).scenario field: hotel_transfer, hotel_only, transfer_only, activities_only.Note: The previously documented
PUT /v1/itinerary/:id/default-category,PUT /v1/itinerary/:id/bundle-pricing, andGET /v1/itinerary/:id/bundle-pricingendpoints were never added to the controller and do not exist in the live codebase. Do not call them.
POST /v1/itinerary/import-itinerary-fullImportItineraryFullDtosrc/modules/itinerary/dto/import-itinerary-full.dto.tsThis API is designed for the "import all at once" requirement and supports:
transferIds)hotelIds)hotelDayMappings)activities with dayOrder, mandatory startTime, optional duration)bundlePricing)Implemented in src/modules/itinerary/itinerary.service.ts:
Transfer mapping:
transferIds)Hotel mapping:
hotelIds)hotelDayMappings (hotelId + dayOrder)hotelDayMappings not provided, maps hotel to all itinerary days with matching locationActivity mapping:
startTime (required) and duration (optional) in activity_other_detailsday_resource_mapping using dayOrderTransfer mapping:
transferIds)Bundle pricing rows can be created in same import request.
Implemented in publish toggle flow (src/modules/itinerary/itinerary.service.ts + src/modules/itinerary/itinerary.repository.ts).
Validation now follows scenario-specific rules:
hotel + transfer (+activities):hotel-only:transfer-only:activities-only:adultPrice requiredAlso aligned:
tripType, hotel category, and bundle pricing category now use the same category enum semantics.tripType is treated as canonical category source.BASIC behavior is treated as STANDARD for compatibility handling.Transfer mapping defaults:
isPrimary=truesrc/modules/transfer/transfer.repository.tsTraveler/pricing interfaces extended for bundle selectors:
src/shared/interfaces/traveler-counts.interface.tssrc/modules/itinerary/interface/traveler-details.interface.tsitineraryDetails.hotels and itineraryDetails.transfers.PUT /v1/itinerary/:id/default-category, PUT /v1/itinerary/:id/bundle-pricing, and GET /v1/itinerary/:id/bundle-pricing were listed in earlier drafts of this doc but were never added to the controller. Use PUT /v1/itinerary/:id/pricing-table instead.POST /v1/bookings) enforces pricingSelection.channel = "b2c" — sending "b2b" returns ERR_BOOKING_PRICING_CHANNEL_MUST_BE_B2C.Markup entity (differentiated by category field: 'markup' vs 'gst'). Neither is a hardcoded constant. When no markup/GST is configured, the price is returned at base cost and gstPercent/gstAmount are null in the summary.