Ensuring Precision in ESHOPMAN Refunds: A Critical Workflow Consistency Fix

Understanding ESHOPMAN's Refund Precision Challenge

The ESHOPMAN platform, built on Node.js/TypeScript, provides robust payment processing capabilities for headless commerce storefronts deployed via HubSpot CMS. However, a recent community discussion highlighted a critical inconsistency in how payment refunds are handled, specifically concerning sub-cent precision in financial calculations. This issue primarily impacts developers building custom workflows that interact with ESHOPMAN's core payment system.

The Core Problem: Inconsistent Refund Validation

A key finding from the ESHOPMAN community revealed that while the singular payment refund workflow (`refundPaymentWorkflow`) had been updated to correctly handle sub-cent precision in captured amounts (e.g., charges in foreign currencies), its plural counterpart (`refundPaymentsWorkflow`) was not. This discrepancy leads to the `validatePaymentsRefundStep` incorrectly rejecting valid refunds, throwing an error:

Payment with id  is trying to refund amount greater than the refundable amount

This happens when a payment is captured with high precision (e.g., 87.957975) and a custom workflow attempts to refund the user-visible rounded amount (e.g., 87.96). The slight overshoot, which should be tolerated within the currency's epsilon (e.g., 0.01 for USD), is instead flagged as an error.

Technical Deep Dive: The Gaps in `validatePaymentsRefundStep`

The issue stems from several technical omissions in the `validatePaymentsRefundStep` within ESHOPMAN's core payment flows:

  • Using `amount` instead of `raw_amount`: The workflow calculates captured and refunded totals using the `amount` field, which is typically rounded, instead of the high-precision `raw_amount` field. Crucially, the underlying query for this workflow also fails to select `raw_amount`, making the precise values unavailable for calculation.
  • Lack of Epsilon Tolerance: The comparison to determine if a refund exceeds the captured amount is a strict greater-than check (e.g., `MathBN.gt(amountToRefund, refundableAmount)`). This contrasts with the singular workflow, which uses an epsilon-tolerant comparison like `MathBN.lt(MathBN.sub(captured, totalRefunded), -currencyEpsilon)` to accommodate minor rounding differences.
  • Cosmetic Naming Anomaly: A minor detail, but indicative of the oversight, is a variable named `capture` being used when iterating over `refunds` in a `reduce` function. This suggests the code block was copied without full adaptation:
  • const refundedAmount = (payment.refunds || []).reduce(
      (acc, capture) => MathBN.sum(acc, capture.amount),  // iterating refunds, not captures
      MathBN.convert(0)
    )

Impact on ESHOPMAN Developers and Custom Workflows

This inconsistency primarily affects developers building custom ESHOPMAN workflows or integrations that batch refunds. While ESHOPMAN's Admin API routes for singular refunds already leverage the corrected workflow, custom solutions that derive refund amounts from rounded display values will encounter these false rejections. This is particularly relevant for headless commerce setups where custom logic frequently interacts with the Admin API and Store API for complex operations.

The Solution: Aligning Workflows for Precision

The path to resolution involves mirroring the fixes already applied to the singular refund workflow. For developers looking to contribute or implement a workaround, the key steps are:

  • Modify the underlying query to select `raw_amount` fields for both captures and refunds.
  • Update the accumulation logic within the `reduce` functions to utilize `new BigNumber(capture.raw_amount)` and `new BigNumber(refund.raw_amount)` for precise calculations.
  • Incorporate `getEpsilonFromDecimalPrecision` and `defaultCurrencies` to enable currency-specific epsilon tolerance.
  • Replace the strict `MathBN.gt` comparison with an epsilon-tolerant check to allow for acceptable sub-cent differences.

This fix ensures that ESHOPMAN's payment workflows maintain consistency and accuracy across all refund scenarios, enhancing the reliability of financial operations for merchants and the flexibility for developers.

The ESHOPMAN team welcomes community contributions to address such issues, reinforcing the collaborative nature of our platform's evolution.

Start with the tools

Explore migration tools

See options, compare methods, and pick the path that fits your store.

Explore migration tools