canProcessTransaction checks if a transaction can be processed given the source balance. It returns an error if the balance is insufficient and overdraft is not allowed. This function includes inflight balances and optionally queued balances in the available balance calculation to prevent creating t
(transaction *Transaction, sourceBalance *Balance)
| 130 | // This function includes inflight balances and optionally queued balances in the available balance calculation |
| 131 | // to prevent creating transactions that would exceed the actual available funds. |
| 132 | func canProcessTransaction(transaction *Transaction, sourceBalance *Balance) error { |
| 133 | if transaction.AllowOverdraft && transaction.OverdraftLimit == 0 { |
| 134 | // If unconditional overdraft is allowed, skip all balance checks |
| 135 | return nil |
| 136 | } |
| 137 | |
| 138 | // Initialize balance fields to ensure inflight balances are not nil |
| 139 | sourceBalance.InitializeBalanceFields() |
| 140 | |
| 141 | // Convert transaction.PreciseAmount to *big.Int for comparison. |
| 142 | transactionAmount := transaction.PreciseAmount |
| 143 | |
| 144 | // Calculate available balance by subtracting inflight balances from committed balance |
| 145 | // This ensures inflight balances are considered when checking if new transactions can be processed |
| 146 | availableBalance := new(big.Int).Sub(sourceBalance.Balance, sourceBalance.InflightDebitBalance) |
| 147 | |
| 148 | // If queued balances are available (when enable_queued_checks is on), also subtract queued debit balance |
| 149 | // This provides an even more comprehensive check by considering pending queued transactions |
| 150 | if sourceBalance.QueuedDebitBalance != nil { |
| 151 | availableBalance = new(big.Int).Sub(availableBalance, sourceBalance.QueuedDebitBalance) |
| 152 | } |
| 153 | |
| 154 | if availableBalance.Cmp(transactionAmount) >= 0 { |
| 155 | // Sufficient funds considering inflight and queued debits |
| 156 | return nil |
| 157 | } |
| 158 | |
| 159 | // Insufficient funds, check if within overdraft limit |
| 160 | if transaction.OverdraftLimit > 0 { |
| 161 | // Calculate the resulting balance after transaction, considering inflight and queued debits |
| 162 | resultingBalance := new(big.Int).Sub(availableBalance, transactionAmount) |
| 163 | |
| 164 | // Convert overdraft limit to big.Int with precision applied |
| 165 | overdraftLimitPrecise := int64(transaction.OverdraftLimit * transaction.Precision) |
| 166 | overdraftLimitBigInt := new(big.Int).SetInt64(overdraftLimitPrecise) |
| 167 | |
| 168 | // Negative of overdraft limit (as balance will be negative) |
| 169 | negativeOverdraftLimit := new(big.Int).Neg(overdraftLimitBigInt) |
| 170 | |
| 171 | // Check if resulting balance is within overdraft limit |
| 172 | if resultingBalance.Cmp(negativeOverdraftLimit) >= 0 { |
| 173 | return nil |
| 174 | } |
| 175 | return fmt.Errorf("transaction exceeds overdraft limit") |
| 176 | } |
| 177 | |
| 178 | // Insufficient funds and no overdraft allowed |
| 179 | return fmt.Errorf("insufficient funds in source balance") |
| 180 | } |
| 181 | |
| 182 | // CommitInflightDebit commits a debit from the inflight balance and adds it to the debit balance. |
| 183 | // This is part of the finalization process for inflight transactions. |