关于 bitrix-catalog
面向 Bitrix 交易目录开发的技能,涵盖产品、价格、SKU 报价和库存。说明 ORM 读取与模型写入的选择,并介绍重新计算和门店访问控制相关注意事项。
主要功能
- 01产品与价格的 ORM 读取
- 02基于模型的产品和价格写入
- 03目录信息块与 SKU 配置
- 04门店库存及访问过滤
- 05价格类型与 VAT 指南
适用场景
- 01更新产品数量或 VAT
- 02通过目录校验添加价格
- 03按门店访问限制读取库存
- 04处理带 SKU 报价的产品
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ bxmaximum/ bitrix-framework-skills --skill bitrix-catalog安装后在 Claude Code 中输入/bitrix-catalog确认已加载。
详细介绍
交易目录(catalog)
基线:main 23.0+ · 已验证:catalog 26.400.0、main 26.800.0
产品 ID = iblock 元素 ID。需要加载 iblock + catalog。购物车、订单、付款 → bitrix-sale;元素和属性 → bitrix-iblocks。
API 选择
| 需求 | 使用 |
|---|---|
| 读取产品/价格/仓库行 | ProductTable、PriceTable、StoreProductTable、CatalogIblockTable(ORM) |
| 写入产品字段(数量、类型、VAT) | Model\Product::add/update — 重新计算 AVAILABLE、父级 SKU 类型/可用性、套装和订阅 |
| 写入价格 | Model\Price::add/update/delete — 计算 PRICE_SCALE、验证货币、重新统计父级 SKU 价格 |
| 注册目录 iblock | CCatalog::Add/Update(没有 D7 写入器) |
| 仅用于旧版兼容 | CCatalogProduct、CPrice、CCatalogSku 助手 |
切勿直接写入 ProductTable/PriceTable:不带 PRICE_SCALE 调用 PriceTable::add() 会导致验证失败,而直接写入会跳过可用性和 SKU 重新计算。
目录 iblock 和 SKU
\CCatalog::Add(['IBLOCK_ID' => $productIblockId]); // simple catalog
\CCatalog::Add([
'IBLOCK_ID' => $offersIblockId,
'PRODUCT_IBLOCK_ID' => $productIblockId,
'SKU_PROPERTY_ID' => $skuPropertyId, // E property on the offers iblock, USER_TYPE = PropertyTable::USER_TYPE_SKU, LINK_IBLOCK_ID = products
]);
$info = \CCatalogSku::GetInfoByIBlock($iblockId); // CATALOG_TYPE, PRODUCT_IBLOCK_ID, IBLOCK_ID, SKU_PROPERTY_ID…
CATALOG_TYPE:CCatalogSku::TYPE_CATALOG(D,普通)、TYPE_PRODUCT(P,仅父级)、TYPE_OFFERS(O,offers iblock)、TYPE_FULL(X,产品 + SKU 父级)。获取产品的 offers:\CCatalogSku::getOffersList($productIds, $iblockId)。
产品类型 ProductTable::TYPE_*:PRODUCT 1、SET 2、SKU 3(带 offers 的父级)、OFFER 4、FREE_OFFER 5(没有父级的 offer)、EMPTY_SKU 6、SERVICE 7(不跟踪库存)。购买 offer(TYPE_OFFER),不要购买 SKU 父级。
use Bitrix\Catalog\Model\Product;
use Bitrix\Catalog\ProductTable;
$result = Product::update($elementId, [ // Product::add(['ID' => $elementId, 'TYPE' => ProductTable::TYPE_PRODUCT, …]) for a new row
'QUANTITY' => 10,
'QUANTITY_TRACE' => ProductTable::STATUS_YES,
'CAN_BUY_ZERO' => ProductTable::STATUS_NO,
]);
if (!$result->isSuccess()) { /* $result->getErrorMessages() */ }
价格
价格类型:GroupTable(b_catalog_group);基准类型为 GroupTable::getBasePriceTypeId()(已缓存,?int)。各类型的查看/购买权限:GroupAccessTable。
use Bitrix\Catalog\GroupTable;
use Bitrix\Catalog\Model\Price;
use Bitrix\Catalog\PriceTable;
$result = Price::add([
'PRODUCT_ID' => $elementId,
'CATALOG_GROUP_ID' => GroupTable::getBasePriceTypeId(),
'PRICE' => 1990.00,
'CURRENCY' => 'RUB', // must exist in the currency module
]);
if (!$result->isSuccess()) { /* $result->getErrorMessages() */ }
$prices = PriceTable::getList([
'select' => ['ID', 'CATALOG_GROUP_ID', 'PRICE', 'CURRENCY', 'QUANTITY_FROM', 'QUANTITY_TO'],
'filter' => ['=PRODUCT_ID' => $elementId],
])->fetchAll();
VAT 位于产品上(VAT_ID、VAT_INCLUDED);税率位于 VatTable 中。最终买家价格和折扣由 sale(bitrix-sale)计算,而不是通过读取 PriceTable 获取。
库存和仓库
- 产品级别:
ProductTable上的QUANTITY、QUANTITY_RESERVED、QUANTITY_TRACE、CAN_BUY_ZERO、AVAILABLE。 - 仓库:
StoreTable+StoreProductTable(STORE_ID、PRODUCT_ID、AMOUNT、QUANTITY_RESERVED)。仓库操作(入库、移动、核销)通过仓库单据(StoreDocumentTable,使用CCatalogDocs::conductDocument($docId, $userId)执行;出错时返回false+$APPLICATION->GetException()),而不是直接编辑AMOUNT或使用 SQL。 - 仓库权限(使用
crm进行库存管理):与用户可查看的内容保持一致:
use Bitrix\Catalog\Access\AccessController;
use Bitrix\Catalog\Access\ActionDictionary;
use Bitrix\Catalog\StoreProductTable;
$access = AccessController::getCurrent()
->getEntityFilter(ActionDictionary::ACTION_STORE_VIEW, StoreProductTable::class) ?? [];
$rows = StoreProductTable::getList([
'select' => ['STORE_ID', 'AMOUNT', 'QUANTITY_RESERVED'],
'filter' => [['=PRODUCT_ID' => $elementId], $access], // nested: an OR in user filter cannot bypass access
])->fetchAll();
- 自 catalog 26.400 起,REST
catalog.storeproduct.list/get和catalog.document.element.list会应用此筛选条件。被禁止访问的仓库对应的单据行中,STORE_FROM/STORE_TO/AMOUNT/PURCHASING_PRICE会返回null,且无法按这些字段筛选或排序。集成不得依赖这些字段。管理员和旧版模式下的库存行不会被筛选:AccessController::getCurrent()->isLegacyAccessMode()(自 catalog 26.400 起;之前:!ModuleManager::isModuleInstalled('crm'))。较旧版本通过 REST 返回所有仓库:请在集成中进行筛选。
检查清单
- 已加载
iblock+catalog;目录 iblock 通过CCatalog::Add注册,SKU 配置了PRODUCT_IBLOCK_ID+SKU_PROPERTY_ID。 - 通过
Model\Product/Model\Price写入产品和价格,并检查每个Result。 - 通过
GroupTable::getBasePriceTypeId()获取基准价格类型,不要硬编码 ID。 - 将 offers(而不是 SKU 父级)加入购物篮。
- 对用户受限的仓库读取库存时使用仓库访问筛选条件;不要使用原始 SQL。
- 批量读取(收集 ID,执行一次查询);不要在循环中调用
CCatalogProduct::GetByID。