{"slug":"bitrix-catalog","title":"bitrix-catalog","summary":"Covers Trade Catalog module — products, SKU/offers, prices, inventory, discounts, bundles, export/import, catalog API choice. Applied for e-commerce features requiring prices, stock, and sale integration. Key terms — catalog, product, SKU, offer, price type, CCatalogProduct, cata","platform":"Claude","tags":[],"authorName":"LLM Mart","authorSlug":"llm-mart","score":0,"source":"github","price":null,"verified":false,"createdAt":"2026-08-28T17:01:55.431469Z","repo":{"url":"https://github.com/bxmaximum/bitrix-framework-skills","stars":32,"forks":5,"license":null,"updatedAt":"2026-08-25T17:45:16Z"},"bodyHtml":"<hr>\n<h2>name: bitrix-catalog\ndescription: Covers Trade Catalog module — products, SKU/offers, prices, inventory, discounts, bundles, export/import, catalog API choice. Applied for e-commerce features requiring prices, stock, and sale integration. Key terms — catalog, product, SKU, offer, price type, CCatalogProduct, catalog module.</h2>\n<h1>Trade Catalog Module</h1>\n<p>Baseline: <strong>main 23.0+</strong>. Features newer than baseline are marked <strong>Since</strong>.</p>\n<p>Catalog attaches commerce data to iblock elements. Requires <code>iblock</code> + <code>catalog</code>. Cart/orders live in <code>sale</code> — see skill <code>bitrix-sale</code>.</p>\n<pre><code>\\Bitrix\\Main\\Loader::includeModule('iblock');\n\\Bitrix\\Main\\Loader::includeModule('catalog');\n</code></pre>\n<p>Product ID = iblock element ID. Trade row: <code>b_catalog_product</code> (<code>ProductTable</code>). Prices: <code>b_catalog_price</code> (<code>PriceTable</code>). Catalog↔iblock link: <code>b_catalog_iblock</code> (<code>CatalogIblockTable</code> / <code>CCatalog</code>).</p>\n<h2>Linking an Iblock to Catalog</h2>\n<p>Register the product iblock as a catalog:</p>\n<pre><code>\\CCatalog::Add([\n    'IBLOCK_ID' =&gt; $productIblockId,\n    'YANDEX_EXPORT' =&gt; 'N',\n    'SUBSCRIPTION' =&gt; 'N',\n]);\n</code></pre>\n<p>Read binding via ORM:</p>\n<pre><code>$row = \\Bitrix\\Catalog\\CatalogIblockTable::getByPrimary($productIblockId)-&gt;fetch();\n// IBLOCK_ID, PRODUCT_IBLOCK_ID, SKU_PROPERTY_ID, VAT_ID, …\n</code></pre>\n<p>Iblock catalog kinds (<code>CCatalogSku</code>, <code>catalog/general/catalog_sku.php</code>):</p>\n<table>\n<thead>\n<tr>\n<th>Constant</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>TYPE_CATALOG</code> (<code>D</code>)</td>\n<td>Simple catalog (no SKU)</td>\n</tr>\n<tr>\n<td><code>TYPE_PRODUCT</code> (<code>P</code>)</td>\n<td>Product iblock with separate offers iblock</td>\n</tr>\n<tr>\n<td><code>TYPE_OFFERS</code> (<code>O</code>)</td>\n<td>Offers (SKU) iblock</td>\n</tr>\n<tr>\n<td><code>TYPE_FULL</code> (<code>X</code>)</td>\n<td>Product iblock that itself holds simple products + SKUs</td>\n</tr>\n</tbody>\n</table>\n<pre><code>$info = \\CCatalogSku::GetInfoByIBlock($iblockId);\n// CATALOG_TYPE, PRODUCT_IBLOCK_ID, SKU_PROPERTY_ID, …\n</code></pre>\n<h2>Product Types (<code>ProductTable</code>)</h2>\n<p>Verified in <code>catalog/lib/product.php</code>:</p>\n<table>\n<thead>\n<tr>\n<th>Constant</th>\n<th>Value</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>TYPE_PRODUCT</code></td>\n<td>1</td>\n<td>Simple product</td>\n</tr>\n<tr>\n<td><code>TYPE_SET</code></td>\n<td>2</td>\n<td>Set / bundle</td>\n</tr>\n<tr>\n<td><code>TYPE_SKU</code></td>\n<td>3</td>\n<td>Parent with offers</td>\n</tr>\n<tr>\n<td><code>TYPE_OFFER</code></td>\n<td>4</td>\n<td>Offer (SKU variant)</td>\n</tr>\n<tr>\n<td><code>TYPE_FREE_OFFER</code></td>\n<td>5</td>\n<td>Offer without parent link</td>\n</tr>\n<tr>\n<td><code>TYPE_EMPTY_SKU</code></td>\n<td>6</td>\n<td>SKU parent without offers</td>\n</tr>\n<tr>\n<td><code>TYPE_SERVICE</code></td>\n<td>7</td>\n<td>Service (no warehouse tracking)</td>\n</tr>\n</tbody>\n</table>\n<pre><code>use Bitrix\\Catalog\\ProductTable;\n\n$product = ProductTable::getByPrimary($elementId, [\n    'select' =&gt; ['ID', 'TYPE', 'QUANTITY', 'AVAILABLE', 'VAT_ID', 'VAT_INCLUDED'],\n])-&gt;fetch();\n\nProductTable::update($elementId, [\n    'QUANTITY' =&gt; 10,\n    'QUANTITY_TRACE' =&gt; ProductTable::STATUS_YES,\n    'CAN_BUY_ZERO' =&gt; ProductTable::STATUS_NO,\n]);\n</code></pre>\n<p>Prefer <code>\\Bitrix\\Catalog\\Model\\Product</code> for add/update when you need catalog automation (availability, parent SKU type, subscriptions). Legacy: <code>CCatalogProduct</code>.</p>\n<h2>SKU / Offers Pattern</h2>\n<ol>\n<li>Product iblock (parents) + offers iblock (variants).</li>\n<li>In the <strong>offers</strong> iblock: property <code>PROPERTY_TYPE = E</code>, <code>LINK_IBLOCK_ID = product iblock</code> (SKU link). Prefer <code>USER_TYPE = SKU</code> (<code>PropertyTable::USER_TYPE_SKU</code>).</li>\n<li>Register offers iblock as catalog linked to the product iblock:</li>\n</ol>\n<pre><code>\\CCatalog::Add([\n    'IBLOCK_ID' =&gt; $offersIblockId,\n    'PRODUCT_IBLOCK_ID' =&gt; $productIblockId,\n    'SKU_PROPERTY_ID' =&gt; $skuPropertyId, // E-property on offers iblock\n]);\n</code></pre>\n<p>Parent elements get <code>TYPE_SKU</code>; offer elements get <code>TYPE_OFFER</code>. Customer buys a specific offer (or a simple <code>TYPE_PRODUCT</code> when no SKU).</p>\n<h2>Prices and Price Types</h2>\n<ul>\n<li>Price type (catalog group): <code>b_catalog_group</code> → <code>Bitrix\\Catalog\\GroupTable</code> (<code>BASE</code>, <code>NAME</code>, …). Access: <code>GroupAccessTable</code> / legacy <code>CCatalogGroup</code>.</li>\n<li>Price row: <code>Bitrix\\Catalog\\PriceTable</code> — <code>PRODUCT_ID</code>, <code>CATALOG_GROUP_ID</code>, <code>PRICE</code>, <code>CURRENCY</code>, optional <code>QUANTITY_FROM</code> / <code>QUANTITY_TO</code>.</li>\n</ul>\n<pre><code>use Bitrix\\Catalog\\PriceTable;\nuse Bitrix\\Catalog\\GroupTable;\n\n$base = GroupTable::getRow(['filter' =&gt; ['=BASE' =&gt; 'Y']]);\n\nPriceTable::add([\n    'PRODUCT_ID' =&gt; $elementId,\n    'CATALOG_GROUP_ID' =&gt; (int)$base['ID'],\n    'PRICE' =&gt; 1990.00,\n    'CURRENCY' =&gt; 'RUB',\n]);\n\n$prices = PriceTable::getList([\n    'filter' =&gt; ['=PRODUCT_ID' =&gt; $elementId],\n    'select' =&gt; ['ID', 'PRICE', 'CURRENCY', 'CATALOG_GROUP_ID'],\n])-&gt;fetchAll();\n</code></pre>\n<p>Legacy write helpers: <code>CPrice</code>. VAT fields live on the product (<code>VAT_ID</code>, <code>VAT_INCLUDED</code>).</p>\n<h2>Stock and Stores (Overview)</h2>\n<ul>\n<li>Product-level qty: <code>ProductTable</code> fields <code>QUANTITY</code>, <code>QUANTITY_RESERVED</code>, <code>QUANTITY_TRACE</code>, <code>CAN_BUY_ZERO</code>, <code>AVAILABLE</code>.</li>\n<li>Multi-store: <code>StoreTable</code> (<code>b_catalog_store</code>) + <code>StoreProductTable</code> (<code>b_catalog_store_product</code>: <code>STORE_ID</code>, <code>PRODUCT_ID</code>, <code>AMOUNT</code>, <code>QUANTITY_RESERVED</code>).</li>\n<li>Documents / batches: <code>StoreDocumentTable</code>, <code>StoreBatchTable</code>, … — use for warehouse ops, not ad-hoc SQL.</li>\n</ul>\n<pre><code>use Bitrix\\Catalog\\StoreProductTable;\n\n$amounts = StoreProductTable::getList([\n    'filter' =&gt; ['=PRODUCT_ID' =&gt; $elementId],\n    'select' =&gt; ['STORE_ID', 'AMOUNT', 'QUANTITY_RESERVED'],\n])-&gt;fetchAll();\n</code></pre>\n<p><code>TYPE_SERVICE</code> products are not warehouse-tracked like ordinary goods.</p>\n<h2>Boundary with <code>sale</code></h2>\n<table>\n<thead>\n<tr>\n<th>Concern</th>\n<th>Module</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Product card, type, qty, prices, stores</td>\n<td><code>catalog</code></td>\n</tr>\n<tr>\n<td>Basket, order, payment, delivery, shipments</td>\n<td><code>sale</code></td>\n</tr>\n</tbody>\n</table>\n<p>Basket lines reference catalog product/offer IDs; price resolution and discounts may involve both modules. Do not invent cart APIs inside <code>catalog</code> — use skill <code>bitrix-sale</code>.</p>\n<h2>API Choice</h2>\n<table>\n<thead>\n<tr>\n<th>Use</th>\n<th>Prefer</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Read product/price/store rows</td>\n<td><code>ProductTable</code>, <code>PriceTable</code>, <code>StoreProductTable</code>, <code>CatalogIblockTable</code></td>\n</tr>\n<tr>\n<td>Write with catalog side effects</td>\n<td><code>\\Bitrix\\Catalog\\Model\\Product</code>, <code>CCatalog::Add/Update</code></td>\n</tr>\n<tr>\n<td>Legacy admin / compatibility</td>\n<td><code>CCatalogProduct</code>, <code>CPrice</code>, <code>CCatalogSku</code></td>\n</tr>\n</tbody>\n</table>\n<p>Inspect <code>bitrix/modules/catalog/lib/</code> before adopting newer <code>v2</code> / REST helpers — confirm against the project kernel.</p>\n<h2>Performance</h2>\n<ul>\n<li>Batch price/stock updates; avoid per-item <code>CCatalogProduct::GetByID</code> in loops/templates.</li>\n<li>Cache list queries; warm after bulk import.</li>\n<li>Load with ORM collections / joins, not N+1.</li>\n</ul>\n<h2>Checklist</h2>\n<ul>\n<li><input disabled=\"disabled\" type=\"checkbox\"> <code>iblock</code> + <code>catalog</code> included.</li>\n<li><input disabled=\"disabled\" type=\"checkbox\"> Product iblock linked via <code>CCatalog::Add</code> / <code>CatalogIblockTable</code>.</li>\n<li><input disabled=\"disabled\" type=\"checkbox\"> SKU: offers iblock + <code>PRODUCT_IBLOCK_ID</code> + <code>SKU_PROPERTY_ID</code>.</li>\n<li><input disabled=\"disabled\" type=\"checkbox\"> Types use <code>ProductTable::TYPE_*</code>.</li>\n<li><input disabled=\"disabled\" type=\"checkbox\"> Prices via <code>PriceTable</code> / price types (<code>GroupTable</code>).</li>\n<li><input disabled=\"disabled\" type=\"checkbox\"> Stock via catalog API / <code>StoreProductTable</code>, not raw SQL.</li>\n<li><input disabled=\"disabled\" type=\"checkbox\"> Cart/orders delegated to <code>sale</code> (<code>bitrix-sale</code>).</li>\n</ul>\n","files":[{"path":"SKILL.md","sizeBytes":6332,"isText":true}],"reviewScore":null,"reviewSummary":null,"trust":{"provenance":"trusted-source-unreviewed","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow.","bodySource":null},"bodyLocked":false,"purchaseUrl":null,"sourceUrl":null,"report":{"provenance":"trusted-source-unreviewed","screen":{"ran":true,"outcome":"clean","suspicious":0,"notes":0,"hiddenCharacters":false},"virusScan":{"engine":"clamav","status":"clean","scannedAt":"2026-08-28T17:03:24.933008Z","sha256":"0E331FF34A1467FC34B8A6D214087126ADC54116D8B6D89330B3362688471D5C","sizeBytes":2686},"review":null,"source":{"repositoryUrl":"https://github.com/bxmaximum/bitrix-framework-skills","path":"skills/bitrix-catalog","license":null,"commit":"66c40e0ac8bdb3a3b68c3e53745b006659341594","subtreeSha":"1EEF970568A55B274D8D980C0FB8D9E445D6C1E867579AE647A99DE5AE930E06","lastSyncedAt":"2026-09-27T19:34:22.479278Z"},"reviewedAt":"2026-08-28T17:06:21.63833Z","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow."},"install":[{"target":"skills-cli","command":"npx skills add https://github.com/bxmaximum/bitrix-framework-skills/tree/main/skills/bitrix-catalog"},{"target":"claude-code","command":"claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install bxmaximum-bitrix-framework-skills@llmmart"},{"target":"git","command":"git clone https://github.com/bxmaximum/bitrix-framework-skills.git"}]}