Setting Up Gift Card Sales in 1C-Bitrix
A gift certificate is a product where payment creates a coupon for an amount equal to the card's denomination. The customer gets a code, comes back, enters the code, and the order amount is deducted from their balance. Three failure points: incorrect coupon creation, wrong deduction, double usage.
Certificate as a SERVICE Type Product
In Bitrix, a gift card is implemented as a product with type TYPE_SERVICE (value 7) in b_catalog_product.TYPE, or via the sale.gift.certificate module if it's enabled in the edition. We'll cover implementation via SERVICE type — it's available in Business and Enterprise without additional modules.
A certificate product is created as a normal infoblock element in the catalog. It's assigned type 7:
\Bitrix\Catalog\ProductTable::update($productId, [
'TYPE' => \Bitrix\Catalog\ProductTable::TYPE_SERVICE,
'QUANTITY_TRACE' => 'N',
'CAN_BUY_ZERO' => 'Y',
]);
With TYPE_SERVICE, Bitrix doesn't track stock and doesn't create warehouse movements when purchasing.
Creating Coupon on Payment
After an order with a certificate is paid, a coupon for the corresponding amount must be created. This is done in the OnSaleOrderPaid handler:
AddEventHandler('sale', 'OnSaleOrderPaid', function(\Bitrix\Main\Event $event) {
$order = $event->getParameter('ENTITY');
foreach ($order->getBasket() as $item) {
if ($item->getField('TYPE') == \Bitrix\Catalog\ProductTable::TYPE_SERVICE) {
// Check this is a certificate by product property
$isCert = checkIsGiftCertificate($item->getProductId());
if (!$isCert) continue;
$code = generateCertificateCode();
$amount = $item->getPrice() * $item->getQuantity();
// Create coupon
\Bitrix\Sale\DiscountCouponsManager::add([
'COUPON' => $code,
'TYPE' => \Bitrix\Sale\DiscountCouponsManager::TYPE_ONE_ORDER,
'ACTIVE' => 'Y',
'ACTIVE_FROM' => new \Bitrix\Main\Type\DateTime(),
'MAX_USE' => 1,
'COUPON_APPLY' => \Bitrix\Sale\DiscountCouponsManager::COUPON_APPLY_ANY,
]);
// Save link: code → amount → user
saveCertificateToCustomTable($code, $amount, $order->getUserId());
// Send code to buyer's email
sendCertificateEmail($code, $amount, $order);
}
}
});
Certificate Amount Discount
A coupon in Bitrix is tied to a discount via b_sale_discount. The standard coupon mechanism supports percentage or fixed amount discounts. For a certificate, we need a fixed discount for the full denomination.
Creating a discount for a certificate:
$discountResult = \Bitrix\Sale\Internals\DiscountTable::add([
'LID' => 's1',
'ACTIVE' => 'Y',
'NAME' => 'Gift Certificate ' . $code,
'TYPE' => 'D', // discount
'COUPON_TYPE' => \Bitrix\Sale\DiscountCouponsManager::TYPE_ONE_ORDER,
'MAX_DISCOUNT' => $amount,
'VALUE_TYPE' => 'F', // fixed amount
'VALUE' => $amount,
'CURRENCY' => 'BYN',
'SORT' => 100,
]);
The coupon is added to the created discount via \Bitrix\Sale\DiscountCouponsManager::add() with DISCOUNT_ID = $discountResult->getId().
Protection Against Double Usage
The MAX_USE field in the coupon limits the number of applications. After use, Bitrix increases the USE_COUNT counter in b_sale_discount_coupon. When USE_COUNT >= MAX_USE, the coupon is deactivated.
However, there's a race condition: two orders can apply the same coupon simultaneously before the first is paid. Protection — switching the coupon to inactive status (ACTIVE = 'N') immediately when applied to an order, not when paid. This is done in the OnSaleOrderBeforeSaved handler.
Partial Usage
If the order amount is less than the certificate's denomination, the remainder is saved. The standard Bitrix discount mechanism doesn't support partial balance — the certificate is fully applied. For the remainder, use a custom table (certificate_code, initial_amount, remaining_amount) and a handler that after payment creates a new coupon for the remainder with a new code or updates the existing one.







