Merged in fix/refactor-currency-display (pull request #3434)

fix(SW-3616): Handle EuroBonus point type everywhere

* Add tests to formatPrice

* formatPrice

* More work replacing config with api points type

* More work replacing config with api points type

* More fixing with currency

* maybe actually fixed it

* Fix MyStay

* Clean up

* Fix comments

* Merge branch 'master' into fix/refactor-currency-display

* Fix calculateTotalPrice for EB points + SF points + cash


Approved-by: Joakim Jäderberg
This commit is contained in:
Anton Gunnarsson
2026-01-15 09:32:17 +00:00
parent c61ddaf94d
commit 16fbdb7ae0
59 changed files with 729 additions and 282 deletions

View File

@@ -15,7 +15,6 @@ import {
} from "./helpers"
import { getRoomPrice, getTotalPrice } from "./priceCalculations"
import type { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
import type { Lang } from "@scandic-hotels/common/constants/language"
import type { BreakfastPackages } from "@scandic-hotels/trpc/routers/hotels/output"
import type { User } from "@scandic-hotels/trpc/types/user"
@@ -41,8 +40,7 @@ export function createDetailsStore(
searchParams: string,
user: User | null,
breakfastPackages: BreakfastPackages,
lang: Lang,
pointsCurrency?: CurrencyEnum
lang: Lang
) {
const isMember = !!user
const nights = dt(initialState.booking.toDate).diff(
@@ -67,23 +65,14 @@ export function createDetailsStore(
...defaultGuestState,
phoneNumberCC: getDefaultCountryFromLang(lang),
},
roomPrice: getRoomPrice(
room.roomRate,
isMember && idx === 0,
pointsCurrency
),
roomPrice: getRoomPrice(room.roomRate, isMember && idx === 0),
specialRequest: {
comment: "",
},
}
})
const initialTotalPrice = getTotalPrice(
initialRooms,
isMember,
nights,
pointsCurrency
)
const initialTotalPrice = getTotalPrice(initialRooms, isMember, nights)
const availableBeds = initialState.rooms.reduce<
DetailsState["availableBeds"]
@@ -184,8 +173,7 @@ export function createDetailsStore(
state.totalPrice = getTotalPrice(
state.rooms.map((r) => r.room),
isMember,
nights,
pointsCurrency
nights
)
const isAllStepsCompleted = checkRoomProgress(
@@ -216,8 +204,7 @@ export function createDetailsStore(
}
currentRoom.roomPrice = getRoomPrice(
currentRoom.roomRate,
isValidMembershipNo || currentRoom.guest.join,
pointsCurrency
isValidMembershipNo || currentRoom.guest.join
)
const nights = dt(state.booking.toDate).diff(
@@ -228,8 +215,7 @@ export function createDetailsStore(
state.totalPrice = getTotalPrice(
state.rooms.map((r) => r.room),
isMember,
nights,
pointsCurrency
nights
)
writeToSessionStorage({
@@ -252,8 +238,7 @@ export function createDetailsStore(
currentRoom.roomPrice = getRoomPrice(
currentRoom.roomRate,
join || !!currentRoom.guest.membershipNo,
pointsCurrency
join || !!currentRoom.guest.membershipNo
)
const nights = dt(state.booking.toDate).diff(
@@ -264,8 +249,7 @@ export function createDetailsStore(
state.totalPrice = getTotalPrice(
state.rooms.map((r) => r.room),
isMember,
nights,
pointsCurrency
nights
)
writeToSessionStorage({
@@ -330,8 +314,7 @@ export function createDetailsStore(
currentRoom.roomPrice = getRoomPrice(
currentRoom.roomRate,
Boolean(data.join || data.membershipNo || isMemberAndRoomOne),
pointsCurrency
Boolean(data.join || data.membershipNo || isMemberAndRoomOne)
)
const nights = dt(state.booking.toDate).diff(
@@ -342,8 +325,7 @@ export function createDetailsStore(
state.totalPrice = getTotalPrice(
state.rooms.map((r) => r.room),
isMember,
nights,
pointsCurrency
nights
)
const isAllStepsCompleted = checkRoomProgress(

View File

@@ -1,6 +1,7 @@
import { describe, expect, it } from "vitest"
import { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
import { PointType } from "@scandic-hotels/common/constants/pointType"
import { RoomPackageCodeEnum } from "@scandic-hotels/trpc/enums/roomFilter"
import {
@@ -998,16 +999,24 @@ describe("getRedemptionPrice", () => {
const result = getRedemptionPrice([], 1)
expect(result).toEqual({
local: { price: 0, currency: CurrencyEnum.POINTS },
local: {
price: 0,
currency: CurrencyEnum.POINTS,
pointsType: PointType.SCANDIC,
},
requested: undefined,
})
})
it("returns price 0 and set currency when rooms are empty", () => {
const result = getRedemptionPrice([], 1, CurrencyEnum.EUROBONUS)
const result = getRedemptionPrice([], 1)
expect(result).toEqual({
local: { price: 0, currency: CurrencyEnum.EUROBONUS },
local: {
price: 0,
currency: CurrencyEnum.POINTS,
pointsType: PointType.SCANDIC,
},
requested: undefined,
})
})
@@ -1026,6 +1035,7 @@ describe("getRedemptionPrice", () => {
pointsPerStay: 100,
currency: CurrencyEnum.POINTS,
additionalPricePerStay: 0,
pointsType: PointType.SCANDIC,
},
},
},
@@ -1040,6 +1050,7 @@ describe("getRedemptionPrice", () => {
currency: CurrencyEnum.POINTS,
additionalPrice: 0,
additionalPriceCurrency: CurrencyEnum.POINTS,
pointsType: PointType.SCANDIC,
},
requested: undefined,
})
@@ -1059,6 +1070,7 @@ describe("getRedemptionPrice", () => {
pointsPerStay: 100,
currency: CurrencyEnum.POINTS,
additionalPricePerStay: 0,
pointsType: PointType.SCANDIC,
},
},
},
@@ -1073,6 +1085,7 @@ describe("getRedemptionPrice", () => {
currency: CurrencyEnum.POINTS,
additionalPrice: 0,
additionalPriceCurrency: CurrencyEnum.POINTS,
pointsType: PointType.SCANDIC,
},
requested: undefined,
})
@@ -1092,6 +1105,7 @@ describe("getRedemptionPrice", () => {
pointsPerStay: 100,
currency: CurrencyEnum.POINTS,
additionalPricePerStay: 0,
pointsType: PointType.SCANDIC,
},
},
},
@@ -1106,6 +1120,7 @@ describe("getRedemptionPrice", () => {
pointsPerStay: 150,
currency: CurrencyEnum.POINTS,
additionalPricePerStay: 0,
pointsType: PointType.SCANDIC,
},
},
},
@@ -1120,6 +1135,7 @@ describe("getRedemptionPrice", () => {
currency: CurrencyEnum.POINTS,
additionalPrice: 0,
additionalPriceCurrency: CurrencyEnum.POINTS,
pointsType: PointType.SCANDIC,
},
requested: undefined,
})
@@ -1144,6 +1160,7 @@ describe("getRedemptionPrice", () => {
pointsPerStay: 100,
currency: CurrencyEnum.POINTS,
additionalPricePerStay: 0,
pointsType: PointType.SCANDIC,
},
},
},
@@ -1158,6 +1175,7 @@ describe("getRedemptionPrice", () => {
currency: CurrencyEnum.POINTS,
additionalPrice: 33,
additionalPriceCurrency: CurrencyEnum.POINTS,
pointsType: PointType.SCANDIC,
},
requested: undefined,
})
@@ -1818,6 +1836,7 @@ describe("getTotalPrice", () => {
pointsPerStay: 100,
currency: CurrencyEnum.POINTS,
additionalPricePerStay: 0,
pointsType: PointType.SCANDIC,
},
},
},
@@ -1856,6 +1875,7 @@ describe("getTotalPrice", () => {
currency: CurrencyEnum.POINTS,
additionalPrice: 0,
additionalPriceCurrency: CurrencyEnum.POINTS,
pointsType: PointType.SCANDIC,
},
requested: undefined,
})

View File

@@ -1,4 +1,5 @@
import { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
import { PointType } from "@scandic-hotels/common/constants/pointType"
import { RateTypeEnum } from "@scandic-hotels/common/constants/rateType"
import { logger } from "@scandic-hotels/common/logger"
@@ -19,11 +20,7 @@ function add(...nums: (number | string | undefined)[]) {
}, 0)
}
export function getRoomPrice(
roomRate: Product,
isMember: boolean,
pointsCurrency?: CurrencyEnum
) {
export function getRoomPrice(roomRate: Product, isMember: boolean) {
if (isMember && "member" in roomRate && roomRate.member) {
let publicRate
if (
@@ -167,23 +164,25 @@ export function getRoomPrice(
perNight: {
requested: undefined,
local: {
currency: pointsCurrency ?? CurrencyEnum.POINTS,
currency: CurrencyEnum.POINTS,
price: roomRate.redemption.localPrice.pointsPerStay,
additionalPrice:
roomRate.redemption.localPrice.additionalPricePerStay,
additionalPriceCurrency:
roomRate.redemption.localPrice.currency ?? undefined,
pointsType: roomRate.redemption.localPrice.pointsType,
},
},
perStay: {
requested: undefined,
local: {
currency: pointsCurrency ?? CurrencyEnum.POINTS,
currency: CurrencyEnum.POINTS,
price: roomRate.redemption.localPrice.pointsPerStay,
additionalPrice:
roomRate.redemption.localPrice.additionalPricePerStay,
additionalPriceCurrency:
roomRate.redemption.localPrice.currency ?? undefined,
pointsType: roomRate.redemption.localPrice.pointsType,
},
},
}
@@ -410,17 +409,18 @@ type RedemptionRoom = BasePriceCalculationRoom & {
localPrice: {
pointsPerStay: number
additionalPricePerStay: number
pointsType: PointType
currency?: CurrencyEnum
}
}
}
}
export function getRedemptionPrice(
rooms: RedemptionRoom[],
nights: number,
pointsCurrency?: CurrencyEnum
) {
export function getRedemptionPrice(rooms: RedemptionRoom[], nights: number) {
// We can assume that all rooms have the same pointsType
const pointsType =
rooms[0]?.roomRate.redemption.localPrice.pointsType || PointType.SCANDIC
return rooms.reduce<Price>(
(total, room) => {
const redemption = room.roomRate.redemption
@@ -444,8 +444,9 @@ export function getRedemptionPrice(
},
{
local: {
currency: pointsCurrency ?? CurrencyEnum.POINTS,
currency: CurrencyEnum.POINTS,
price: 0,
pointsType,
},
requested: undefined,
}
@@ -580,8 +581,7 @@ export function getTotalPrice(
| VoucherRoom
)[],
isMember: boolean,
nights: number,
pointsCurrency?: CurrencyEnum
nights: number
) {
const corporateChequeRooms = rooms.filter(
(x): x is CorporateCheckRoom => "corporateCheque" in x.roomRate
@@ -594,7 +594,7 @@ export function getTotalPrice(
(x): x is RedemptionRoom => "redemption" in x.roomRate
)
if (redemptionRooms.length > 0) {
return getRedemptionPrice(redemptionRooms, nights, pointsCurrency)
return getRedemptionPrice(redemptionRooms, nights)
}
const voucherRooms = rooms.filter(