@ticketboothapp/booking 1.2.83 → 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.83",
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,
@@ -5189,16 +5215,7 @@ export function AdminChangeBookingFlow({
5189
5215
  rate?.baseInDisplayCurrency,
5190
5216
  rate?.appliedAdjustments ?? []
5191
5217
  );
5192
- const qty = Math.max(0, line.qty);
5193
- return {
5194
- line: {
5195
- category: line.category,
5196
- qty,
5197
- itemTotal: line.itemTotal,
5198
- pricePerUnit: qty > 0 ? roundMoney(line.itemTotal / qty) : 0,
5199
- },
5200
- breakdown,
5201
- };
5218
+ return { line, breakdown };
5202
5219
  }),
5203
5220
  feeLineItems: feeLineItemsWithAddOns,
5204
5221
  returnPriceAdjustment: checkoutReturnLineAmount,
@@ -5217,7 +5234,7 @@ export function AdminChangeBookingFlow({
5217
5234
  return;
5218
5235
  }
5219
5236
 
5220
- const ticketLinesForModal: CheckoutModalLineItem[] = ticketRowsForCheckoutBreakdown.map((line) => {
5237
+ const ticketLinesForModal: CheckoutModalLineItem[] = ticketLineItemsForChangeFlowDisplay.map((line) => {
5221
5238
  const rate = pricing.find((r) => r.category === line.category);
5222
5239
  const breakdown = getPriceBreakdown(
5223
5240
  line.category,
@@ -5225,16 +5242,7 @@ export function AdminChangeBookingFlow({
5225
5242
  rate?.baseInDisplayCurrency,
5226
5243
  rate?.appliedAdjustments ?? []
5227
5244
  );
5228
- const qty = Math.max(0, line.qty);
5229
- return {
5230
- line: {
5231
- category: line.category,
5232
- qty,
5233
- itemTotal: line.itemTotal,
5234
- pricePerUnit: qty > 0 ? roundMoney(line.itemTotal / qty) : 0,
5235
- },
5236
- breakdown,
5237
- };
5245
+ return { line, breakdown };
5238
5246
  });
5239
5247
 
5240
5248
  setCheckoutClientSecret(paymentIntent.clientSecret ?? '');
@@ -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,
@@ -4563,16 +4560,7 @@ export function ChangeBookingFlow({
4563
4560
  rate?.baseInDisplayCurrency,
4564
4561
  rate?.appliedAdjustments ?? []
4565
4562
  );
4566
- const qty = Math.max(0, line.qty);
4567
- return {
4568
- line: {
4569
- category: line.category,
4570
- qty,
4571
- itemTotal: line.itemTotal,
4572
- pricePerUnit: qty > 0 ? roundMoney(line.itemTotal / qty) : 0,
4573
- },
4574
- breakdown,
4575
- };
4563
+ return { line, breakdown };
4576
4564
  });
4577
4565
 
4578
4566
  setCheckoutClientSecret(paymentIntent.clientSecret ?? '');