Merged in chore/price-calculation-tests (pull request #3072)

chore: Add more price calculation tests

* Add tests and refactor types for getVoucherPrice

* Add tests for sumPackagesRequestedPrice

* Add tests for calculateVat


Approved-by: Joakim Jäderberg
This commit is contained in:
Anton Gunnarsson
2025-11-04 12:50:51 +00:00
parent dc42a22513
commit 7fc49428c7
4 changed files with 214 additions and 12 deletions

View File

@@ -2,7 +2,11 @@ import { describe, expect, it } from "vitest"
import { CurrencyEnum } from "@scandic-hotels/common/constants/currency" import { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
import { getAdditionalPrice, getRedemptionPrice } from "./helpers" import {
getAdditionalPrice,
getRedemptionPrice,
getVoucherPrice,
} from "./helpers"
type GetAdditionalPriceParams = Parameters<typeof getAdditionalPrice> type GetAdditionalPriceParams = Parameters<typeof getAdditionalPrice>
describe("getAdditionalPrice", () => { describe("getAdditionalPrice", () => {
@@ -307,3 +311,150 @@ describe("getRedemptionPrice", () => {
}) })
}) })
}) })
describe("getVoucherPrice", () => {
it("returns price 0 and default currency when rooms are empty", () => {
const result = getVoucherPrice([], 1)
expect(result).toEqual({
local: { price: 0, currency: CurrencyEnum.Voucher },
requested: undefined,
})
})
it("returns price for single room with voucher price", () => {
const nights = 1
const result = getVoucherPrice(
[
{
adults: 1,
breakfast: false,
roomFeatures: [],
roomRate: {
voucher: {
numberOfVouchers: 1,
},
},
},
],
nights
)
expect(result).toEqual({
local: {
price: 1,
currency: CurrencyEnum.Voucher,
additionalPrice: 0,
},
requested: undefined,
})
})
it("returns price for single room with multiple nights", () => {
const nights = 3
const result = getVoucherPrice(
[
{
adults: 1,
breakfast: false,
roomFeatures: [],
roomRate: {
voucher: {
numberOfVouchers: 3,
},
},
},
],
nights
)
expect(result).toEqual({
local: {
price: 3,
currency: CurrencyEnum.Voucher,
additionalPrice: 0,
},
requested: undefined,
})
})
it("returns price for multiple rooms with multiple nights", () => {
const nights = 3
const result = getVoucherPrice(
[
{
adults: 1,
breakfast: false,
roomFeatures: [],
roomRate: {
voucher: {
numberOfVouchers: 3,
},
},
},
{
adults: 1,
breakfast: false,
roomFeatures: [],
roomRate: {
voucher: {
numberOfVouchers: 2,
},
},
},
],
nights
)
expect(result).toEqual({
local: {
price: 5,
currency: CurrencyEnum.Voucher,
additionalPrice: 0,
},
requested: undefined,
})
})
it("does not return price for room without voucher", () => {
const nights = 3
const result = getVoucherPrice(
[
{
adults: 1,
breakfast: false,
roomFeatures: [],
roomRate: {
redemption: {
localPrice: {
pointsPerStay: 150,
currency: CurrencyEnum.POINTS,
additionalPricePerStay: 0,
},
},
},
},
{
adults: 1,
breakfast: false,
roomFeatures: [],
roomRate: {
voucher: {
numberOfVouchers: 2,
},
},
},
],
nights
)
expect(result).toEqual({
local: {
price: 2,
currency: CurrencyEnum.Voucher,
additionalPrice: 0,
},
requested: undefined,
})
})
})

View File

@@ -14,7 +14,6 @@ import type {
CorporateChequeProduct, CorporateChequeProduct,
PriceProduct, PriceProduct,
Product, Product,
VoucherProduct,
} from "@scandic-hotels/trpc/types/roomAvailability" } from "@scandic-hotels/trpc/types/roomAvailability"
import type { User } from "@scandic-hotels/trpc/types/user" import type { User } from "@scandic-hotels/trpc/types/user"
@@ -417,13 +416,17 @@ function getCorporateChequePrice(rooms: TRoom[], nights: number) {
) )
} }
interface TRoomVoucher extends TRoom { type VoucherRoom = PriceCalculationRoom & {
roomRate: VoucherProduct roomRate: {
voucher: {
numberOfVouchers: number
}
}
} }
function getVoucherPrice(rooms: TRoom[], nights: number) { export function getVoucherPrice(rooms: PriceCalculationRoom[], nights: number) {
return rooms return rooms
.filter((room): room is TRoomVoucher => "voucher" in room.roomRate) .filter((room): room is VoucherRoom => "voucher" in room.roomRate)
.reduce<Price>( .reduce<Price>(
(total, room) => { (total, room) => {
const voucher = room.roomRate.voucher const voucher = room.roomRate.voucher
@@ -450,7 +453,7 @@ function getVoucherPrice(rooms: TRoom[], nights: number) {
) )
} }
type GetRedemptionPriceRoom = { type PriceCalculationRoom = {
adults: number adults: number
breakfast: breakfast:
| { localPrice: { price: number; currency?: CurrencyEnum } } | { localPrice: { price: number; currency?: CurrencyEnum } }
@@ -465,7 +468,7 @@ type GetRedemptionPriceRoom = {
// We don't care about roomRate unless it's RedemptionProduct // We don't care about roomRate unless it's RedemptionProduct
roomRate: object roomRate: object
} }
type RedemptionRoom = GetRedemptionPriceRoom & { type RedemptionRoom = PriceCalculationRoom & {
roomRate: { roomRate: {
redemption: { redemption: {
localPrice: { localPrice: {
@@ -478,7 +481,7 @@ type RedemptionRoom = GetRedemptionPriceRoom & {
} }
export function getRedemptionPrice( export function getRedemptionPrice(
rooms: GetRedemptionPriceRoom[], rooms: PriceCalculationRoom[],
nights: number, nights: number,
pointsCurrency?: CurrencyEnum pointsCurrency?: CurrencyEnum
) { ) {

View File

@@ -4,7 +4,12 @@ import { AlertTypeEnum } from "@scandic-hotels/common/constants/alert"
import { CurrencyEnum } from "@scandic-hotels/common/constants/currency" import { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
import { dt } from "@scandic-hotels/common/dt" import { dt } from "@scandic-hotels/common/dt"
import { filterOverlappingDates, sumPackages } from "./index" import {
calculateVat,
filterOverlappingDates,
sumPackages,
sumPackagesRequestedPrice,
} from "./index"
import type { specialAlertsSchema } from "@scandic-hotels/trpc/routers/hotels/schemas/hotel/specialAlerts" import type { specialAlertsSchema } from "@scandic-hotels/trpc/routers/hotels/schemas/hotel/specialAlerts"
import type { z } from "zod" import type { z } from "zod"
@@ -98,3 +103,42 @@ describe("sumPackages", () => {
expect(result).toEqual({ currency: CurrencyEnum.SEK, price: 350 }) expect(result).toEqual({ currency: CurrencyEnum.SEK, price: 350 })
}) })
}) })
describe("sumPackagesRequestedPrice", () => {
it("returns 0 price for null packages", () => {
const result = sumPackagesRequestedPrice(null)
expect(result).toEqual({ currency: undefined, price: 0 })
})
it("returns 0 price for undefined packages", () => {
const result = sumPackagesRequestedPrice(undefined)
expect(result).toEqual({ currency: undefined, price: 0 })
})
it("returns 0 price for empty packages", () => {
const result = sumPackagesRequestedPrice([])
expect(result).toEqual({ currency: undefined, price: 0 })
})
it("sums prices of packages", () => {
const result = sumPackagesRequestedPrice([
{ requestedPrice: { totalPrice: 100, currency: CurrencyEnum.SEK } },
{ requestedPrice: { totalPrice: 200, currency: CurrencyEnum.SEK } },
{ requestedPrice: { totalPrice: 50, currency: CurrencyEnum.SEK } },
])
expect(result).toEqual({ currency: CurrencyEnum.SEK, price: 350 })
})
})
describe("calculateVat", () => {
it("calculates VAT correctly", () => {
expect(calculateVat(100, 25)).toEqual({
priceExclVat: 80,
vatAmount: 20,
})
expect(calculateVat(5, 100)).toEqual({
priceExclVat: 2.5,
vatAmount: 2.5,
})
})
})

View File

@@ -9,7 +9,6 @@ import { ChildBedTypeEnum } from "@scandic-hotels/trpc/enums/childBedTypeEnum"
import { RoomPackageCodeEnum } from "@scandic-hotels/trpc/enums/roomFilter" import { RoomPackageCodeEnum } from "@scandic-hotels/trpc/enums/roomFilter"
import type { CurrencyEnum } from "@scandic-hotels/common/constants/currency" import type { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
import type { Packages } from "@scandic-hotels/trpc/types/packages"
import type { JSX } from "react" import type { JSX } from "react"
import type { RoomPackageCodes } from "../../types/components/selectRate/roomFilter" import type { RoomPackageCodes } from "../../types/components/selectRate/roomFilter"
@@ -63,7 +62,12 @@ export function sumPackages(
) )
} }
export function sumPackagesRequestedPrice(packages: Packages | null) { export function sumPackagesRequestedPrice(
packages:
| { requestedPrice: { totalPrice: number; currency?: CurrencyEnum } }[]
| null
| undefined
) {
if (!packages || !packages.length) { if (!packages || !packages.length) {
return { return {
currency: undefined, currency: undefined,