Developing RFQ functionality for 1C-Bitrix

Our company is engaged in the development, support and maintenance of Bitrix and Bitrix24 solutions of any complexity. From simple one-page sites to complex online stores, CRM systems with 1C and telephony integration. The experience of developers is confirmed by certificates from the vendor.
Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1175
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    811
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Development based on Bitrix, Bitrix24, 1C for the company Development of an Online Appointment Booking Widget for a Medical Center
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Development based on 1C Enterprise for MIRSANBEL
    747
  • image_crm_dolbimby_434_0.webp
    Website development on CRM Bitrix24 for DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    976

RFQ (Request for Quotation) Feature Development on 1C-Bitrix

On B2B sites, prices are often not published openly: they depend on volume, region, contract terms, or are simply managed manually. Instead of a "Buy" button, you need a "Request a Quote" button — RFQ (Request for Quotation). The standard 1C-Bitrix sale module is not suited for this task: it is designed for public pricing and immediate payment. RFQ is a separate process: request → manager processing → quotation → negotiation → order.

Process architecture

An RFQ request goes through several statuses: new → processing → quoted → accepted → rejected → ordered. After the accepted status, the customer can place an order at the agreed price through the standard sale module.

Request table bl_rfq:

CREATE TABLE bl_rfq (
    id          SERIAL PRIMARY KEY,
    user_id     INT REFERENCES b_user(ID),
    status      VARCHAR(30) DEFAULT 'new',
    manager_id  INT,
    comment     TEXT,
    manager_note TEXT,
    created_at  TIMESTAMP DEFAULT NOW(),
    updated_at  TIMESTAMP DEFAULT NOW(),
    expires_at  TIMESTAMP,
    order_id    INT
);

Request line items bl_rfq_items:

CREATE TABLE bl_rfq_items (
    id          SERIAL PRIMARY KEY,
    rfq_id      INT REFERENCES bl_rfq(id) ON DELETE CASCADE,
    product_id  INT NOT NULL,     -- infoblock element ID
    sku_id      INT,              -- trade offer ID
    quantity    NUMERIC(10,3),
    unit        VARCHAR(20),
    price_requested NUMERIC(12,2), -- price requested by the customer (optional)
    price_quoted    NUMERIC(12,2), -- price quoted by the manager
    comment     TEXT
);

RFQ add-to-request interface

The "Request a Quote" button replaces the "Add to Cart" button on product cards — or coexists with it if some products have a public price.

Display logic: in result_modifier.php of the catalog.element component, check the product property PROPERTY_PRICE_ON_REQUEST or the absence of a price in $arResult['ITEM_PRICES']:

$showRFQ = ($arResult['ITEM_PRICES'][0]['PRICE'] ?? 0) === 0
    || $arResult['ITEM']['PROPERTIES']['PRICE_ON_REQUEST']['VALUE'] === 'Y';
$arResult['SHOW_RFQ'] = $showRFQ;

The button sends an AJAX request with product_id, sku_id, quantity to the RfqController::addItemAction() controller.

RFQ cart

The customer can add multiple items before submitting — similar to a cart, but for quotes. Data is stored in the session ($_SESSION['RFQ_ITEMS']) or in the bl_rfq table with draft status. When the request is submitted, the status changes to new and the manager receives a notification.

CRM processing and notifications

When a request transitions to new status, a lead or deal is created in the CRM via \Bitrix\Crm\LeadTable::add() or the REST API crm.deal.add. Product line items from bl_rfq_items are added to the deal via crm.deal.productrows.set.

Manager notification — via \Bitrix\Im\Notify::send() (internal Bitrix24 notifications) and email via \Bitrix\Main\Mail\Event::send() with the event template RFQ_NEW_REQUEST.

Issuing a quotation and converting to an order

The manager fills in price_quoted for each line item in the admin interface and sets the status to quoted. The customer receives an email with a link to their account, where they can see the quotation. On clicking "Accept" — status becomes accepted, after which an order is created in b_sale_order with fixed prices via CSaleOrder::Add() with forced PRICE passed per line item.

Case study: industrial equipment distributor

Situation: 4,000 SKUs with no public prices; managers processed requests via email manually, response time 2–3 days.

Implementation:

  • RFQ cart with the ability to add multiple products
  • Automatic deal creation in Bitrix24 CRM on request submission
  • Customer account with request history and statuses
  • Email notifications to manager (immediately) and customer (on status change)
  • One-click conversion of an accepted quotation to an order

Result: request processing time reduced to 4 hours; managers stopped losing requests in their inboxes.

Stage Duration
Schema and state machine design 2 days
Backend: tables, controllers, agents 4 days
Frontend: button, RFQ cart, customer account 4 days
CRM integration 2 days
Email notifications and testing 2 days

What is included in development

  • RFQ state machine and data model design
  • "Add to Cart" button replacement/augmentation for products without a public price
  • RFQ cart with AJAX line item management
  • Admin interface for processing requests and setting prices
  • Integration with the Bitrix24 CRM module (deals, product line items)
  • Request history section in the customer account