mcpField
B
bitrix-catalog

bitrix-catalog

github.com/bxmaximum开发47292 次安装2 周前更新
代码仓库

关于 bitrix-catalog

面向 Bitrix 交易目录开发的技能,涵盖产品、价格、SKU 报价和库存。说明 ORM 读取与模型写入的选择,并介绍重新计算和门店访问控制相关注意事项。

主要功能

  1. 01产品与价格的 ORM 读取
  2. 02基于模型的产品和价格写入
  3. 03目录信息块与 SKU 配置
  4. 04门店库存及访问过滤
  5. 05价格类型与 VAT 指南

适用场景

  1. 01更新产品数量或 VAT
  2. 02通过目录校验添加价格
  3. 03按门店访问限制读取库存
  4. 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 价格
注册目录 iblockCCatalog::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。

评论

支持 Markdown