Search by

mar-pod-b2b / module-b2b-shared-catalog

Company-specific catalog visibility and indexed catalog permissions for Marpod B2B Advanced.

Maintainers

Package info

gitlab.com/mar-pod-b2b/module-b2b-shared-catalog

Issues

Type:magento2-module

pkg:composer/mar-pod-b2b/module-b2b-shared-catalog

Transparency log

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

1.2.4 2026-08-24 16:09 UTC

README

Per-company visible assortment: which categories and products a company's storefront users can see at all, independent of price.

Status

Full catalog engine, indexer, cache integration, and Admin UI shipped. Assortment is assigned at the company level (one company = one catalog); unit-level assignment (once Marpod_B2bCompanyHierarchy is also installed) is a natural future extension but is not a hard requirement today.

Implemented foundation

  • declarative schema: marpod_b2b_shared_catalog (public/custom catalogs, one public catalog per website created automatically), marpod_b2b_shared_catalog_category and marpod_b2b_shared_catalog_product (category- and product-level assignment — assigning a category makes every product in it visible, on top of any individually-assigned product; the two mechanisms add together), marpod_b2b_shared_catalog_company (company-to-catalog assignment), marpod_b2b_shared_catalog_product_index (the flattened visibility index category listing pages query against via a JOIN, not by filtering a loaded collection);
  • a default public catalog is created automatically per website (via a website_save_after observer plus a data patch for existing websites) so a company with no explicit assignment still sees the full standard catalog; custom (private) catalogs are assigned explicitly;
  • SharedCatalogIndexBuilderInterface / the marpod_b2b_shared_catalog_product indexer — full-rebuild per catalog on every run (assignment edits are rare in practice, so this trades a simpler implementation for not tracking partial/incremental changes);
  • SharedCatalogVisibilityCheckerInterface — direct access to a product outside a company's catalog (e.g. typing the PDP URL directly) returns 404, not just a hidden listing row;
  • Full Page Cache correctness: product-listing blocks render as cacheable and do not see the real customer session while a cache entry is being built (so the same HTML can be shared safely across customers in the same group). SetSharedCatalogHttpContextPlugin resolves the customer's catalog_id once, early (ActionInterface::beforeExecute, the same hook level Magento's own customer_group context plugin uses), stores it in Magento\Framework\App\Http\Context, and a separate plugin only reads it later during Layer::prepareProductCollection — so Varnish/FPC correctly varies the cached page per catalog instead of serving one company's assortment to another.

Admin UI

Marpod_B2bSharedCatalog::manage (marpod_b2b_shared_catalog/catalog/index) provides a catalog grid and a customer-style edit screen with General, Assigned Categories, Assigned Products, and Assigned Companies tabs. Assignment grids are shown before separate assignment forms, page actions use Magento's native action bar, and assignment POST actions restore the originating tab. The screen also provides a manual reindex action.

APIs

Administrative REST operations require Marpod_B2bSharedCatalog::manage and are available below /V1/marpod-b2b/shared-catalogs. They cover catalog CRUD plus category, product, and company assignment reads and writes. Company assignment removal is available at DELETE /V1/marpod-b2b/shared-catalog-companies/:companyId.

The storefront GraphQL query marpodB2bSharedCatalog returns the catalog resolved for the current visitor and website, including assigned category IDs and directly assigned product IDs. A company catalog is resolved from authenticated customer membership; guests and customers without an explicit company assignment receive the website's default public catalog. A submitted company ID is never trusted by the resolver.

Requirements

  • PHP 8.5
  • Magento 2.4.9-compatible framework packages
  • mar-pod-b2b/module-b2b-core, mar-pod-b2b/module-b2b-company

May be combined with Marpod_B2bPricing/Marpod_B2bAdvancedPricing, but does not require either — catalog visibility and price are independent decisions in this design.

Installation

Run from the Magento project root:

composer require mar-pod-b2b/module-b2b-shared-catalog:^1.2
bin/magento module:enable Marpod_B2bSharedCatalog
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento cache:clean
bin/magento indexer:reindex marpod_b2b_shared_catalog_product

Development

The planned scope, dependency rules, cache boundaries, security requirements, and test strategy are documented in packages/B2B_LIGHT_PLAN.md in the development Magento project (section 9.2).

Unit tests:

vendor/bin/phpunit -c dev/tests/unit/phpunit.xml.dist packages/module-b2b-shared-catalog/Test/Unit

REST/GraphQL API tests (real HTTP against a running instance — routing, authentication, ACL enforcement, and cross-company/website isolation; see mar-pod-b2b/module-b2b-core's README for the shared Test/Api base classes these build on):

vendor/bin/phpunit -c dev/tests/api-functional/phpunit_rest.xml \
    packages/module-b2b-shared-catalog/Test/Api/Rest/SharedCatalogRestTest.php

vendor/bin/phpunit -c dev/tests/api-functional/phpunit_graphql.xml \
    packages/module-b2b-shared-catalog/Test/Api/GraphQl/SharedCatalogGraphQlTest.php

Admin, REST, and GraphQL smoke test:

cd packages/module-b2b-shared-catalog/Test/Playwright
npm install
MAGENTO_BASE_URL=http://localhost:8090 \
MAGENTO_ADMIN_USER=playwright_test \
MAGENTO_ADMIN_PASSWORD='your-local-test-password' \
npm test

Limitations

  • catalog search (OpenSearch) and the XML sitemap are not filtered by catalog assignment in this iteration — a product hidden from a company's category listing can still surface through full-text search or the sitemap. Treat this as a known gap if search-result leakage matters for your deployment;
  • assignment is company-level only; per-hierarchy-unit assignment is not implemented.

Uninstallation

Do not remove the package while another installed module requires it. The marpod_b2b_shared_catalog_* tables contain business data and are retained when the module is disabled or its package is removed. Remove the marpod_b2b_shared_catalog_product indexer schedule/state if disabling permanently.