v2.0

GoRules Version 2 is here - redesigned, now with managed cloud.GoRules Version 2 is here!

Watch the launch videoWatch

Returns Processing System

Streamlines product return processing by applying business rules based on customer status, product details, and return circumstances for optimal efficiency.

Solution

This returns management system automates and standardizes the entire returns process by applying configurable business rules. It analyzes multiple factors including product type, condition, purchase timeframe, and return reason to determine the appropriate handling path and refund amount. For electronics and appliances still under warranty, defective items receive full replacements, while damaged goods qualify for partial refunds with restocking fees.

The system dynamically adjusts return policies based on customer membership tier, providing premium members with more favorable terms. It handles receipt verification, calculates appropriate refund amounts, and assigns restocking fees according to product condition and return timeframe. Each return is assigned to a specific processing department with an appropriate priority level and expected processing timeline. The system also generates the right customer communication, ensuring consistent messaging aligned with the return decision.

How it works

The decision flow processes return requests through five sequential evaluation stages:

  1. Customer Eligibility Assessment: Analyzes customer profile data to determine high-value status, frequent returner patterns, and purchase timeframe to establish initial eligibility parameters.
  2. Return Type Classification: Evaluates product type, condition, purchase timeframe, and return reason against a comprehensive rule set to determine the appropriate return handling type.
  3. Processing Queue Assignment: Routes each return to the appropriate department based on return type (warranty, quality assurance, customer service, or standard returns).
  4. Priority Level Determination: Assigns a processing priority and timeline based on customer value and item value, ensuring faster processing for high-value customers.
  5. Customer Communication Selection: Determines the appropriate communication template based on return approval status to ensure clear and consistent messaging.

Where teams use it

  • Retail e-commerce operations
  • Electronics and appliance retailers
  • Clothing and accessories stores
  • Omnichannel retail businesses
  • Customer service departments
  • Warranty processing centers
  • Quality assurance departments

Inside the decision model

Returns Processing System ships as a JDM decision graph with 6 nodes, 4 decision tables and 18 rules. Download it, load it into GoRules, and run it as-is on Zen Engine.

Decision graph6 nodes · read-only
input requestexpression customerEligibilitytable determineReturnTypetable determineProcessingQueuetable determinePriorityLeveltable determineCommunication
01

Request

input

Three nested objects frame the request: customer with membershipTier and returnsHistoryCount, product with type, condition, daysFromPurchase, and price, and return with reason and hasReceipt. The schema pins membershipTier to standard, premium, or vip and condition to five states, which the classification table matches against directly.

Sample requestJSON
{
  "customer": {
    "id": "CUST-12345",
    "membershipTier": "premium",
    "returnsHistoryCount": 3
  },
  "product": {
    "type": "electronics",
    "condition": "damaged",
    "daysFromPurchase": 12,
    "price": 249.99
  },
  "return": {
    "reason": "defective item - won't power on",
    "hasReceipt": true
  }
}
02

Customer Eligibility

expression

Four boolean flags are derived up front: isHighValueCustomer is true for a 'vip' or 'premium' customer.membershipTier, isFrequentReturner trips when customer.returnsHistoryCount > 5, isPurchaseWithinWarranty checks product.daysFromPurchase <= 30, and isHighValueItem marks product.price >= 100. Precomputing these keeps the big classification table free of repeated tier and threshold logic and lets later tables branch on single fields.

Expressions4 fields
isHighValueCustomercustomer.membershipTier == 'vip' or customer.membershipTier == 'premium'
isFrequentReturnercustomer.returnsHistoryCount > 5
isPurchaseWithinWarrantyproduct.daysFromPurchase <= 30
isHighValueItemproduct.price >= 100
03

Determine Return Type

table

Eight first-hit rows cross product.type, product.condition, return.reason, product.daysFromPurchase, and return.hasReceipt into a return type, refund, and fee. Defective 'electronics' or 'appliances' in new condition within 30 days with a receipt earn 'warranty_replacement' at full product.price; damaged or opened units within 15 days drop to 'partial_refund' at 80% with a 10 restocking fee; clothing follows a parallel pair of rows at 100% or 70% store credit. Reasons containing 'quality' get a 'quality_review' within 90 days, receiptless returns past 30 days become discounted 'store_credit' where isHighValueCustomer lifts the payout from 50% to 80% and waives the 15 fee, anything past 90 days is 'denied', and the catch-all routes to 'manual_review'.

The economics behind the tiers are standard retail returns practice: opened electronics cannot be resold as new, so the refund haircut and restocking fee recover part of the remarketing loss, and receiptless returns pay out less because the purchase price cannot be verified. Softening those penalties for premium and vip customers is a deliberate retention trade, spending margin on the customers with the highest lifetime value, while the hard 90-day cutoff bounds the liability window entirely.

Decision tablefirst hit policy
Product Typeproduct.typeProduct Conditionproduct.conditionReturn Reasonreturn.reasonDays From Purchaseproduct.daysFromPurchaseHas Receiptreturn.hasReceiptReturn TypereturnDetails.typeRefund AmountreturnDetails.refundAmountRestocking FeereturnDetails.restockingFee
'electronics', 'appliances''new', 'like_new'startsWith($, 'defect')<= 30true'warranty_replacement'product.price0
'electronics', 'appliances''damaged', 'opened'-<= 15true'partial_refund'product.price * 0.810
'clothing', 'accessories''new', 'like_new'-<= 30true'full_refund'product.price0
'clothing', 'accessories''used', 'opened'-<= 15true'store_credit'product.price * 0.75
--contains($, 'quality')<= 90-'quality_review'isHighValueCustomer ? product.price : product.price * 0.90
---> 30false'store_credit'isHighValueCustomer ? product.price * 0.8 : product.price * 0.5isHighValueCustomer ? 0 : 15

+2 more rows in the downloadable template

04

Determine Processing Queue

table

Queue routing keys on returnDetails.type alone: 'warranty_replacement' goes to the 'warranty_dept', 'quality_review' to 'quality_assurance', 'manual_review' to 'customer_service', and the blank catch-all sends everything else to the general 'returns_dept'. First hit ordering makes the three specialist rows take precedence over the default.

Separating queues this way matches how return operations are actually staffed: warranty claims need technicians who can test the unit, quality reviews feed defect data back to sourcing, and edge cases need a human with discretion. Keeping the mapping in its own table means a reorganization changes four rows, not the classification logic.

Decision tablefirst hit policy
Return TypereturnDetails.typeProcessing QueuereturnDetails.processingQueue
'warranty_replacement''warranty_dept'
'quality_review''quality_assurance'
'manual_review''customer_service'
-'returns_dept'
05

Determine Priority Level

table

Service speed pairs isHighValueCustomer with isHighValueItem: a high-value customer gets 'high' priority and 2 expected processing days regardless of item value, an ordinary customer returning an item worth 100 or more gets 'medium' and 5 days, and everything else runs 'standard' at 7 days.

Putting the customer flag ahead of the item flag encodes a retention-first stance, since a premium member returning a cheap item still sees the fast lane. The 2, 5, and 7 day targets are internal SLA choices, useful mainly because publishing an expected timeline cuts the where-is-my-refund contact volume.

Decision tablefirst hit policy
High Value CustomerisHighValueCustomerHigh Value ItemisHighValueItemPriority LevelreturnDetails.priorityLevelExpected Processing DaysreturnDetails.expectedProcessingDays
true-'high'2
falsetrue'medium'5
falsefalse'standard'7
06

Determine Communication

table

Messaging follows the verdict in three rows on returnDetails.type: 'denied' triggers the 'rejection_notice' template, 'partial_refund' and 'store_credit' share the 'partial_approval' template, and the catch-all sends 'approved' for everything else.

Collapsing many return types into three templates is a sensible communications choice, because customers only need to know whether they get everything, something, or nothing. Binding the template to the decision output also guarantees the letter can never contradict the refund that was actually booked.

Decision tablefirst hit policy
Return TypereturnDetails.typeCustomer CommunicationreturnDetails.customerCommunication
'denied''rejection_notice'
'partial_refund', 'store_credit''partial_approval'
-'approved'

Make this template
your own.

Load Returns Processing System into GoRules, adjust the rules to your policy, and ship it behind your own API.