Refund Guarantee
Description / Background
Many users are hesitant to prepay for buffet or set menu bookings because they worry about losing money if their plans change. This leads to fewer bookings, especially when cancellation policies are unclear or too strict, which is common on other platforms like Booking.com or hotel websites.
To solve this, Hungry Hub is introducing the Refund Guarantee—an optional add-on at checkout. It allows users to get a full refund (via promo code) if they cancel at least 24 hours before their reservation.
This feature helps build trust, reduces booking risk, and gives Hungry Hub a clear advantage over competitors with less flexible policies.
Objectives
- Admin can set the refund guarantee on package “Accept Refund Guarantee?”
- Admin can select from two Fee Type Choice:
- Percentage of package price (%) → package price is 100 THB and the percentage of refund fee is 10%, so the refund fee is 10 THB
- Fixed price (THB / SGD) → admin input the price number
- Admin can see the
Refund Guaranteelabel on the booking list - At checkout, total price = package price × quantity + refund fee (percentage or fixed)
- The refund fee will be package-based, meaning that if a user books 2 different packages, the user needs to pay for 2 refund fees
- Users and Guest can add
Refund Guaranteewhen they checkout - The
Refund Guaranteeis optional - Users and Guest can only use prepaid for the
Refund Guarantee - Users and Guest can view the terms and conditions of refund guarantee
- The refund section will be displayed when user books package that accepts refund guarantee
- The refund section will be displayed when user books package and add-on that all of them accept refund guarantee
- The refund section will not be displayed when one of the package or add-on user books did not accept refund guarantee
- The refund guarantee will be returned to the gift card when the user books the package using the gift card.
- Guests will receive the refund voucher via email.
- The refund voucher is valid for 1 year (365 days) after it is sent and can be used once.
- The refund guarantee received will be in the form of a promotional voucher.
- The refund guarantee fee is calculated on a per-package and per-add-on basis. Example:
- If user books 2 packages, the refund guarantee will be multiplied by 2
- If user books 1 package and 2 add-ons, the refund guarantee will use 1 price from the package and 2 prices from the add-ons
- When user books using gift card, the refund will be returned to the gift card
- The refund guarantee received will be in the form of a promotional voucher
- CANCEL condition:
- Cancel but out of refund period → Use
Cancelledlabel under the BookingID on Booking List Page - Cancel & refund (When user cancels the booking within the refundable period and claims the refund):
- Use
Cancelled with refundlabel under the BookingID on Booking List Page Admin Dashboard - Use
Canceledon Booking List Page Partner Portal. Once canceled, the payment becomesDue, and the Total Due will only be the package total (excluding the refund guarantee fee). - Automatically refunded via promo code directly (make sure it’s showing on promo code table as well)
- Users receive 100% of the booking price after discounts are applied (excluding the Refund Guarantee fee)
- The refund promo code is valid for 1 year (365 days) from the date of issuance and can be used once.
- Use
- Cancel but out of refund period → Use
- Users and Guest can cancel the booking and claim the refund via:
- Selecting Cancel Booking and Claim Refund in the email confirmation within the required time before dining time
- Claiming through the booking confirmation page
- Users and Guest can’t claim refund when period has ended
- Display tooltip with updated description: “Select Cancel Booking and Claim Refund in the email confirmation within the required time before your dining time to receive a promo code equal to your subtotal (excluding the Refund Guarantee fee)”
- When user clicks
Claim Refund, show pop-up message: “The promo code will be sent to your email and valid for 1 year” - Include refund guarantee information in confirmation email
- Display message: “Select Cancel Booking and Claim Refund on your booking within the required time before your dining time to receive a promo code equal to your subtotal (excluding the Refund Guarantee fee)”
- Include: “The promo code will be sent to your email and valid for 1 year”
- Refund Voucher Specifications
- Format Requirements:
- All countries & currencies (as long as in the same currency)
- All package types supported
- No minimum total price requirement
- No specific city restriction
- No “first time booking only” restriction
- No max pax limitation
- All devices supported
- All payment methods supported
- Not required 100% prepayment
- Don’t allow to mix with points
- Promo code category: Refund Guarantee
- Subsidized by: HungryHub
- Discount type: Fixed amount (equal to subtotal excluding refund fee)
- Max usage: 1 time per voucher
- Expiry date: 1 year (365 days) from issue date
- Every voucher created must be shown on promo code admin dashboard, email, and end user side
- Format Requirements:
Scope
booking flow
Sequence Diagram / Flow

ERD
UML
Backend Implementation
- Created
ReservationRefundGuaranteemodel withreservation_id,refund_fee_cents,refund_currency,refundable_amount_cents,refundable_until,status(pending/claimed/expired), andvoucher_idfields - Added
can_claim_refund?,refund_period_expired?,mark_as_claimed!,mark_as_expired!,pending?,claimed?,expired?, andformatted_refundable_untilmethods toReservationRefundGuaranteemodel - Added
belongs_to :voucher(optional) association toReservationRefundGuaranteemodel to link created refund vouchers - Used Money gem monetization for
refund_feeandrefundable_amountfields inReservationRefundGuaranteemodel - Added
accept_refund_guarantee,refund_type(percentage/fixed_amount),refund_amount, andrefund_hours_in_advancefields toHhPackage::AddOnmodel with validations - Added same refund guarantee fields to
HhPackage::PackageAttrmodel to enable packages to support refund guarantee - Extended
Reservationmodel withrefund_fee_amount_float,refundable_amount_float,has_cancelled_with_refund?, andassign_refund_guarantee_datamethods - Added
has_one :refund_guaranteeassociation toReservationmodel - Added
:cancelled_with_refundstatus symbol to reservation statuses - Integrated
@accept_refundflag and@custom_refund_fee_centsattribute intoChargeCalculatorfor refund guarantee calculation - Modified
ChargeCalculator#calculateto process refund fees for packages and add-ons with refund guarantee enabled - Updated
ChargeCalculator#calc_charge_percentto return 100% when refund guarantee is enabled (requires full prepayment) - Implemented refund fee calculation logic supporting both percentage and fixed_amount types with ceiling rounding
- Added
total_refund_price,total_refund_price_cents,total_refund_price_v2,total_refundable_amount,total_refundable_amount_cents, andtotal_refundable_amount_v2to charge calculation output - Supported custom refund fee override via
custom_refund_fee_centsfor admin adjustments - Refactored
VoucherCalculatorto apply vouchers to combined package + add-on + refund fee totals (vouchers apply to refundable amount, not refund fee itself) - Updated voucher application order to calculate base prices, add refund fees, apply vouchers, then calculate final charge
- Created
RefundGuaranteeClaimServiceto validate reservations, check claimability, cancel bookings, create refund vouchers, and mark guarantees as claimed - Updated
RefundGuaranteeClaimServiceto support guest bookings (non-member) with voucher creation and email delivery - Changed refund voucher expiry from 3 months to 1 year with constant
EXPIRY_DURATION = 1.year - Modified refund voucher to support both member (specific_customer with user_id) and guest (all_restaurants without user_id) voucher types
- Linked created refund voucher to
ReservationRefundGuaranteerecord viavoucher_idforeign key after successful creation - Removed member-only validation for refund guarantee - now supports both members and guest bookings
- Implemented error handling in
RefundGuaranteeClaimServicefor reservation_not_found, refund_not_available, refund_period_expired, refund_already_claimed, and refund_not_claimable scenarios - Removed validation requiring
user_idinReservationService::Form::HungryHubandAgents::UpdateForAdminto allow guest refund guarantee - Updated
ReservationService::Createto acceptcustom_refund_fee_centsand passaccept_refundflag to charge calculator - Modified
CancelReservationServiceto supportclaim_refundparameter that triggers refund guarantee claim flow and skips normal cancellation email notification - Added
accept_refund_guarantee,refund_type,refund_amount, andrefund_hours_in_advancestrong parameters to admin add-ons controller - Created admin UI components in
Price.vueandaddOnSettingStore.jswith refund guarantee checkbox, radio buttons for percentage/fixed price, amount input, and hours in advance input - Implemented admin UI validations ensuring refund type selection, amount > 0, percentage 0-100 range, and hours >= 0
- Updated admin reservations controller to include refund guarantee in
calculate_package_price, support claim via cancel reason, preserve refund data in updates, include inpopulate_seed, and added send refund notification endpoint - Enabled admin custom refund fee override via
custom_refund_fee_centsparameter for special cases - Created new POST endpoint
/api/v5/reservations/:reservation_id/claim_refund.json(member) requiring authentication - Created new POST endpoint
/api/v5/reservations/:encrypted_id/claim_refund_guest.json(guest) without authentication using encrypted reservation ID - Updated member claim refund endpoint to allow guest bookings by checking
reservation.user_id.present?instead of requiring match - Added
accept_refund_guaranteeparameter tocalculate_package_priceAPI endpoint for charge calculation with refund fees - Added
accept_refund_guaranteeparameter to voucher validation API endpoint for refund-aware voucher calculations - Added
accept_refund_guaranteeparameter to reservation creation API endpoints for booking with refund guarantee - Extended
ReservationSerializerwithrefund_fee_v2,refundable_amount_v2, andmax_refundable_atfields (conditional display) - Added
refund_guaranteeobject withtype,amount, andhours_in_advanceto add-on and package serializers - Created
RefundGuaranteeHelperwithcalculate_refundable_until_timeandformat_refund_guarantee_deadlinemethods for deadline calculations - Created
ExpireRefundStatusWorkerbackground worker to automatically expire pending refund guarantees past their deadline with batch processing and error handling - Updated
CheckPaymentWorkerto include refund guarantee data in payment verification - Added
:cancelled_with_refundstatus handling toReservationDecoratorwith red background color (#FFEAEB) and translation support - Created
UserMailer#claim_refund_guaranteemethod to send refund confirmation emails with voucher details for both members and guests - Added email banners and promo code icons:
hh-banner-refund-en.png,hh-banner-refund-th.png,hh-download-app-en.png,hh-download-app-th.png,hh-promo-code-icon-1/2/3.png - Created
claim_refund_guarantee_en.html.erbandclaim_refund_guarantee_th.html.erbemail templates (306 lines each) with voucher code, expiry date, and usage instructions - Created shared partial
_refund_guarantee_description.html.erbwith member/guest-specific messaging (member: profile, guest: email) and 1-year validity period - Updated booking confirmation email templates (AYCE, DIY, PP, XP) for English and Thai to use shared refund guarantee partial instead of inline code
- Refactored email templates for owner, staff, and guest assistance to use shared refund guarantee description partial
- Modified
UserMailer#booking_cancelto skip sending cancellation email when refund guarantee claim is processed (delegated to claim_refund_guarantee mailer) - Triggered
NotificationWorkers::Reservation.perform_in(30.seconds, reservation.id, 'refund')after successful refund claim to send confirmation email - Added i18n translation
actions.reservation.refund_claimed_guestfor guest refund success message in en, th, ko, cn locales - Removed unused i18n key
errors.refund_guarantee.only_for_memberfrom error translations - Added
"refund guarantee"cancel reason constant to reservation class methods - Added
CHARGE_TYPE_ON_CHARGEandCHARGE_TYPE_ON_HOLDconstants to package model - Updated admin reservation UI with “Send Refund Confirmation to User” button for cancelled_with_refund bookings
- Updated
UserCancelWithRefundComponent.vuewith member/guest conditional messaging (profile vs email), 1-year validity text, andis_memberprop support - Updated
quickEdit.vueto passreservationprop (includingis_memberflag) toUserCancelWithRefundComponent - Added
is_memberflag toquick_edit.html.erbtemplate data serialization - Created comprehensive model specs for
ReservationRefundGuarantee(359 lines) covering associations, monetization, status transitions, optional voucher relation, and currency handling - Created service specs for
RefundGuaranteeClaimService(549+ lines) covering successful claims, voucher creation for members and guests, 1-year expiry, validation failures, currency handling, and error scenarios - Refactored charge calculator specs to cover refund guarantee fee calculation (percentage & fixed), custom fee override, charge percent 100% enforcement, and voucher integration
- Created new voucher calculator specs (620 lines) covering package/delivery vouchers, combined vouchers, percentage/fixed amounts, deductible vouchers, and priority sorting
- Created worker specs for
ExpireRefundStatusWorker(383 lines) covering batch expiration, time-based filtering, status updates, and error handling - Created factory for
reservation_refund_guaranteestest data generation - Updated package form Vue components (
PackageForm.vue,PricingForm.vue,form.vue) to support refund guarantee settings with UI controls and validations - Updated
quickEdit.vueadmin component to display and manage refund guarantee data - Added refund guarantee UI to admin reservation audit data, quick edit, and reservation views
- Updated reservation report worker to include refund guarantee data in reporting
- Passed
accept_refund_guaranteeflag through voucher form validation - Updated
pt_add_referencehelper inPtOnlineSchemaChange::Helperto support custom foreign key constraint names via:nameoption - Added
voucher_idcolumn toreservation_refund_guaranteestable via migration20251216094800_add_voucher_relation_to_reservation_refund_guarantees.rb - Added foreign key constraint
fk_reservation_refund_guarantees_voucher_idonvoucher_idreferencingvouchers.idusing pt-online-schema-change - Created data task migration
20251217033132_backfill_vouchers_on_reservation_refund_guarantees.rbto backfill existing voucher links - Added
accept_refundandcustom_refund_fee_centsfields toreservation_propertiestable - Created
reservation_refund_guaranteestable with indexes onreservation_id,status,refundable_until, andvoucher_id - Added refund guarantee columns to
hh_package_package_attrstable with indexes - Added refund guarantee columns to
add_onstable with indexes - Updated database schema to reflect all refund guarantee tables, columns, and foreign key relationships
https://github.com/hungryhub-team/hh-server/pull/7183 https://github.com/hungryhub-team/hh-server/pull/7572
Mobile Implementation (Android)
- Created new
RefundGuaranteeKotlin data class (app/src/main/java/com/hb/hungryhub/model/hybrid/checkout/RefundGuarantee.kt) with three fields:type,amount, andhours_in_advance - Used
@SerializedNameannotations for JSON serialization/deserialization from API responses - Added
refund_guaranteefield toPackagemodel (app/src/main/java/com/hb/hungryhub/model/bookingguest/Package.java) with Gson@Exposeannotation - Implemented getter and setter methods for
refundGuaranteeinPackagemodel - Imported
RefundGuaranteeclass inPackagemodel to support refund guarantee data structure - Added
refund_guaranteefield toAddOnmodel (app/src/main/java/com/hb/hungryhub/model/hybrid/checkout/AddOn.java) with Gson@Exposeannotation - Implemented getter and setter methods for
refundGuaranteeinAddOnmodel - Enabled packages to carry refund guarantee information including fee type (percentage or fixed), amount value, and minimum hours in advance for eligibility
- Enabled add-ons to support refund guarantee feature with same data structure as packages
https://github.com/hungryhub-team/hh-android/pull/2086
Hybrid Implementation (Web/PWA)
- Added
RESERVATION_CANCELLED_WITH_REFUNDconstant for tracking cancelled bookings with refund status - Added
VOUCHER_CATEGORY_REFUND_GUARANTEEconstant for refund guarantee voucher category - Added
EVENT_ON_BOOKING_CANCELLEDconstant for hybrid event when booking is cancelled - Created
RefundGuaranteeSchematype definition withtype,amount, andhoursInAdvancefields - Extended
PackandAddOnschemas to includerefundGuaranteeproperty for type safety - Extended booking charge types to include
refund_guaranteeandsubtotal_refund_guaranteeitems - Extended voucher categories to include
refund_guaranteetype - Added
acceptRefundGuaranteeboolean parameter tocalculateChargeAPI payload schema - Created
claimRefund.tsAPI service with POST endpoint to cancel booking and claim refund with error handling usinguseHandleErrorcomposable - Added
claimRefundGuestfunction toclaimRefund.tsAPI service for guest users to claim refund using encrypted booking ID - Added
acceptRefundGuaranteeparameter andrefundFeeV2/maxRefundableAtresponse fields tocreateBookingAPI - Extended
getBookingDetailAPI response schema withrefundFeeV2,maxRefundableAt,refundableAmountV2,dueAmountV2, andprepaidAmountV2fields - Added
acceptRefundGuaranteeparameter tovalidateVouchersAPI payload - Created
RefundGuarantee.vuecomponent (202 lines) with radio button selector, gradient borders (green/red), shield icons, price fetching, loading state, and view details link - Created
RefundGuaranteeTnc.vuecomponent displaying terms, 3-step how-it-works guide, gift card terms, how-to-buy guide with responsive layout and i18n support - Updated
RefundGuaranteeTnc.vueto show dynamic content based on user authentication status (member vs guest instructions) - Hidden gift card terms section for guest users in
RefundGuaranteeTnc.vue - Created
RefundGuaranteePage.vuecomponent (75 lines) as modal/bottom sheet container with lazy loading for terms content - Created
RefundGuaranteeLabel.vuecomponent displaying refundable deadline with Tippy.js tooltip on booking confirmation - Updated
RefundGuaranteeLabel.vueto acceptisUserSignedInprop and display dynamic tooltip content (email vs profile instructions) - Created
RefundGuaranteeModal.vuereusable modal component (106 lines) with customizable title, subtitle, description, cancel/confirm buttons - Updated
ChargeItem2.vueto supportrefund_guaranteeandsubtotal_refund_guaranteecharge types, hide quantity display, and treat as charge types - Integrated
RefundGuaranteecomponent intoCheckOutPage.vuewith visibility conditions (prepaid, hours in advance check) and selection validation with toast error - Removed user sign-in requirement for displaying refund guarantee at checkout (now available for guests)
- Added refund guarantee state reset on checkout page exit and mount
- Added “Extra Coverage” section title slot and retry button for failed calculations in
BookingChargeSummary2.vue - Implemented border styling logic in
BookingChargeSummary.vueto visually separate refund items with borders - Added
acceptRefundGuaranteestate (string: “”, “true”, “false”) andresetRefundGuarantee()action to booking store - Created
isAcceptRefundGuaranteegetter in booking package store to check if packages/add-ons support refund guarantee - Created
maxRefundGuaranteeHoursgetter to return maximum hours in advance from all selected items - Added
totalRefundPriceV2andtotalRefundableAmountV2fields to booking charge store state - Modified
calculateChargein booking charge store to acceptapplyChargeDataparameter controlling store data application - Updated calculate charge payload to include
acceptRefundGuaranteeflag based on store state and package acceptance - Added
maxRefundableAtfield to booking confirmation store data - Added
totalRefundPriceV2,totalRefundableAmountV2, anddueAmountV2fields to booking confirmation charge object - Created
isBeforeRefundableDategetter using dayjs to check if current time is before refund deadline - Mapped
prepaidAmountV2tochargePriceV2in booking confirmation to show paid amount - Added
refund_guaranteeto voucher categories inOffersPage.vue,AvailablePromoCode.vue,ExpiredPromoCode.vue, andOffersList.vue - Added translation mapping for
cancelledWithRefundstatus inBookingHistoryCard.vue - Updated
BookingHistoryCard.vueto hide action button for bookings withcancelled_with_refundstatus - Added green shield icon display for active refund guarantee bookings in
UpcomingBookingDesktop.vueandUpcomingBookingMobile.vue(only before deadline) - Extended
ChargeObjecttype to includetotalRefundPriceV2andtotalRefundableAmountV2fields - Updated
buildChargeSummaryfunction inbookingCharge.tsto add subtotal item and refund guarantee charge item with estimated prices - Added refund guarantee support in charge summary parsing for booking confirmation in
chargeSummary.ts - Included
acceptRefundGuaranteein calculate charge payload for confirmation page calculations - Conditionally added
acceptRefundGuaranteeto booking payload increateBooking.tswhen package accepts, user selected “true”, and booking has charge price - Updated
rebuildPackagesDataandrebuildAddOnsDataincheckOutEvents.tsto preserverefundGuaranteedata during rebuilds - Included
acceptRefundGuaranteein voucher validation payload invalidateVoucher.ts - Included
refundGuaranteein package and add-on payload data ingetBookingProcessData.ts - Set
acceptRefundGuarantee: falsein calculate charge payload for booking edit inBookingEditChargeSummary.vueto prevent recalculation - Updated
BookingConfirmationContent.vueto handle guest and member refund claim flows separately with different API calls - Added
guestRedirectionAfterClaimRefundfunction to redirect guests after successful refund claim (hybrid event or home page) - Updated refund confirmation modal to display dynamic message based on authentication status (profile vs email delivery)
- Updated
BookingConfirmationContainer.vueto handlecancelled_with_refundstatus as payment-failed state - Added claim refund button with state-based styling in
BookingConfirmationSidebar.vue - Updated
BookingConfirmationDesktop.vueandBookingConfirmationMobile.vueto passisUserSignedInprop toRefundGuaranteeLabel - Updated payment type computed property to use
dueAmountV2for remaining payment amount - Added guest-specific translation keys in 16 language files:
submitYourClaimViaEmail,selectClaimRefundGuest,get100PercentPromoCodeRefundGuest,selectCancelAndClaimRefundInEmail,thePromoCodeWillBeSentToEmail - Updated promo code validity period from 3 months to 1 year in all language files
- Added
subtotaltranslation key in 16 language files (English, Thai, Japanese, Korean, Chinese Simplified/Traditional, Indonesian, Malay, Vietnamese, French, German, Spanish, Russian, Khmer, Lao) - Created SVG icon files:
icon-shield-check.svg,icon-shield-cross.svg - Created PNG icon files:
icon-shield-gray.png,icon-shield-green.png,icon-shield-red.png - Created guarantee step icons:
icon-buy-guarantee-step-1.svg,icon-buy-guarantee-step-2.svg - Created guarantee feature icons:
icon-guarantee-1.png,icon-guarantee-2.png - Created guide images:
buy-guarantee-1.png,buy-guarantee-2.png
https://github.com/hungryhub-team/hh-pegasus/pull/2058 https://github.com/hungryhub-team/hh-pegasus/pull/2398
PRD & Task
PRD:
- https://app.clickup.com/9003122396/docs/8ca1fpw-7922/8ca1fpw-52016
- https://app.clickup.com/9003122396/v/dc/8ca1fpw-7922/8ca1fpw-56816
Tasks: https://app.clickup.com/t/86cze8rc8 https://app.clickup.com/t/86d18dqmf
Design
user : https://www.figma.com/design/suDZ8JohloPf0kpLZ9AuL7/Checkout-Page?node-id=7197-2345&t=dYD29w4xEt2YGFZZ-1 v2 and guest: https://www.figma.com/design/suDZ8JohloPf0kpLZ9AuL7/Checkout-Page?node-id=7197-2345&t=cn78twhOsoWXUMqV-1
API Blueprint
User APIs (API v5)
| Method | Path | Description | Authentication | Parameters |
|---|---|---|---|---|
| POST | /api/v5/reservations/:reservation_id/claim_refund.json | Cancel booking and claim refund guarantee (member) | Required (Bearer token) | reservation_id (in path) |
| POST | /api/v5/reservations/:encrypted_id/claim_refund_guest.json | Cancel booking and claim refund guarantee (guest) | Not required (uses encrypted ID) | reservation_id (encrypted, in path) |
| POST | /api/v5/restaurants/:restaurant_id/calculate_package_price | Calculate booking charges including refund fees | Optional | accept_refund_guarantee (boolean), package_bought (array), adult (integer), kids (integer), distance (float) |
| POST | /api/v5/vouchers/validate | Validate vouchers with refund guarantee consideration | Required | accept_refund_guarantee (boolean), voucher codes, booking details |
| POST | /api/v5/reservations | Create reservation with refund guarantee | Required | reservation object with accept_refund_guarantee flag |
Admin APIs
| Method | Path | Description | Authentication | Parameters |
|---|---|---|---|---|
| POST | /admin/reservations/:id/calculate_package_price | Calculate charges for admin bookings (supports custom refund fee) | Admin session | accept_refund (boolean), custom_refund_fee_cents (integer), package/add-on details |
| PUT | /admin/reservations/:id | Update reservation (preserves refund guarantee) | Admin session | Full reservation object with refund guarantee data |
| POST | /admin/reservations/:id/cancel | Cancel booking with optional refund claim | Admin session | reason (string, set to “refund guarantee” to claim) |
| POST/PUT | /admin/add_ons | Create/Update add-on with refund guarantee settings | Admin session | accept_refund_guarantee, refund_type, refund_amount, refund_hours_in_advance |
Vendor APIs (No direct refund guarantee endpoints, uses standard booking flow)
All vendor APIs maintain compatibility with refund guarantee through existing booking creation flows.
API Response Examples
Claim Refund Success Response (Member)
{
"success": true,
"data": null,
"message": "Refund claimed successfully"
}
Claim Refund Success Response (Guest)
{
"success": true,
"data": null,
"message": "Your booking has been cancelled and a promo code has been sent to your email"
}
Claim Refund Error Responses
// 403 Forbidden (Member endpoint only)
{
"success": false,
"message": "You are not authorized to access this reservation",
"data": null
}
// 404 Not Found
{
"success": false,
"message": "Reservation not found",
"data": null
}
// 422 Unprocessable Entity (various refund errors)
{
"success": false,
"message": "Refund guarantee has expired" | "Refund already claimed" | "Refund not available",
"data": null
}
Calculate Charge Response (with Refund Guarantee)
{
"success": true,
"data": {
"total_price": 1150,
"total_price_cents": 115000,
"total_price_v2": 1150,
"charge_price": 1150,
"charge_price_cents": 115000,
"charge_percent": 100,
"total_refund_price": 100,
"total_refund_price_cents": 10000,
"total_refund_price_v2": 100,
"total_refundable_amount": 1050,
"total_refundable_amount_cents": 105000,
"total_refundable_amount_v2": 1050,
"selected_packages": [...],
"selected_add_ons": [...],
"currency": "THB"
}
}
Reservation Serializer (with Refund Guarantee)
{
"id": 12345,
"status": "pending_arrival",
"refund_fee_v2": 100,
"refundable_amount_v2": 1050,
"max_refundable_at": "2025-11-23T14:00:00+07:00",
// ... other reservation fields
}
Package/Add-on Serializer (with Refund Guarantee Settings)
{
"id": 1234,
"name": "Premium Buffet Package",
"refund_guarantee": {
"type": "percentage",
"amount": "10",
"hours_in_advance": 24
},
// ... other package fields
}
New Query
No new complex queries added. Uses standard ActiveRecord associations and scopes.
DB Schema / Database Migration
-
Create
reservation_refund_guaranteesTableColumn Type Null Default Description idbigint NO Primary key reservation_idinteger YES Foreign key to reservations table refund_fee_centsinteger NO 0 Refund guarantee fee paid (in cents) refund_currencystring(191) YES ‘THB’ Currency code refundable_amount_centsinteger NO 0 Amount that can be refunded (in cents) refundable_untildatetime YES Deadline for claiming refund statusstring(191) YES Enum: pending, claimed, expired created_atdatetime NO Record creation timestamp updated_atdatetime NO Record update timestamp -
Add Refund Guarantee Fields to
hh_package_package_attrsTableColumn Type Null Default Description accept_refund_guaranteeboolean YES false Whether package accepts refund guarantee refund_typestring(191) YES Enum: percentage,fixed_amountrefund_amountinteger YES Percentage value (0-100) or amount in cents refund_hours_in_advanceinteger YES Minimum hours before booking for refund eligibility -
Add accept_refund_guarantee, refund_type, refund_amount, refund_hours_in_advance to
add_onsTable -
Add Refund Guarantee Fields to
reservation_propertiesTableColumn Type Null Default Description accept_refundboolean YES false Whether booking has refund guarantee custom_refund_fee_centsinteger YES Admin override for refund fee (in cents)
Indexes:
index_reservation_properties_on_accept_refundindex_add_ons_on_accept_refund_guaranteeindex_hh_package_package_attrs_on_accept_refund_guaranteeindex_reservation_refund_guarantees_on_reservation_idindex_reservation_refund_guarantees_on_statusindex_reservation_refund_guarantees_on_refundable_until
Schema Relationships
reservations
└─ has_one :refund_guarantee (reservation_refund_guarantees)
└─ has_one :property (reservation_properties)
└─ stores: accept_refund, custom_refund_fee_cents
hh_package_packages
└─ has_one :package_attr (hh_package_package_attrs)
└─ stores: accept_refund_guarantee, refund_type, refund_amount, refund_hours_in_advance
add_ons
└─ stores: accept_refund_guarantee, refund_type, refund_amount, refund_hours_in_advance (directly on table)
vouchers
└─ new category: 'refund_guarantee' (uses existing vouchers table)
Improvement:
| Feature Name | Date | What Changed | Description |
|---|---|---|---|