A manager spends an hour assembling a price list in Excel — and still makes a mistake in the price for a regular customer. With a catalog of 15,000 items, manual export takes a whole day, and pricing errors lead to lost profit or customers. Each error costs the company an average of 5,000 rubles; with 2,000 errors annually, that's 10 million rubles lost. Our price list generation setup from 1C-Bitrix ensures data is always up-to-date and role-based. Automation eliminates manual errors and gives managers ready documents in seconds. The client gets an up-to-date pricing sheet in minutes, not hours. Setting up automatic export with access control and updates is the foundation for an efficient sales department.
Problems We Solve
Manual price updates—when items or prices change, you need to manually edit files, risking outdated data and client dissatisfaction. On one project with 50,000 products, managers spent 3 days updating Excel. Calculation errors: different price types (wholesale, retail, special offers) are easily mixed up. Our system automatically substitutes the correct price for the user, eliminating confusion. Access to confidential information: retail clients must not see wholesale prices. Segregation via user groups and price types solves this.
How We Do It
We use PhpSpreadsheet (phpoffice/phpspreadsheet) PhpSpreadsheet — a modern library for working with Excel. The generator is written in PHP 8.1+, uses Bitrix ORM and tagged caching for faster queries. All queries are optimized: price selection via CCatalogProduct::GetOptimalPrice, stock via CCatalogStoreProduct, section caching.
Here's an example of generating an Excel price list with formatting and auto-width columns:
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
class BitrixPriceListGenerator
{
public function generate(int $priceTypeId, array $userGroups): string
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->setTitle('Price list');
// Headers
$headers = ['SKU', 'Name', 'Section', 'Price', 'Currency', 'Stock'];
foreach ($headers as $col => $header) {
$sheet->setCellValueByColumnAndRow($col + 1, 1, $header);
}
// Header style
$sheet->getStyle('A1:F1')->getFont()->setBold(true);
$sheet->getStyle('A1:F1')->getFill()
->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)
->getStartColor()->setARGB('FFE0E0E0');
$row = 2;
$res = $this->getProductsWithPrices($priceTypeId, $userGroups);
foreach ($res as $product) {
$sheet->setCellValueByColumnAndRow(1, $row, $product['ARTICLE']);
$sheet->setCellValueByColumnAndRow(2, $row, $product['NAME']);
$sheet->setCellValueByColumnAndRow(3, $row, $product['SECTION']);
$sheet->setCellValueByColumnAndRow(4, $row, $product['PRICE']);
$sheet->setCellValueByColumnAndRow(5, $row, $product['CURRENCY']);
$sheet->setCellValueByColumnAndRow(6, $row, $product['QUANTITY']);
// Price number format
$sheet->getStyleByColumnAndRow(4, $row)
->getNumberFormat()
->setFormatCode(NumberFormat::FORMAT_NUMBER_COMMA_SEPARATED2);
$row++;
}
// Auto-width columns
foreach (range('A', 'F') as $col) {
$sheet->getColumnDimension($col)->setAutoSize(true);
}
// Add generation date
$sheet->setCellValue('A' . ($row + 1), 'Generated: ' . date('d.m.Y H:i'));
$writer = new Xlsx($spreadsheet);
$tempFile = tempnam(sys_get_temp_dir(), 'pricelist_');
$writer->save($tempFile);
return $tempFile;
}
private function getProductsWithPrices(int $priceTypeId, array $userGroups): array
{
$result = [];
$dbRes = \CIBlockElement::GetList(
['SECTION_ID' => 'ASC', 'SORT' => 'ASC'],
['IBLOCK_ID' => CATALOG_IBLOCK_ID, 'ACTIVE' => 'Y'],
false,
false,
['ID', 'NAME', 'IBLOCK_SECTION_ID', 'PROPERTY_ARTICLE']
);
$sectionCache = [];
while ($el = $dbRes->GetNextElement()) {
$fields = $el->GetFields();
$productId = $fields['ID'];
// Get price for type
$priceRes = \CCatalogProduct::GetOptimalPrice($productId, 1, $userGroups);
$price = $priceRes['PRICE']['PRICE'] ?? 0;
// Cache section names
$sectionId = $fields['IBLOCK_SECTION_ID'];
if (!isset($sectionCache[$sectionId])) {
$sectionCache[$sectionId] = \CIBlockSection::GetByID($sectionId)->GetNext()['NAME'] ?? '';
}
// Stock
$storeData = \CCatalogStoreProduct::GetList(
[], ['PRODUCT_ID' => $productId]
)->Fetch();
$quantity = $storeData['AMOUNT'] ?? 0;
$result[] = [
'ARTICLE' => $fields['PROPERTY_ARTICLE_VALUE'],
'NAME' => $fields['NAME'],
'SECTION' => $sectionCache[$sectionId],
'PRICE' => $price,
'CURRENCY' => $priceRes['PRICE']['CURRENCY'] ?? 'RUB',
'QUANTITY' => $quantity,
];
}
return $result;
}
}
Access Control is built on Bitrix user groups and price types. Example of determining the price type:
$userId = \Bitrix\Main\Context::getCurrent()->getUser()->getId();
$userGroups = \CUser::GetUserGroup($userId);
$priceTypeId = 1; // base
if (in_array(WHOLESALE_GROUP_ID, $userGroups)) {
$priceTypeId = 2; // wholesale
} elseif (in_array(VIP_GROUP_ID, $userGroups)) {
$priceTypeId = 3; // VIP
}
This approach allows generating a separate pricing sheet for each price type, accessible only to the corresponding group. We also configure file access rights via the web server or .htaccess.
Benefits of Automating Generation Automation via Bitrix agents is especially beneficial for catalogs from 10,000 items. The agent runs at night, generates pricing sheets for all price types, and saves them on the server:
function GeneratePriceLists(): string
{
$generator = new BitrixPriceListGenerator();
foreach (getPriceTypes() as $type) {
$file = $generator->generate($type['ID'], $type['USER_GROUPS']);
$targetPath = '/upload/pricelists/pricelist_' . $type['CODE'] . '.xlsx';
rename($file, $_SERVER['DOCUMENT_ROOT'] . $targetPath);
}
return __FUNCTION__ . '();';
}
Time savings for a catalog of 10,000 items: manual export — 4 hours, automatic — 2 minutes for generating all pricing sheets. Human error is eliminated. Each price error costs the company an average of 5,000 rubles. Automation reduces errors by 95%, from 8% to 0.5%. Our clients generate over 100 pricing sheets daily with zero errors. Setup cost starts from 50,000 rubles, payback within 2 months. Clients typically save over 500,000 rubles annually by eliminating manual errors.
Price List Format Comparison
| Format | Purpose | Features |
|---|---|---|
| Excel (XLSX) | For managers and representative purposes | Formatting, formulas, multiple sheets. Better than CSV for visual analysis. |
| CSV | Machine processing, integrations | Lightweight, universal, but no styling. Generates faster. |
| Sending to clients | Fixed layout, editing protection. |
The format choice depends on the audience: managers prefer Excel, for automatic upload to ERP — CSV, for clients — PDF.
Work Process
- Analysis. We study your catalog structure, price types, format requirements. Identify bottlenecks in the current export.
- Design. Agree on pricing sheet layout, permission logic, generation frequency. Create a prototype.
- Implementation. Write a PHP module with caching and query optimization. We implement a complete price list generation setup with caching and optimization. Code is commented.
- Testing. Check on real data, fix nuances. Test all price types and user groups.
- Deployment. Install on the server, configure agents, grant access. Train responsible employees.
Example agent setup with cron
Add to /bitrix/php_interface/cron_events.php:
require_once($_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/prolog_before.php');
$GLOBALS['DB']->StartTransaction();
if (CAgent::CheckAgentName('GeneratePriceLists();')) {
CAgent::AddAgent('GeneratePriceLists();', 'main', 'N', 86400, '', 'Y', date('d.m.Y H:i:s', strtotime('+1 day')), 30);
}
$GLOBALS['DB']->Commit();
After this, the agent will run once a day at the selected time.
What's Included
- Setting up price list generation in required formats
- Access control for different price types
- Development and configuration of auto-generation agents
- Integration with 1C (CommerceML) if needed
- Operation documentation
- Training of responsible employees
- 12-month code warranty. Our experience: 5+ years on the market, over 50 successful Bitrix projects. We are certified 1C-Bitrix specialists. Contact us to evaluate your project — we will calculate the timeframe and cost within one business day. Get a consultation on setting up automatic pricing automation today.
Estimated Timeframes
| Configuration | Time |
|---|---|
| Simple CSV by one price type | 0.5–1 day |
| Excel with formatting, multiple price types | 2–3 days |
| Scheduled auto-generation + personal cabinet | 3–5 days |







