Skip to main content

Update Journey - Đổi Hành Trình

APIs:

  1. POST /api/v1/services/booking/v1/tim-chuyen - Search new flight (WITH ve_id)
  2. POST /api/v1/services/booking/v1/cap-nhat-hanh-trinh - Calculate fee & confirm

📋 Overview

Đổi chuyến bay trong booking sang chuyến khác (cùng route hoặc khác route).

Flow:

1. Search new flight (must include ve_id)
2. Wait 5 seconds (for DB persistence)
3. Calculate change fee (preview)
4. Confirm & Payment

⚠️ CRITICAL: Search request MUST include ve_id để backend persist full flight data.


🔌 Step 1: Search New Flight

API Endpoint

POST {{base_url}}/api/v1/services/booking/v1/tim-chuyen

Same API as normal search BUT MUST include ve_id.

Request Body

{
"sid": "socket-id",
"chang_bay": [
{
"index": 0,
"diem_di": "SGN",
"diem_den": "HAN",
"ngay_di": "02-11-2025"
}
],
"nhieu_chang": 0,
"hanh_khach": {
"nguoi_lon": 1,
"tre_em": 0,
"em_be": 0
},
"hang_bay": ["VJ"],
"ve_re_thang": 0,
"ma_khuyen_mai": "",
"ve_id": 94
}

Key Difference from Normal Search:

"ve_id": 94  // ← CRITICAL: Include booking ID

Why ve_id is Required:

  • Tells backend to persist full flight data to database
  • Without ve_id, backend only caches data temporarily
  • cap-nhat-hanh-trinh API needs full data in DB

Rule:

  • Normal search: Omit ve_id
  • Update journey: Include ve_id

After Search: Wait for DB Persistence

// After receiving flights from Socket.IO
socket.on("sever-sent-data-end", async (airlines) => {
// Save selected flight UUID
STATE.new_flight_uuid = selectedFlight.uuid;

// IMPORTANT: Wait 5 seconds for DB persistence
console.log("⏳ Waiting 5s for DB persistence...");
await new Promise((resolve) => setTimeout(resolve, 5000));

// Now proceed to calculate fee
});

Why wait: Backend needs time to persist full flight data to DB.


🔌 Step 2: Calculate Change Fee

API Endpoint

POST {{base_url}}/api/v1/services/booking/v1/cap-nhat-hanh-trinh

Headers

{
"Content-Type": "application/json",
"Authorization": "Bearer {access_token}"
}

Request Body (Preview)

{
"ve_id": 94,
"index_chang_bay_doi": 0,
"loai_phi_dai_ly": "Nhập",
"uuid_chuyen_bay": "8a3b697a-aeba-11f0-8b81-86d224031662",
"index_chang_bay_moi": 0,
"xac_nhan": "",
"tong_tien": 0
}

Fields:

FieldTypeRequiredDescription
ve_idnumber✅ YesBooking ID
index_chang_bay_doinumber✅ YesJourney index to change (0-based)
loai_phi_dai_lystring✅ YesFee type: "Nhập" or "Cơ bản"
uuid_chuyen_baystring✅ YesNew flight UUID (from search)
index_chang_bay_moinumber✅ YesNew flight segment index (0-based)
xac_nhanstring✅ YesConfirmation: "" = preview, "y" = confirm
tong_tiennumber✅ YesTotal amount: 0 for preview

⚠️ Index Convention:

  • index_chang_bay_doi: 0-based (0 = first journey to change)
  • index_chang_bay_moi: 0-based (usually 0 for single segment)

Response (Preview)

{
"message": "Tổng tiền thanh toán là 0",
"data": {
"pnr": "2EVXYF",
"tong_tien": 0,
"phi_thay_doi": 378000,
"f2_info": {
"code": "ST2010",
"balance": 58793897,
"sufficient": true
}
},
"status": "success",
"code": 200
}

Response Fields:

FieldTypeDescription
tong_tiennumberAmount difference (new - old flight)
phi_thay_doinumberChange fee
f2_info.balancenumberCurrent F2 wallet balance
f2_info.sufficientbooleanBalance sufficient for payment

Payment Logic:

if (tong_tien > 0) {
// New flight more expensive
payment = tong_tien; // Pay difference + change fee
} else if (tong_tien === 0 && phi_thay_doi > 0) {
// New flight same/cheaper
payment = phi_thay_doi; // Pay only change fee
}

🔌 Step 3: Confirm Change

Request Body (Confirm)

{
"ve_id": 94,
"index_chang_bay_doi": 0,
"loai_phi_dai_ly": "Nhập",
"uuid_chuyen_bay": "8a3b697a-aeba-11f0-8b81-86d224031662",
"index_chang_bay_moi": 0,
"xac_nhan": "y",
"tong_tien": 378000
}

Key Changes from Preview:

{
"xac_nhan": "y", // ← Confirm
"tong_tien": 378000 // ← Actual payment amount
}

Success Response

{
"message": "Cập nhật hành trình thành công",
"data": null,
"status": "success",
"code": 200
}

💡 Complete Example: cURL

Step 1: Search New Flight (with ve_id)

curl -X POST "{{base_url}}/api/v1/services/booking/v1/tim-chuyen" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer {access_token}" \
-d '{
"sid": "socket-id",
"chang_bay": [{
"index": 0,
"diem_di": "SGN",
"diem_den": "HAN",
"ngay_di": "02-11-2025"
}],
"nhieu_chang": 0,
"hanh_khach": {
"nguoi_lon": 1,
"tre_em": 0,
"em_be": 0
},
"hang_bay": ["VJ"],
"ve_re_thang": 0,
"ma_khuyen_mai": "",
"ve_id": 94
}'

Important: Socket.IO will return flights. Save first flight's UUID.

Wait 5 seconds after receiving flights before next step.

Step 2: Calculate Fee

curl -X POST "{{base_url}}/api/v1/services/booking/v1/cap-nhat-hanh-trinh" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer {access_token}" \
-d '{
"ve_id": 94,
"index_chang_bay_doi": 0,
"loai_phi_dai_ly": "Nhập",
"uuid_chuyen_bay": "new-flight-uuid",
"index_chang_bay_moi": 0,
"xac_nhan": "",
"tong_tien": 0
}'

Response:

{
"data": {
"tong_tien": 0,
"phi_thay_doi": 378000
}
}

Step 3: Confirm

curl -X POST "{{base_url}}/api/v1/services/booking/v1/cap-nhat-hanh-trinh" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer {access_token}" \
-d '{
"ve_id": 94,
"index_chang_bay_doi": 0,
"loai_phi_dai_ly": "Nhập",
"uuid_chuyen_bay": "new-flight-uuid",
"index_chang_bay_moi": 0,
"xac_nhan": "y",
"tong_tien": 378000
}'

⚠️ CRITICAL RULES

1. Search MUST Include ve_id

// ❌ Wrong: Normal search for update journey
{
"sid": "...",
"chang_bay": [...],
// Missing ve_id
}
// Result: Flight data NOT persisted → cap-nhat-hanh-trinh fails

// ✅ Correct: Include ve_id
{
"sid": "...",
"chang_bay": [...],
"ve_id": 94 // ← CRITICAL
}
// Result: Flight data persisted to DB → cap-nhat-hanh-trinh works
// After Socket.IO returns flights
const newFlightUUID = flights[0].uuid;

// WAIT for DB persistence
await new Promise((resolve) => setTimeout(resolve, 5000));

// Now can call cap-nhat-hanh-trinh
await calculateChangeFee(newFlightUUID);

3. Index is 0-based

{
"index_chang_bay_doi": 0, // 0 = first journey (0-indexed)
"index_chang_bay_moi": 0 // 0 = first segment (0-indexed)
}

Different from other APIs:

  • Update Services: index_chang_bay is 1-based
  • Update Journey: index_chang_bay_doi is 0-based

4. Payment Calculation

const preview = await calculateChangeFee();
const tong_tien = preview.data.tong_tien;
const phi_thay_doi = preview.data.phi_thay_doi;

let payment;
if (tong_tien > 0) {
payment = tong_tien; // New flight more expensive
} else if (tong_tien === 0 && phi_thay_doi > 0) {
payment = phi_thay_doi; // New flight cheaper, pay change fee only
} else {
payment = 0; // No payment needed
}

// Use in confirm request
await confirmChange({ tong_tien: payment });

5. Fee Type

"loai_phi_dai_ly": "Nhập"  // Always use "Nhập" for update journey

🐛 Common Issues

"Không tìm thấy thông tin"

Cause: ve_id not included in search request

Solution:

// Include ve_id in search
const searchBody = {
...,
ve_id: bookingId
};

"BookingKey is invalid"

Cause: Flight data not persisted in DB

Solutions:

  1. Include ve_id in search
  2. Wait 5 seconds after search before calculate fee

"The reservation balance is greater than the given payment"

Cause: tong_tien mismatch

Solution: Use correct payment amount:

const payment = tong_tien > 0 ? tong_tien : phi_thay_doi;

📊 Change Fee Examples

Case 1: New Flight More Expensive

Old flight: 1,000,000 VND
New flight: 1,500,000 VND
Change fee: 378,000 VND
---
tong_tien: 878,000 VND (difference + fee)

Case 2: New Flight Cheaper

Old flight: 1,500,000 VND
New flight: 1,000,000 VND
Change fee: 378,000 VND
---
tong_tien: 0 VND
phi_thay_doi: 378,000 VND
Payment: 378,000 VND (fee only)

🔗 Complete Flow


⚠️ Important Notes

1. ve_id is CRITICAL

// Update journey search
const searchBody = {
sid: socket.id,
chang_bay: [...],
hanh_khach: {...},
hang_bay: ['VJ'],
ve_id: bookingId // ← MUST INCLUDE
};

Without ve_id, backend will NOT persist flight data → Update journey will fail.

2. Wait After Search

const flights = await searchFlights(ve_id);
await sleep(5000); // 5 seconds
await calculateFee();

3. 0-based Indexing

{
"index_chang_bay_doi": 0, // 0-indexed
"index_chang_bay_moi": 0 // 0-indexed
}

4. Preview vs Confirm

// Preview
{
"xac_nhan": "",
"tong_tien": 0
}

// Confirm
{
"xac_nhan": "y",
"tong_tien": 378000 // From preview response
}

🔗 Next Steps

After updating journey:

  1. View Updated Booking02-GET-DETAILS.md
  2. Payment03-PAYMENT.md (if additional payment needed)

📝 Notes

  • Search request MUST include ve_id for update journey
  • Wait 5 seconds after search for DB persistence
  • index_chang_bay_doi is 0-based (different from update services)
  • loai_phi_dai_ly: Always use "Nhập"
  • Payment = tong_tien or phi_thay_doi (whichever is greater)
  • Change fee usually ~378,000 VND
  • Preview before confirm to check fees
  • Works on both HOLD and ISSUED bookings