Mastering ESHOPMAN Pricing: A Critical Look at calculatePrices() Behavior and a Smart Workaround

Accurate pricing is the bedrock of any successful e-commerce operation, especially when managing your storefronts through ESHOPMAN and deploying them via HubSpot CMS. The ESHOPMAN platform, built on Node.js/TypeScript, provides robust tools via its Admin API and Store API for handling complex pricing scenarios, including product variants and dynamic price lists. However, a recent community insight has highlighted a specific behavior within the core pricing module's calculatePrices() function that ESHOPMAN developers and merchants should be aware of.

The Unexpected Price Selection Challenge

When interacting with ESHOPMAN's pricing module, developers often use the calculatePrices() function to determine the final price of a product based on various rules and contexts. A peculiar situation arises when this function is invoked with what appears to be an "empty" context – specifically, when only the mandatory currency_code is provided, and no other specific rules (like region or customer group) are present. In such cases, the system might unexpectedly select a price from a price list that does have explicit rules, even though those rules are not met by the provided context.

Consider an ESHOPMAN price set with multiple price records, some default and some tied to price lists. Imagine a scenario with:

  • A default price (e.g., 5 EUR).
  • A price from a "New Price List" (no rules on the pricelist itself) offering 3 EUR.
  • A price from a "Price List for special customers" (with a customer_group_id rule) offering 1 EUR.

When calculatePrices() is called with an empty context (e.g., { context: { currency_code: "eur" } }), one would expect the system to select the most general price available, typically the one with no rules from the price list that also has no rules (e.g., 3 EUR). However, the observed behavior is that it might incorrectly select the price from the "Price List for special customers" (e.g., 1 EUR), despite the customer group rule not being present in the context.

Understanding the Technical Root Cause

This behavior stems from a specific optimization within the ESHOPMAN pricing module's underlying logic (found in the pricing.ts repository for the Node.js/TypeScript implementation). When the system determines that the provided context lacks "complex" rules to evaluate, it takes a shortcut in its database query. The simplified logic for selecting prices without complex context looks something like this (conceptually, in SQL-like terms):

WHERE 
(price.rules_count = 0)
OR
(price.price_list_id IS NOT NULL AND pl.rules_count = 0)

The issue here is the second part of the OR condition. It allows a price to be selected if it comes from a price list (price.price_list_id IS NOT NULL) AND the price list itself has no rules (pl.rules_count = 0). The critical flaw is that it doesn't correctly account for price lists that do have rules, but which contain price records that themselves have no rules. This means a price from a rule-bound price list could still be selected if the price record within it has no rules, leading to an incorrect price display on your HubSpot-deployed storefront.

The more accurate logic, similar to what is followed when a "complex" context is present, would be:

WHERE 
(price.price_list_id IS NULL AND price.rules_count = 0)
OR
(price.price_list_id IS NOT NULL AND (price.rules_count = 0 AND pl.rules_count = 0))

This corrected logic ensures that if a price is sourced from a price list, both the individual price record and the price list itself must have no rules for it to be considered in an empty context.

The Immediate Workaround for ESHOPMAN Developers

While a permanent fix for this behavior is being addressed, ESHOPMAN developers can implement an immediate workaround to ensure accurate price calculations for their HubSpot storefronts. By introducing a "dummy" rule into your context object, you can force the calculatePrices() function to bypass the problematic shortcut and utilize the more comprehensive, correct logic path.

Here’s how you can apply this workaround:

const price = await pricingModuleService.calculatePrices(
    { id: [priceSetId] },
    {
        context: {
            currency_code: "eur",
            // Add a dummy rule to force complex context evaluation
            dummy: "xxx" 
        }
    }
);

By adding dummy: "xxx" (or any other non-existent rule), you effectively make the context "complex" enough for the system to use the correct evaluation path, leading to the expected price selection. This ensures that your headless commerce pricing logic remains accurate and consistent across your ESHOPMAN applications and HubSpot CMS deployments.

Key Takeaways for ESHOPMAN Users

This community insight underscores the importance of understanding the nuances of core ESHOPMAN functionalities, especially for those leveraging its powerful Admin API and Store API for custom development and integrations. Being aware of such behaviors and knowing how to implement workarounds is crucial for maintaining data integrity and providing a seamless experience on your HubSpot-managed storefronts. Always validate your pricing logic, especially when dealing with dynamic price lists and varied customer segments.

Start with the tools

Explore migration tools

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

Explore migration tools