Backend Development 12 min read

Design and Implementation of Vivo Mall Promotion Pricing Engine

The article details Vivo Mall’s new promotion pricing engine, which replaces duplicated site‑level logic with a layered model (product, shop, platform) that supports configurable stacking, processes discounts through three calculation stages, and uses a meta‑driven rule engine to flexibly interpret JSON promotion templates, ensuring extensible, stable pricing functionality.

vivo Internet Technology
vivo Internet Technology
vivo Internet Technology
Design and Implementation of Vivo Mall Promotion Pricing Engine

Background

As the Vivo Mall business architecture continuously upgrades, complex marketing activities are being split into an independent promotion system. The original pricing logic (product detail page, shopping cart, order confirmation, order submission) remained in the main site, leading to duplicated development when promotions increase.

The promotion system must now provide pricing capabilities, requiring a redesign of the pricing model.

Original Pricing Business

The original pricing scenarios include product detail, shopping cart, order confirmation, and order submission. Three major pricing factors are identified:

Promotion activities (product‑level and order‑level discounts)

Coupons (coupons, vouchers)

Virtual deductions (points, exchange credits)

Relationships among scenarios and factors are illustrated in the diagram below:

Original Pricing Model

The original model defines a priority order among pricing factors, shown in the following diagram:

Promotion Pricing Model

The promotion system adopts a layered pricing model (product‑level, shop‑level, platform‑level). Different layers can be stacked, while the same layer is mutually exclusive unless explicitly allowed.

When calculating a discount, each layer depends on the price resulting from the previous layer (product‑level uses original price, shop‑level uses product‑level result, platform‑level uses shop‑level result).

Stacking Rules

Different layers stack by default; the same layer does not stack unless configured. Two stacking modes exist: normal stacking (e.g., order discount + coupon) and parallel stacking (e.g., coupon + voucher), where each layer’s eligibility is evaluated against the price after the preceding layer.

Core Pricing Process

The overall flow consists of three main calculation stages (CalcItem → CalcShop → CalcGroup) plus optional interruption nodes (CalcInterrupt). The generic flow is:

All three layers share a common calculation logic, differing only by the level identifier.

General Process Steps

Obtain the current level’s promotion getter

Filter the promotion getter

Query promotions

Filter promotions

Calculate discounts via the pricing engine

Filter calculation results

Flexible filter nodes allow business‑specific rules such as channel restrictions or device‑specific promotions.

System Core Design

The pricing engine interprets promotion templates, which are JSON strings describing a hierarchy of meta‑information (AND, OR, NOT, CONDITIONAL, COMPLEX). The engine executes these metas to decide whether a discount applies.

Promotion Template Example

{
  "type": "COMPLEX",
  "condition": {
    "type": "AND",
    "metas": [
      {
        "type": "CONDITIONAL",
        "metas": [
          {"type": "CONDITION", "metaCode": "terminalCheckCondition"}
        ],
        "param": "needTerminalCheck"
      },
      {"type": "CONDITION", "metaCode": "amountOverCondition"}
    ]
  },
  "action": {
    "type": "AND",
    "metas": [
      {"type": "ACTION", "metaCode": "cutPriceAction"},
      {"type": "ACTION", "metaCode": "freezeCouponAction"}
    ]
  }
}

Pricing Engine Implementation (Key Code)

private boolean executeMeta(Meta meta, EngineContext context) {
    if (meta instanceof AndMeta) {
        return executeAndMeta((AndMeta)meta, context);
    } else if (meta instanceof OrMeta) {
        return executeOrMeta((OrMeta) meta, context);
    } else if (meta instanceof NotMeta) {
        return executeNotMeta((NotMeta)meta, context);
    } else if (meta instanceof ComplexMeta) {
        return executeComplexMeta((ComplexMeta)meta, context);
    } else if (meta instanceof ConditionalMeta) {
        return executeConditionalMeta((ConditionalMeta)meta, context);
    } else {
        return executeIMeta(meta, context);
    }
}

private boolean executeComplexMeta(ComplexMeta complexMeta, EngineContext context) {
    Meta condition = complexMeta.getCondition();
    Meta action = complexMeta.getAction();
    return executeMeta(condition, context) && executeMeta(action, context);
}

private boolean executeConditionalMeta(ConditionalMeta conditionalMeta, EngineContext context) {
    PromotionContext promotionContext = context.getPromotionContext();
    if (promotionContext == null || promotionContext.getParameters() == null) {
        return true;
    }
    String conditionParam = conditionalMeta.getParameter();
    String sNeedProcess = promotionContext.getParameters().get(conditionParam);
    if (sNeedProcess == null) {
        return true;
    }
    boolean needProcess = Boolean.parseBoolean(sNeedProcess);
    if (needProcess) {
        return executeMeta(conditionalMeta.getMetas().get(0), context);
    } else {
        return true;
    }
}

private boolean executeIMeta(Meta meta, EngineContext context) {
    IMeta iMeta = MetaFactory.get(meta.getMetaDef().getMetaCode());
    if (iMeta == null) {
        throw new CalcException("meta not found, metaCode=" + meta.getMetaDef().getMetaCode());
    }
    return iMeta.execute(context);
}

The engine thus provides a flexible, extensible rule execution framework that can accommodate various promotion types while keeping the core calculation stable.

Conclusion

The article outlines the design thinking behind Vivo Mall’s promotion pricing center, covering layered pricing, unified discount models, meta‑driven templates, and a rule‑engine‑style pricing core. The approach balances stability with extensibility, laying a foundation for future pricing‑related features such as price monitoring, pricing matrices, and time‑travel debugging.

e-commercerule engineSoftware Architecturebackend developmentpromotiondiscount modelpricing engine
vivo Internet Technology
Written by

vivo Internet Technology

Sharing practical vivo Internet technology insights and salon events, plus the latest industry news and hot conferences.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.