Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ export default function GuestDetailsModal({
roomTypeId={reservation.roomTypeId}
ratePlanId={reservation.ratePlanId}
totalAmount={reservation.totalAmount}
currencyCode={currencyCode}
/>
</div>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { UserPlus, Split, ArrowRightLeft, Trash2 } from 'lucide-react';
import { api } from '../../lib/api';
import { moneyString, requirePropertyId } from '../../lib/api-helpers';
import { moneyString, requirePropertyId, requireCurrency } from '../../lib/api-helpers';
import { useToast } from '../ui/Toast';
import FindGuest from '../guests/FindGuest';
import type { Guest } from '../../types/guest';
Expand Down Expand Up @@ -54,14 +54,14 @@ export default function ReservationPartyPanel({
roomTypeId,
ratePlanId,
totalAmount,
currencyCode = 'USD',
currencyCode,
}: {
reservationId: string;
propertyId: string;
roomTypeId?: string;
ratePlanId?: string;
totalAmount?: string;
currencyCode?: string;
currencyCode?: string | null;
}) {
const { t } = useTranslation();
const { toast } = useToast();
Expand Down Expand Up @@ -166,6 +166,7 @@ export default function ReservationPartyPanel({
const splitMutation = useMutation({
mutationFn: () => {
requirePropertyId(propertyId);
requireCurrency(currencyCode ?? null);
return api.post(
`/v1/reservations/${reservationId}/split`,
{
Expand Down
3 changes: 2 additions & 1 deletion apps/dashboard/src/pages/Accounting.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -279,10 +279,11 @@ function AccountingHome() {
const recordArPayment = useMutation({
mutationFn: () => {
requirePropertyId(propertyId);
requireCurrency(selectedLedger?.currencyCode ?? null);
return api.post(`/v1/ar/ledgers/${selectedLedger!.id}/payments`, {
propertyId,
amount: moneyString(arPaymentAmount),
currencyCode: selectedLedger?.currencyCode ?? 'USD',
currencyCode: selectedLedger?.currencyCode,
});
},
onSuccess: () => {
Expand Down
13 changes: 8 additions & 5 deletions apps/dashboard/src/pages/Folios.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -243,14 +243,17 @@ function SplitFolioPanel({
});

const createSplitFolio = useMutation({
mutationFn: () =>
api.post('/v1/folios', {
mutationFn: () => {
requirePropertyId(propertyId);
requireCurrency(folio.currencyCode ?? null);
return api.post('/v1/folios', {
propertyId,
reservationId,
guestId: folio.guestId,
type: 'guest',
currencyCode: folio.currencyCode ?? 'USD',
}),
currencyCode: folio.currencyCode,
});
},
onSuccess: () => {
refetchSiblings();
setSplitOpen(false);
Expand Down Expand Up @@ -497,7 +500,7 @@ function FolioDetail() {
const folio: Folio | null = folioData?.data ?? folioData ?? null;
const charges: Charge[] = chargesData?.data ?? chargesData ?? [];
const payments: Payment[] = paymentsData?.data ?? paymentsData ?? [];
const currencyCode = folio?.currencyCode ?? 'USD';
const currencyCode = folio?.currencyCode ?? null;

const reversedIds = new Set(
charges.filter((c) => c.isReversal && c.originalChargeId).map((c) => c.originalChargeId!),
Expand Down
8 changes: 5 additions & 3 deletions apps/dashboard/src/pages/FrontDesk.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { ConciergeBell, LogIn, Users, LogOut, UserPlus, UsersRound, ArrowRightLeft, StickyNote, UserRound, Plus, X } from 'lucide-react';
import { addDays, differenceInCalendarDays, format, parseISO } from 'date-fns';
import { api } from '../lib/api';
import { moneyString, requirePropertyId } from '../lib/api-helpers';
import { moneyString, requirePropertyId, requireCurrency } from '../lib/api-helpers';
import { useProperty } from '../context/PropertyContext';
import StatusBadge from '../components/ui/StatusBadge';
import Modal from '../components/ui/Modal';
Expand Down Expand Up @@ -472,6 +472,7 @@ export default function FrontDesk() {

const plans: any[] = Array.isArray(ratePlans) ? ratePlans : ratePlans?.data ?? [];
const plan = plans.find((p) => p.id === wiRatePlanId);
requireCurrency(plan?.currencyCode ?? null);
const nightly = Number(plan?.baseAmount ?? 0);
const guestId = wiGuest.id;
const resCreate = await api.post(
Expand All @@ -486,7 +487,7 @@ export default function FrontDesk() {
adults: 1 + primaryAdditionalIds.length,
source: 'walk_in',
totalAmount: moneyString(nightly * wiNights),
currencyCode: plan?.currencyCode ?? 'USD',
currencyCode: plan?.currencyCode,
},
{ skipErrorToast: true },
);
Expand Down Expand Up @@ -518,6 +519,7 @@ export default function FrontDesk() {
for (let i = 0; i < wiExtraRooms.length; i++) {
const extra = wiExtraRooms[i];
const planExtra = plans.find((p) => p.id === extra.ratePlanId);
requireCurrency(planExtra?.currencyCode ?? null);
const nightlyExtra = Number(planExtra?.baseAmount ?? 0);
const extraGuestIds = [extra.guest!.id, ...extraAdditionalIds[i]];
// Occupants must be attached to the source (primary) reservation before they
Expand All @@ -539,7 +541,7 @@ export default function FrontDesk() {
roomTypeId: extra.roomTypeId,
ratePlanId: extra.ratePlanId,
totalAmount: moneyString(nightlyExtra * wiNights),
currencyCode: planExtra?.currencyCode ?? 'USD',
currencyCode: planExtra?.currencyCode,
roomId: extra.roomId,
adults: extraGuestIds.length,
overrideMaxOccupancy: extra.overrideOccupancy,
Expand Down
3 changes: 2 additions & 1 deletion apps/dashboard/src/pages/HouseAccounts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ function HouseAccountList() {
const createMutation = useMutation({
mutationFn: () => {
requirePropertyId(propertyId);
requireCurrency(currencyCode);
return api.post('/v1/house-accounts', { propertyId, name, kind, currencyCode });
},
onSuccess: () => {
Expand Down Expand Up @@ -321,7 +322,7 @@ function HouseAccountDetail() {

const account: HouseAccount | null = data?.data ?? data ?? null;
const products: Product[] = productsData?.data ?? productsData ?? [];
const currencyCode = account?.currencyCode ?? 'USD';
const currencyCode = account?.currencyCode ?? null;

const postCharge = useMutation({
mutationFn: () => {
Expand Down
2 changes: 1 addition & 1 deletion apps/dashboard/src/pages/RatePlans.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ function RatePlanDetail() {
<div><p className="text-xs text-telivity-mid-grey">{t('ratePlans.code')}</p><p className="text-sm font-medium">{plan.code}</p></div>
<div><p className="text-xs text-telivity-mid-grey">{t('ratePlans.baseAmount')}</p><p className="text-sm font-medium">{plan.baseAmount != null ? formatMoney(plan.baseAmount, currencyCode) : '—'}</p></div>
<div><p className="text-xs text-telivity-mid-grey">{t('ratePlans.roomType')}</p><p className="text-sm font-medium">{plan.roomTypeName ?? '—'}</p></div>
<div><p className="text-xs text-telivity-mid-grey">{t('ratePlans.currency')}</p><p className="text-sm font-medium">{plan.currency ?? plan.currencyCode ?? 'USD'}</p></div>
<div><p className="text-xs text-telivity-mid-grey">{t('ratePlans.currency')}</p><p className="text-sm font-medium">{plan.currency ?? plan.currencyCode ?? ''}</p></div>
{plan.type === 'derived' && (
<>
<div><p className="text-xs text-telivity-mid-grey">{t('ratePlans.parentRatePlan')}</p><p className="text-sm font-medium font-mono">{plan.parentRatePlanId ?? '—'}</p></div>
Expand Down
12 changes: 9 additions & 3 deletions apps/dashboard/src/pages/Reservations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ function parseImportRows(text: string): Record<string, unknown>[] {
.split('\n')
.map((line) => line.trim())
.filter(Boolean)
.map((line) => {
.map((line, index) => {
const [
guestId,
arrivalDate,
Expand All @@ -86,14 +86,20 @@ function parseImportRows(text: string): Record<string, unknown>[] {
adults,
children,
] = line.split(',').map((s) => s.trim());
if (!currencyCode) {
// Was `currencyCode || 'USD'`. A missing column is not a USD booking —
// it is a row we cannot price, and importing it as dollars against a
// property trading in anything else writes a wrong number to a ledger.
throw new Error(`Row ${index + 1}: currencyCode is required`);
}
const row: Record<string, unknown> = {
guestId,
arrivalDate,
departureDate,
roomTypeId,
ratePlanId,
totalAmount: totalAmount ? moneyString(totalAmount) : undefined,
currencyCode: currencyCode || 'USD',
currencyCode,
source: source || 'direct',
};
if (adults) row.adults = Number(adults);
Expand Down Expand Up @@ -646,7 +652,7 @@ function ReservationList() {
totalAmount={
detailRes.totalAmount != null ? String(detailRes.totalAmount) : undefined
}
currencyCode={detailRes.currencyCode ?? 'USD'}
currencyCode={detailRes.currencyCode ?? null}
/>
<ReservationOpsNotes reservationId={detailRes.id} propertyId={propertyId!} />
<ReservationMessageCompose reservationId={detailRes.id} propertyId={propertyId!} />
Expand Down
Loading