bitrix-catalog について
Bitrix のトレードカタログ開発向けスキルです。商品、価格、SKU オファー、在庫を扱い、再計算や店舗アクセスに配慮した ORM 読み取りとモデル経由の書き込み方法を説明します。
主な機能
- 01商品と価格の ORM 読み取り
- 02モデル経由の商品・価格の書き込み
- 03カタログ情報ブロックと SKU の設定
- 04店舗在庫とアクセスフィルター
- 05価格タイプと VAT の指針
活用シーン
- 01商品の数量や VAT の更新
- 02カタログ検証を通した価格の追加
- 03店舗アクセス制限下での在庫参照
- 04SKU オファーを持つ商品の処理
インストール
コマンドをコピーしてターミナルで実行します。
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、オファー iblock)、TYPE_FULL(X、商品 + SKU 親)。商品のオファー:\CCatalogSku::getOffersList($productIds, $iblockId)。
商品タイプ ProductTable::TYPE_*:PRODUCT 1、SET 2、SKU 3(オファーを持つ親)、OFFER 4、FREE_OFFER 5(親を持たないオファー)、EMPTY_SKU 6、SERVICE 7(在庫管理なし)。購入するのはオファー(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 にあります。最終購入者向けの価格と割引は PriceTable から読み取るのではなく、sale(bitrix-sale)で計算されます。
在庫と店舗
- 商品レベル:
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を読み込み、CCatalog::Addでカタログ iblock を登録し、PRODUCT_IBLOCK_ID+SKU_PROPERTY_IDを使用して SKU を設定する。 - 商品と価格の書き込みには
Model\Product/Model\Priceを使用し、すべてのResultを確認する。 - 基本価格タイプには
GroupTable::getBasePriceTypeId()を使用し、ID をハードコードしない。 - バスケットには SKU 親ではなくオファーを追加する。
- ユーザーに制限がある場合は店舗アクセスフィルターを使用して在庫を読み取り、直接 SQL は使用しない。
- 読み取りはまとめて行う(ID を収集してクエリを 1 回実行)。ループ内で
CCatalogProduct::GetByIDを使用しない。