Update Journey - Đổi Hành Trình
APIs:
POST /api/v1/services/booking/v1/tim-chuyen- Search new flight (WITH ve_id)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-trinhAPI 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:
| Field | Type | Required | Description |
|---|---|---|---|
ve_id | number | ✅ Yes | Booking ID |
index_chang_bay_doi | number | ✅ Yes | Journey index to change (0-based) |
loai_phi_dai_ly | string | ✅ Yes | Fee type: "Nhập" or "Cơ bản" |
uuid_chuyen_bay | string | ✅ Yes | New flight UUID (from search) |
index_chang_bay_moi | number | ✅ Yes | New flight segment index (0-based) |
xac_nhan | string | ✅ Yes | Confirmation: "" = preview, "y" = confirm |
tong_tien | number | ✅ Yes | Total 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:
| Field | Type | Description |
|---|---|---|
tong_tien | number | Amount difference (new - old flight) |
phi_thay_doi | number | Change fee |
f2_info.balance | number | Current F2 wallet balance |
f2_info.sufficient | boolean | Balance 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
2. Wait After Search
// 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_bayis 1-based - Update Journey:
index_chang_bay_doiis 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:
- Include
ve_idin search - 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:
- View Updated Booking →
02-GET-DETAILS.md - Payment →
03-PAYMENT.md(if additional payment needed)
📝 Notes
- Search request MUST include
ve_idfor update journey - Wait 5 seconds after search for DB persistence
index_chang_bay_doiis 0-based (different from update services)loai_phi_dai_ly: Always use"Nhập"- Payment =
tong_tienorphi_thay_doi(whichever is greater) - Change fee usually ~378,000 VND
- Preview before confirm to check fees
- Works on both HOLD and ISSUED bookings