Decimal Price
Description / Background
Decimal price for Singapore expansion
Glossary
https://app.clickup.com/9003122396/docs/8ca1fpw-35796/8ca1fpw-41516
Objectives
- User can see the price until the cents number
- User can pay the prepaid booking with decimal number
- System will not display for
.00 - This feature has a flipper to enable or disable the feature

Sequence Diagram / Flow
Backend Implementation
-
app/controllers/api/v5/pages_controller.rb: Added a new feature toggle for enabling decimal prices. -
Adjusted the calculation for total amount and due amount to handle decimal values more accurately.
-
Added new attributes to handle prices in both integer and decimal formats.
-
Changed amount calculation to use floating-point numbers instead of integers.
-
Updated price formatting to conditionally remove cents if the price is a whole number.
-
Updated to handle and display prices accurately, including conditional formatting for whole numbers and decimals.
-
Added validation and monetization for amount in cents.
-
Added methods to handle price in both cents and decimal formats.
-
app/models/hh_package/pricing.rb: Changed price handling from integer to floating-point. -
app/my_lib/hh_money.rb: Added methods to handle prices with and without cents. -
app/my_lib/hh_package/reservation_packages/charge_calculator.rb: Updated calculations to handle decimal values accurately. -
app/my_lib/hh_package/reservation_packages/voucher_calculator.rb: Adjusted voucher calculations to handle cents. -
app/my_lib/my_active_merchants/gb_primepay_gateway.rb: Changed amount handling to use floating-point numbers. -
app/my_lib/receptionist/credit_card_checker.rb: Changed charge amount handling to use floating-point numbers. -
Added logic to handle prices in cents and decimals based on feature toggles.
-
Updated payment summary to handle decimal values and added a private method to format values to decimals.
-
A new currency/money field named
amount_v2is added to several models and calculations to handle monetary values with higher precision (to_d) while maintaining backward compatibility with the existingamountfield (which usesto_i). -
A new migration file (
20250415062310_add_amount_v2_cents_to_reservation_vouchers.rb) adds a fieldamount_v2_centsto thereservation_voucherstable. -
The
ReservationVouchermodel now includes theamount_v2field usingmonetize. Methods dealing withamountare updated to useamount_v2where necessary. -
Example updates include:
- Using
amount.to_dfor precise calculations. - Updating
assign_amount_voucherto store both the integer (to_i) and decimal (to_d) representations.
- Using
-
Controllers like
api/v5/vouchers_controller.rbanddashboard/v2/reservations_controller.rbare modified to includeamount_v2in their logic and response payloads. -
Example: The
serialized_vouchermethod now includesvouchers_amount_v2in the metadata. -
Services such as
partner_service/bills/calculate_service.rbnow useamount_v2_centsfor summing voucher values instead ofamount_cents. -
VoucherForm::Applyintroduces a new methodvouchers_amount_v2to calculate the total amount using theamount_v2field. -
The
Api::V5::ReservationSerializernow includesamount_v2in its serialized output for vouchers. -
Updates in views like
admin/vouchers/show.html.slimto displayamount_v2instead ofamount. -
The
voucher_calculatorclass is updated with logic for handlingamount_v2in various calculations (e.g.,get_voucher_amount_v2,assign_used_vouchers). -
Both
amountandamount_v2exist in parallel, ensuring backward compatibility while transitioning to the new field. -
Handles backfill for the
amount_v2field on charges. -
Changes include:
- Skipping charges where
amountisnilor zero. - If
amountisnil, it sets it to0and updates the database without validations. - Updates the
amount_v2_centsandamount_v2_currencyfields directly in the database usingupdate_column.
- Skipping charges where
-
Handles backfill for the
total_price_v2_centsandcharge_price_v2_centsfields on reservations. -
Changes include:
- If no reservations are found to process, it raises an
ActiveRecord::Rollbackinstead of just returning. - Updates
total_price_v2_centsandcharge_price_v2_centsdirectly in the database usingupdate_column.
- If no reservations are found to process, it raises an
-
The workers now prefer
update_columnfor direct database updates instead ofsave!to skip validations and improve performance. -
Added a new entry in
sidekiq_scheduler.yml:backfill_decimals_price_and_charge:- Scheduled to run daily at midnight (UTC+7 timezone).
- Executes the
ScheduleWorkers::Decimals::BackfillDecimalsworker.
https://github.com/hungryhub-team/hh-server/pull/6395/files
https://github.com/hungryhub-team/hh-server/pull/6369
https://github.com/hungryhub-team/hh-server/pull/6542
https://github.com/hungryhub-team/hh-server/pull/6511
Hybrid Implementation
getBookingDetail.ts:- Added new fields
chargePriceDecimalandtotalPriceDecimal, which store price values as strings.
- Added new fields
searchRestaurantGraphql.ts:- Added
amountCentsto thepriceAndPricingTypeobject, which stores the price in cents.
- Added
BookingSummary.vue:- Updated the display of the total price to use a new
isInCentsparameter for formatting money.
- Updated the display of the total price to use a new
RestaurantCardRoot.vue:- Added
isInCentsparameter to theformatMoneyfunction call.
- Added
string.ts:- Modified the
formatMoneyfunction to handle theisInCentsparameter. IfisInCentsis true, it converts cents to the main currency unit before formatting.
- Modified the
onHoldPrice.ts:- Changed the
pricePerPersonandpricefields to usechargePriceCents. - Added the
isInCentsparameter when formatting money.
- Changed the
restaurant.ts:- Added
amountCentsto thepriceV2object.
- Added
BookingConfirmationDesktop.vueandBookingConfirmationMobile.vue:- Added the
isInCentsparameter when formatting money.
- Added the
PaymentSuccessPage.vue:- Added the
isInCentsparameter when formatting money. - Modified the calculation of
amountandchargePriceto use cents values.
- Added the
QrPackagePage.vueandQrPackagePageDesktop.vue:- Added the
isInCentsparameter when formatting money.
- Added the
SearchRestaurantCard.vue:- Added
currencyto the price display. - Imported
convertToNumberand used it to format the lowest price.
- Added
SelectDateTime.vue:- Simplified icon class names.
PopUpTotalPrice.vue:- Changed the
totalPricefield tototalPackagePriceCentsand added theisInCentsparameter when formatting money.
- Changed the
BookingEditChargeSummary.vue:- Added new fields
chargePriceCents,totalPriceCents, andtotalPackagePriceCentsto thechargeObject.
- Added new fields
BookingSummary.vue:- Changed the
totalPricefield tototalPriceCents.
- Changed the
BreadCrumbs.vue:- Simplified class names.
bookingCharge.ts:- Added
chargePriceCentsandtotalPriceCentsfields to theChargeObjecttype. - Modified functions to use these new fields and convert cents to the main currency unit.
- Added
chargeSummary.ts:- Added the
chargePriceCentsandtotalPriceCentsfields to theChargeObjecttype. - Modified functions to use these new fields and convert cents to the main currency unit.
- Added the
Booking.ts:- Added
chargePriceCents,totalPriceCents, andtotalPackagePriceCentsto thebookingChargeSchema.
- Added
Restaurant.ts:- Added
amountCentsto thepricePerPersonandpriceAndPricingTypeobjects.
- Added
https://github.com/hungryhub-team/hh-pegasus/pull/1678
Partner Portal Implementation
- The original implementation used
accounting.formatMoneyto format the price with no decimal places (precision set to0). - Sets the precision to 2 decimal places (for more accurate monetary representation).
- Checks if the resulting
formattedPriceends with.00.- If true, it removes the trailing
.00for cleaner formatting. - Otherwise, it returns the formatted price as-is.
- If true, it removes the trailing
- The code now checks if there is a preformatted price (
item.price_format). If it exists, it usesitem.price_format; otherwise, it falls back to formatting the price withformatMoney. - This ensures that any preformatted price provided is prioritized over dynamically formatting it.
- The total package price is now calculated from
response.data.total_package_price_centsby dividing it by 100 (to convert from cents to the base currency). The result is then stored inthis.totalPackagePrice. - This change standardizes the handling of monetary values to use cents, which is a common practice to avoid floating-point errors in calculations.
- The function now uses
accounting.formatMoneyto format the price but replaces trailing.00,.X0, or.0Xwith a more compact representation (e.g., removes unnecessary zeros). The new regex ensures that only significant decimal places are retained. - This change improves the formatting of prices, making them cleaner and easier to read.
https://github.com/hungryhub-team/book-bite/pull/656
https://github.com/hungryhub-team/book-bite/pull/792
PRD & Task
https://app.clickup.com/t/86cy3bqmr
Design
no design