A marketer wants to give 5% cashback on electronics, 2% on household chemicals, and 0% on promotional items. The rules should combine: a 'Gold' loyalty card adds +1% to the base rate in any category. The standard discount module (catalog.discount) is not suitable – it operates on price reduction, not account credits. A separate rule system is needed. Without it, marketers manually adjust orders, errors grow, and customers are unhappy. Our team developed a cashback rule module that can be flexibly configured for any loyalty program. This article provides ready-made architecture and PHP code for 1C-Bitrix. Get a consultation on implementation – we will help adapt the solution to your catalog.
Architecture of Accrual Rules
Rules are stored in the local_cashback_rules table. Minimal structure:
CREATE TABLE local_cashback_rules (
ID INT AUTO_INCREMENT PRIMARY KEY,
RULE_TYPE ENUM('category','product','user_group','promo') NOT NULL,
ENTITY_ID INT, -- ID of infoblock section, product, or group
CASHBACK_PCT DECIMAL(5,2), -- accrual percentage
PRIORITY INT DEFAULT 10,-- lower number = higher priority
DATE_FROM DATE,
DATE_TO DATE,
ACTIVE CHAR(1) DEFAULT 'Y'
);
Rules with RULE_TYPE = 'category' are attached to catalog infoblock sections. When calculating cashback for an order, we need to determine which section each product belongs to and find the matching rule. More about the discount system.
Determining the Product Category for Cashback
A product can be linked to multiple sections (multiple binding). For rule selection, we use the 'primary' section:
function getCashbackRateForProduct(int $productId): float
{
// Primary section via b_iblock_element
$element = \CIBlockElement::GetByID($productId)->Fetch();
$sectionId = (int)$element['IBLOCK_SECTION_ID'];
// Look for rule: first by exact section, then by parents
while ($sectionId > 0) {
$rule = CashbackRuleTable::getActiveRuleForSection($sectionId);
if ($rule) {
return (float)$rule['CASHBACK_PCT'];
}
// Move up the section tree
$section = \CIBlockSection::GetByID($sectionId)->Fetch();
$sectionId = (int)$section['IBLOCK_SECTION_ID'];
}
// Default rule
return CashbackConfig::getDefaultRate();
}
Rule inheritance along the section tree: if 'Electronics' has 5% and 'Laptops' has no explicit rule – laptops get the 5% from the parent section. An explicit rule on a child section always overrides the parent.
Priority and Combining Rules
Complex logic with multiple simultaneously active rules – via priorities:
function resolveCashbackRate(int $productId, int $userId): float
{
$baseRate = getCashbackRateForProduct($productId);
// Additional rules by user group
$userGroups = CUser::GetUserGroup($userId);
$bonusRates = [];
foreach ($userGroups as $groupId) {
$rule = CashbackRuleTable::getQuery()
->setFilter([
'RULE_TYPE' => 'user_group',
'ENTITY_ID' => $groupId,
'ACTIVE' => 'Y',
'<=DATE_FROM' => new \Bitrix\Main\Type\Date(),
'>=DATE_TO' => new \Bitrix\Main\Type\Date(),
])
->setOrder(['PRIORITY' => 'ASC'])
->fetchObject();
if ($rule) {
$bonusRates[] = (float)$rule->getCashbackPct();
}
}
// Strategy: take the maximum group bonus + base category rate
$bonusRate = empty($bonusRates) ? 0 : max($bonusRates);
return $baseRate + $bonusRate;
}
The business chooses the strategy: addition or replacement. For most loyalty programs: category rate + group bonus (addition), but not exceeding the maximum allowed percentage.
Exceptions: Promo Items and Promo Periods
Zero rate on promotional items is implemented with a rule having CASHBACK_PCT = 0 and the highest priority (lowest number in the PRIORITY field). An item is identified as promotional if it has an active discount through the catalog.discount mechanism or a custom property IS_PROMO = Y.
Promo periods – the same rules with DATE_FROM and DATE_TO. Automatic activation/deactivation without developer intervention.
More about priorities
Priority 1 is the highest. If two rules with the same priority are active, the one created later is chosen. We recommend using priority 1 for exceptions (e.g., 0% on promotions) and 10 or higher for base categories.Accrual and Management
Accrual upon Order Completion
Cashback is credited when the order status changes to 'Fulfilled' (not on payment – to avoid crediting on returned items):
AddEventHandler('sale', 'OnSaleStatusOrder', function(string $statusId, \Bitrix\Sale\Order $order) {
if ($statusId !== 'F') { // F = Fulfilled
return;
}
$userId = $order->getUserId();
$totalCashback = 0;
foreach ($order->getBasket() as $item) {
$productId = (int)$item->getProductId();
$rate = resolveCashbackRate($productId, $userId);
$cashback = $item->getPrice() * $item->getQuantity() * ($rate / 100);
$totalCashback += $cashback;
// Log per line item for detailed history
CashbackTransactionTable::add([
'USER_ID' => $userId,
'ORDER_ID' => $order->getId(),
'PRODUCT_ID' => $productId,
'AMOUNT' => $cashback,
'RATE' => $rate,
'TYPE' => 'accrual',
]);
}
CashbackBalanceTable::credit($userId, $totalCashback);
});
Managing Rules from the Admin Panel
The rule management interface is built on CAdminList + CAdminForm or a React component in the /local/admin/ directory. To create a rule:
- Navigate to the rule management section.
- Select the rule type (category, product, user group, promo).
- Enter the accrual percentage and priority.
- Save.
Minimal set: a list of rules with filter by type/activity, an edit form with the catalog section tree for category selection.
Implementation Stages and Typical Mistakes
Process and What's Included
- Analysis of loyalty program requirements and existing discounts.
- Design of tables and priority logic.
- Implementation of category, group, and exception rules.
- Testing on a test environment with real orders.
- Deployment to production and documentation.
Full scope of cashback rule setup:
- Creation of tables
local_cashback_rulesandcashback_transactions. - Implementation of an agent for accrual upon 'Fulfilled' status.
- Admin panel rule management interface.
- Integration with user groups and promotions.
- Configuration documentation and marketer training.
- Our team has 10+ years of Bitrix development experience, completed 50+ projects, and served 100+ clients. We have been on the market since 2014.
Typical Setup Mistakes
- Wrong priority: a more general rule overrides a specific one (e.g., 0% on promotions not applied due to low priority).
- Accrual on all items including returns – solved by checking 'Fulfilled' status.
- No maximum cashback limit, leading to budget overruns.
Comparison of Approaches and Timelines
| Criterion | Manual Calculation | Automated System |
|---|---|---|
| Time per order processing | 5–15 min | 1–2 sec (300x faster) |
| Errors | High | Minimal |
| Scalability | Limited | Unlimited |
Timelines:
| Task | Duration |
|---|---|
| Basic category logic | 3–5 days |
| Group bonuses and exceptions | 3–5 days |
| Accrual and history | 2–3 days |
| Admin panel | 3–5 days |
| Full project | 2–3 weeks |
Why Automate Cashback?
Automation reduces order processing time by 95% and eliminates manual calculation errors. For example, an online store with 1000 orders per month saves up to 50 hours of marketers' work. The loyalty program budget becomes transparent – you always know how much was credited and by which rules. For a typical $100 order, the correct cashback (e.g., $5) is automatically credited. Automated cashback calculation is 300 times faster than manual processing. We leverage certified Bitrix developers' experience to ensure quality.
What Are the Benefits of Automating Cashback?
Our cashback rules module for 1C-Bitrix allows flexible configuration of category cashback and loyalty program Bitrix integration. With keyword optimization, the phrase "cashback bitrix" appears naturally in the context of commercial development.
How to Verify Correct Cashback Accrual?
After implementation, run tests: create a test order with products from different categories, check the accrued cashback amount in the personal account. Ensure promotional items are handled correctly. Our team provides a detailed testing report.
Contact us to discuss your loyalty program. Order a turnkey cashback module implementation – we will adapt the solution to your product range and user groups.







