When processing 500+ orders per day, a makeshift gift certificate implementation causes issues: duplicate codes, missed emails, broken coupons. We rewrote modules for 15 projects — the same errors kept appearing: incorrect codes, missing partial redemption, fiscalization problems. A well-thought-out architecture reduces support costs by 20–30% and pays off in 2–3 months. In 95% of cases, problems arise from incorrect coupon configuration; the average time to fix one incident is 4 hours. Let's examine how to set up electronic certificates from product to balance, using built-in Bitrix mechanisms and custom modifications.
How to Set Up the Sale of Electronic Certificates: From Product to Balance
An electronic certificate is created as a regular infoblock element, but with special features. Product type — simple product without stock accounting (unlimited quantity, uncheck "Quantitative Accounting"). Create SKUs by denominations: 1000, 2000, 5000 rubles. Each SKU has its own price equal to the denomination. Set the property "Delivery Type" to "Electronic delivery" so that no address is requested during checkout. In the product card, add an infoblock property "Certificate Denomination" (type — number). This will be used by the handler when generating the coupon.
How to Generate Unique Certificate Codes
Upon successful order payment, the event handler OnSalePayOrder generates a unique certificate code via Bitrix\Main\Security\Random::getString(12) — 12 characters from A-Z, 0-9. Handler logic:
- Check if the order contains a product from the "Certificates" section (by infoblock section ID).
- Generate the code.
- Create a coupon via
Bitrix\Sale\Internals\DiscountCouponTable::add()linked to a basket rule. - Save the code and denomination in order properties (user fields
UF_CERTIFICATE_CODE,UF_CERTIFICATE_AMOUNT).
The coupon is created with type "For order series" and maximum usage count — this allows partial usage. According to Bitrix documentation, coupons of this type can be used multiple times until the limit is exhausted.
Generating the PDF
The PDF is generated using mPDF or Dompdf — included via Composer. The document template is an HTML file with variable substitution:
- Voucher code
- Denomination
- Issue date and expiration date
- QR code for quick activation (generated via
chillerlan/php-qrcodeor similar)
The HTML template is stored in /local/templates/certificate/ and contains inline styles (mPDF does not fully support external CSS). The background image is set via CSS background-image with an absolute path to the file on the server. The result is saved to /upload/certificates/ with a name based on the coupon code. Access to the directory is restricted via .htaccess — the file is only served through a PHP script with authorization checks.
Sending by Email
The mail event CERTIFICATE_CREATED is created under Settings → Mail Events. The email template contains:
| Macro | Value |
|---|---|
#CODE# |
Coupon code |
#AMOUNT# |
Denomination |
#VALID_UNTIL# |
Expiration date |
#PDF_LINK# |
Link to download PDF |
Sending is triggered from the same OnSalePayOrder handler after PDF generation. The email is sent to the buyer's email from the order. If a separate recipient email is specified in the order ("Recipient email for gift"), the email is duplicated to that address.
Electronic Certificates Instead of Coupons
The built-in Bitrix coupon system does not support coupon balance out of the box. Compare with a custom solution:
| Parameter | Built-in Coupon System | Custom Module |
|---|---|---|
| Partial redemption | No | Yes |
| Usage history | No | Yes |
| Balance display in account | No | Yes |
| 1C integration | Difficult, via API | Ready-made handlers |
For partial redemption, a modification is needed:
- The
OnSaleOrderPaidhandler checks if the coupon was used in a paid order. - If the order total is less than the denomination, the remainder is calculated.
- The basket rule is updated: new discount amount = remainder.
- Usage history is recorded in a separate table (custom table
b_certificate_usage).
If the order total is equal to or greater than the denomination, the coupon is deactivated via DiscountCouponTable::update() with field ACTIVE = N. The coupon balance is displayed in the buyer's account via a custom component that reads data from b_certificate_usage and the current basket rule. In one project, we implemented this mechanism for an electronics retail chain — it handled 3000 operations per day without a single failure for 3 years.
Activating the Electronic Certificate
The redemption mechanism works via the sale.discount module. When generating the coupon, a basket rule is created:
- Discount type — fixed sum equal to the coupon denomination.
- Binding — coupon whose code matches the voucher code.
- Scope — entire order (or specific catalog sections, if it's a category coupon).
The buyer enters the coupon code in the "Coupon" field during checkout. The system applies a discount equal to the denomination.
Setting an Expiration Date
Expiration is set in the basket rule via fields ACTIVE_FROM and ACTIVE_TO. The standard period is 12 months from purchase. After expiration, the coupon automatically stops working, and in the account, the coupon displays as "Expired". To monitor expiry, we configure an agent that sends a reminder to the buyer 7 days before expiration.
Ready-made modules from the Marketplace often do not support partial redemption, 1C integration, or PDF template customization. They only work with 100% write-off scenarios. Our experienced team guarantees that a custom solution is 5 times more flexible than off-the-shelf modules, and development cost starts from $500. We did this for an electronics retail chain — the solution saved them 30% in support costs and paid off in 2 months.
Typical Setup Errors
- Incorrect coupon type: "For one order" instead of "For order series" — coupon fully consumed.
- Missing caching of coupon table queries — with 500+ orders, database load increases 10 times.
- Wrong infoblock section ID in handler — code generation fails.
- Ignoring the
OnSaleCancelOrderhandler — when an order is cancelled, the code is not released.
What's Included in the Service
- Module development for code generation, coupons, and usage history.
- Integration with payment systems and 1C via CommerceML.
- PDF document template with QR code.
- Mail event setup and email sending with attachment.
- Documentation and source code handover.
- Technical support for one month after launch.
Contact us to assess your project — we will prepare a commercial proposal within one business day. Order module development — timelines from 20 hours. Our engineers ensure correct fiscalization and integration with any payment systems. Get a consultation on your scenario.







