@ticketboothapp/booking 1.2.82 → 1.2.84

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ticketboothapp/booking",
3
- "version": "1.2.82",
3
+ "version": "1.2.84",
4
4
  "private": false,
5
5
  "sideEffects": [
6
6
  "**/*.css",
@@ -152,14 +152,39 @@ function omitZeroAmountPromoDiscountSummaryLines(lines: PriceSummaryLine[]): Pri
152
152
  });
153
153
  }
154
154
 
155
- function mapSummaryLinesToFeReceiptLineItems(lines: PriceSummaryLine[]): NonNullable<AdminFeAuthoritativeReceipt['lineItems']> {
155
+ function resolveTicketQtyFromQuantities(
156
+ category: string,
157
+ quantities: Record<string, number>,
158
+ ): number | undefined {
159
+ const c = category.trim();
160
+ if (Object.prototype.hasOwnProperty.call(quantities, c)) return quantities[c];
161
+ const up = c.toUpperCase();
162
+ for (const [key, val] of Object.entries(quantities)) {
163
+ if (key.toUpperCase() === up) return val;
164
+ }
165
+ return undefined;
166
+ }
167
+
168
+ /** Receipt TICKET rows sent on admin quote must follow picker {@link quantities}: BE apply uses these lines for headcount when feReceipt is authoritative — server `priceSummaryLines` can lag counts. */
169
+ function mapSummaryLinesToFeReceiptLineItems(
170
+ lines: PriceSummaryLine[],
171
+ quantities: Record<string, number>,
172
+ ): NonNullable<AdminFeAuthoritativeReceipt['lineItems']> {
156
173
  return lines.map((line) => {
157
174
  if (line.kind === 'ticket') {
175
+ const uiQty = resolveTicketQtyFromQuantities(line.category, quantities);
176
+ const lineQty = Math.max(0, line.qty);
177
+ const effectiveQty =
178
+ uiQty != null && uiQty >= 0 ? Math.round(uiQty) : lineQty;
179
+ let amount = roundMoney(line.itemTotal);
180
+ if (lineQty > 0 && effectiveQty !== lineQty) {
181
+ amount = roundMoney((line.itemTotal * effectiveQty) / lineQty);
182
+ }
158
183
  return {
159
184
  label: line.category,
160
- amount: roundMoney(line.itemTotal),
185
+ amount,
161
186
  type: 'TICKET',
162
- quantity: line.qty,
187
+ quantity: Math.max(0, effectiveQty),
163
188
  };
164
189
  }
165
190
  const normalizedType = String(line.type ?? '').trim().toUpperCase();
@@ -3828,7 +3853,7 @@ export function AdminChangeBookingFlow({
3828
3853
  const displayChangeFlowProposedTotalWithEditableLines = roundMoney(
3829
3854
  displayChangeFlowProposedTotal + editableSummaryPreSubtotalDelta
3830
3855
  );
3831
- /** Tax-included currencies: ticket row amounts match authoritative new-booking total (quote/display), not raw catalog/floor rollup. */
3856
+ /** Tax-included: scale ticket row $ on the PriceSummary so ADULT lines match the footer total (quote/display). Payment breakdown still uses {@link ticketLineItemsForChangeFlowDisplay} — it must reconcile to amount-due, not full new-booking total. */
3832
3857
  const taxIncludedReconciledCheckoutPriceSummaryLines = useMemo(() => {
3833
3858
  if (!isTaxIncludedInPrice || !originalReceipt || showProviderPricingInlineEditor) {
3834
3859
  return editableCheckoutPriceSummaryLines;
@@ -3851,7 +3876,10 @@ export function AdminChangeBookingFlow({
3851
3876
  const hasTaxLine = taxIncludedReconciledCheckoutPriceSummaryLines.some(
3852
3877
  (line) => line.kind === 'line' && String(line.type ?? '').toUpperCase() === 'TAX'
3853
3878
  );
3854
- const lineItems = mapSummaryLinesToFeReceiptLineItems(taxIncludedReconciledCheckoutPriceSummaryLines);
3879
+ const lineItems = mapSummaryLinesToFeReceiptLineItems(
3880
+ taxIncludedReconciledCheckoutPriceSummaryLines,
3881
+ quantities,
3882
+ );
3855
3883
  if (!hasTaxLine && Math.abs(displayChangeFlowTax) >= 0.0005) {
3856
3884
  lineItems.push({
3857
3885
  label: t('booking.tax') !== 'booking.tax' ? t('booking.tax') : 'Taxes and fees',
@@ -3875,6 +3903,7 @@ export function AdminChangeBookingFlow({
3875
3903
  };
3876
3904
  }, [
3877
3905
  taxIncludedReconciledCheckoutPriceSummaryLines,
3906
+ quantities,
3878
3907
  displayChangeFlowTax,
3879
3908
  displayChangeFlowSubtotal,
3880
3909
  editableSummaryPreSubtotalDelta,
@@ -5034,11 +5063,8 @@ export function AdminChangeBookingFlow({
5034
5063
  }),
5035
5064
  )
5036
5065
  : totalPrice;
5037
- const ticketRowsForCheckoutBreakdown = taxIncludedReconciledCheckoutPriceSummaryLines.filter(
5038
- (l): l is Extract<PriceSummaryLine, { kind: 'ticket' }> => l.kind === 'ticket',
5039
- );
5040
5066
  const lines = [
5041
- ...ticketRowsForCheckoutBreakdown.map((line) => ({
5067
+ ...ticketLineItemsForChangeFlowDisplay.map((line) => ({
5042
5068
  label: line.category,
5043
5069
  amount: line.itemTotal,
5044
5070
  type: 'TICKET' as const,
@@ -5181,7 +5207,7 @@ export function AdminChangeBookingFlow({
5181
5207
  availabilityProductOptionId,
5182
5208
  itineraryDisplay: itineraryDisplay ?? undefined,
5183
5209
  clientSecret: paymentIntent.clientSecret ?? '',
5184
- ticketLinesForModal: ticketRowsForCheckoutBreakdown.map((line) => {
5210
+ ticketLinesForModal: ticketLineItemsForChangeFlowDisplay.map((line) => {
5185
5211
  const rate = pricing.find((r) => r.category === line.category);
5186
5212
  const breakdown = getPriceBreakdown(
5187
5213
  line.category,
@@ -5208,7 +5234,7 @@ export function AdminChangeBookingFlow({
5208
5234
  return;
5209
5235
  }
5210
5236
 
5211
- const ticketLinesForModal: CheckoutModalLineItem[] = ticketRowsForCheckoutBreakdown.map((line) => {
5237
+ const ticketLinesForModal: CheckoutModalLineItem[] = ticketLineItemsForChangeFlowDisplay.map((line) => {
5212
5238
  const rate = pricing.find((r) => r.category === line.category);
5213
5239
  const breakdown = getPriceBreakdown(
5214
5240
  line.category,
@@ -4466,11 +4466,8 @@ export function ChangeBookingFlow({
4466
4466
  originalReceiptTotal: originalReceipt?.total ?? 0,
4467
4467
  audience: 'customer',
4468
4468
  });
4469
- const ticketRowsForCheckoutBreakdown = taxIncludedSelfServeReconciledPriceSummaryLines.filter(
4470
- (l): l is Extract<PriceSummaryLine, { kind: 'ticket' }> => l.kind === 'ticket',
4471
- );
4472
4469
  const lines = [
4473
- ...ticketRowsForCheckoutBreakdown.map((line) => ({
4470
+ ...ticketLineItemsForChangeFlowDisplay.map((line) => ({
4474
4471
  label: line.category,
4475
4472
  amount: line.itemTotal,
4476
4473
  type: 'TICKET' as const,
@@ -4555,7 +4552,7 @@ export function ChangeBookingFlow({
4555
4552
  })()
4556
4553
  );
4557
4554
 
4558
- const ticketLinesForModal: CheckoutModalLineItem[] = ticketRowsForCheckoutBreakdown.map((line) => {
4555
+ const ticketLinesForModal: CheckoutModalLineItem[] = ticketLineItemsForChangeFlowDisplay.map((line) => {
4559
4556
  const rate = pricing.find((r) => r.category === line.category);
4560
4557
  const breakdown = getPriceBreakdown(
4561
4558
  line.category,