buildCumulativeResult method

PaymentResult buildCumulativeResult({
  1. required String businessId,
  2. required String userId,
  3. required String merchantId,
  4. String isoCurrencyCode = '',
  5. String shortCurrencyCode = '',
})

Builds a cumulative PaymentResult summarising the entire split session.

The result includes the total amount paid across all successful legs, the split tip amount, and the payment leg count.

Implementation

PaymentResult buildCumulativeResult({
  required String businessId,
  required String userId,
  required String merchantId,
  String isoCurrencyCode = '',
  String shortCurrencyCode = '',
}) {
  if (_currentSession == null) {
    _logger?.error(this, 'buildCumulativeResult: no active session');
    throw StateError(
      'Cannot build cumulative result: no active split session.',
    );
  }

  final session = _currentSession!;

  final totalPaid = session.amountPaid;

  // Calculate change and tendered amounts for split flows.
  //
  // Change = sum of per-cash-leg surplus (cashTendered − legAmount) across
  //   all successful cash legs where cashTendered > legAmount.
  //   This is the surplus (excluding the implicit tip baked into the
  //   KeypadPage amount) that was accumulated from cash overpayment.
  //
  // amountTendered = totalPaid + totalCashSurplus — represents what was
  //   actually tendered, including the tip amount plus the cash surplus.
  final successfulLegs = session.paymentLegs.where((l) => l.isSuccess);
  Decimal totalCashSurplus = Decimal.zero;
  for (final leg in successfulLegs) {
    if (leg.cashTendered != null && leg.cashTendered! > leg.amount) {
      totalCashSurplus += leg.cashTendered! - leg.amount;
    }
  }
  final change = totalCashSurplus;
  final amountTendered = totalPaid + totalCashSurplus;

  _logger?.info(
    this,
    'buildCumulativeResult: building — '
    'state=${session.state.name}, '
    'amountPaid=$totalPaid, '
    'tipAmount=${session.tipAmount}, '
    'changeAmount=$change, '
    'amountTendered=$amountTendered, '
    'totalCashSurplus=$totalCashSurplus, '
    'successfulLegs=${session.successfulLegCount}/'
    '${session.paymentLegs.length}',
  );

  return PaymentResult(
    businessId: businessId,
    userId: userId,
    transactionId: session.splitId,
    transactionReference: 'SPLIT-${session.splitId}',
    traceId: session.splitId,
    transactionType: TransactionType.purchase,
    amount: session.amountPaid,
    isoCurrencyCode: isoCurrencyCode,
    shortCurrencyCode: shortCurrencyCode,
    transactionStatus: PaymentStatus.processed,
    status: session.state == SplitSessionState.fullyPaid
        ? 'success'
        : 'partial_success',
    statusCode: session.state == SplitSessionState.fullyPaid
        ? 'FULLY_PAID'
        : 'PARTIALLY_PAID',
    statusMessage: session.state == SplitSessionState.fullyPaid
        ? 'Split payment completed'
        : 'Split payment partially completed',
    statusDescription: session.state == SplitSessionState.fullyPaid
        ? 'All payment legs processed successfully'
        : '${session.successfulLegCount} of ${session.paymentLegs.length} legs processed',
    batchReference: '',
    batchNumber: 0,
    paymentType: 'split',
    paymentProviderId: '',
    paymentProviderType: PaymentProviderType.unknown,
    paymentProviderName: 'Split Payment',
    merchantId: merchantId,
    authCode: '',
    authResponseCode: '',
    authResponse: '',
    entry: '',
    entryMode: '',
    paymentMethod: 'split',
    maskedPan: '',
    uti: '',
    terminalId: '',
    otherAmount: Decimal.zero,
    splitTipAmount: session.totalTipAmount,
    splitExplicitTipAmount: session.explicitTipAmount,
    paymentLegCount: session.successfulLegCount,
    changeAmount: change,
    amountTendered: amountTendered,
  );
}