Skip to content
advanced Phase 92 · Enterprise Features

Shared Catalogs

Shared catalogs - custom pricing per company, catalog sharing

45m
0 problems
Topic Progress 0%

Shared Catalog Architecture

Catalog Types

  ┌─────────────────┐
  │  Public Catalog │  Default for all
  └────────┬────────┘
           │
  ┌────────▼────────┐
  │ Shared Catalog  │  Company-specific
  │  (Custom)       │  pricing & products
  └────────┬────────┘
           │
  ┌────────▼────────┐
  │ Company Assigned│  Linked to companies
  └─────────────────┘

Shared Catalog Repository

namespace Magento\SharedCatalog\Api;

interface SharedCatalogRepositoryInterface
{
    public function get(int $catalogId): SharedCatalogInterface;
    public function getList(SearchCriteriaInterface $searchCriteria): SharedCatalogSearchResultsInterface;
    public function save(SharedCatalogInterface $catalog): SharedCatalogInterface;
    public function delete(SharedCatalogInterface $catalog): bool;
}

Shared Catalog Interface

namespace Magento\SharedCatalog\Api\Data;

interface SharedCatalogInterface
{
    public function getId(): ?int;
    public function getName(): string;
    public function getType(): string;
    public function getCreatedById(): int;
    public function getCreatedAt(): string;
    public function getDescription(): ?string;
    public function getStructureId(): int;
    public function getPricingId(): int;
    public function getCompaniesCount(): int;
}

Custom Pricing

Pricing Manager

namespace Vendor\B2B\Catalog\Pricing;

class SharedCatalogPricingManager
{
    private PricingReaderInterface $pricingReader;
    private PricingWriterInterface $pricingWriter;

    public function setProductPrice(
        int $catalogId,
        int $productId,
        float $price,
        float $discount = 0
    ): void {
        $pricingData = new PricingData([
            'catalog_id' => $catalogId,
            'product_id' => $productId,
            'price' => $price,
            'discount' => $discount,
            'final_price' => $price - $discount,
        ]);

        $this->pricingWriter->save($pricingData);
    }

    public function getProductPrice(
        int $catalogId,
        int $productId
    ): ?PricingData {
        return $this->pricingReader->getByCatalogAndProduct(
            $catalogId,
            $productId
        );
    }

    public function getCatalogPrices(int $catalogId): array
    {
        return $this->pricingReader->getAllByCatalog($catalogId);
    }
}

Price Tier Configuration

namespace Vendor\B2B\Catalog\Pricing\Tier;

class PriceTierManager
{
    public function setTiers(
        int $catalogId,
        int $productId,
        array $tiers
    ): void {
        foreach ($tiers as $tier) {
            $tierData = new PriceTierData([
                'catalog_id' => $catalogId,
                'product_id' => $productId,
                'qty_from' => $tier['qty_from'],
                'qty_to' => $tier['qty_to'],
                'price' => $tier['price'],
                'discount' => $tier['discount'] ?? 0,
            ]);

            $this->tierRepo->save($tierData);
        }
    }

    public function getTiers(
        int $catalogId,
        int $productId
    ): array {
        return $this->tierRepo->getByCatalogAndProduct(
            $catalogId,
            $productId
        );
    }
}

Catalog Assignment

Company-Catalog Assignment

namespace Vendor\B2B\Catalog\Assignment;

class CatalogAssignment
{
    private CompanyRepositoryInterface $companyRepo;

    public function assignCatalog(
        int $companyId,
        int $catalogId
    ): void {
        $company = $this->companyRepo->get($companyId);
        $company->setSharedCatalogId($catalogId);
        $this->companyRepo->save($company);
    }

    public function unassignCatalog(int $companyId): void
    {
        $company = $this->companyRepo->get($companyId);
        $company->setSharedCatalogId(null);
        $this->companyRepo->save($company);
    }

    public function getCatalogCompanies(int $catalogId): array
    {
        return $this->companyRepo->getList(
            $this->createSearchCriteria($catalogId)
        )->getItems();
    }
}

Catalog Permission Check

namespace Vendor\B2B\Catalog\Permission;

class CatalogPermissionChecker
{
    public function canAccess(
        int $customerId,
        int $productId
    ): bool {
        $customer = $this->customerRepo->getById($customerId);
        $companyId = $customer->getCompanyId();

        if (!$companyId) {
            return false;
        }

        $company = $this->companyRepo->get($companyId);
        $catalogId = $company->getSharedCatalogId();

        if (!$catalogId) {
            return false;
        }

        return $this->catalogProductRepo->exists($catalogId, $productId);
    }
}

Catalog Synchronization

Catalog Sync Service

namespace Vendor\B2B\Catalog\Sync;

class CatalogSyncService
{
    private SharedCatalogRepositoryInterface $catalogRepo;
    private ProductRepositoryInterface $productRepo;

    public function syncFromDefault(int $catalogId): SyncResult
    {
        $catalog = $this->catalogRepo->get($catalogId);
        $result = new SyncResult();

        // Get default catalog products
        $defaultProducts = $this->getDefaultProducts();

        foreach ($defaultProducts as $product) {
            $exists = $this->catalogProductRepo->exists(
                $catalogId,
                $product->getId()
            );

            if (!$exists) {
                $this->catalogProductRepo->addProduct(
                    $catalogId,
                    $product->getId()
                );
                $result->addAdded($product->getSku());
            }
        }

        // Remove products not in default
        $catalogProducts = $this->catalogProductRepo->getByCatalog($catalogId);
        foreach ($catalogProducts as $catalogProduct) {
            if (!$this->inDefault($catalogProduct->getProductId())) {
                $this->catalogProductRepo->removeProduct(
                    $catalogId,
                    $catalogProduct->getProductId()
                );
                $result->addRemoved($catalogProduct->getSku());
            }
        }

        return $result;
    }
}

Price Sync

namespace Vendor\B2B\Catalog\Sync;

class PriceSyncService
{
    public function syncPrices(
        int $catalogId,
        string $source
    ): void {
        $prices = $this->priceSource->fetch($source, $catalogId);

        foreach ($prices as $sku => $price) {
            $product = $this->productRepo->get($sku);
            $this->pricingManager->setProductPrice(
                $catalogId,
                $product->getId(),
                $price
            );
        }
    }
}

Quiz

1. What is a shared catalog?

Question 1 options

2. How is pricing managed in shared catalogs?

Question 2 options

3. What happens when a product is removed from the default catalog?

Question 3 options

Flashcards

Question

What is a shared catalog?

Answer

Company-specific catalog with custom pricing

Question

How does pricing work?

Answer

Custom price per product per shared catalog

Question

What is catalog assignment?

Answer

Linking a shared catalog to a company

Question

What is catalog sync?

Answer

Updating shared catalog from default catalog

Revision Notes

Key Takeaways

  • 1. Shared catalogs provide company-specific product selections
  • 2. Custom pricing can be set per product per catalog
  • 3. Companies are assigned to shared catalogs
  • 4. Catalog sync keeps shared catalogs updated
  • 5. Permissions control product visibility

Interview Tips

  • Explain shared catalog vs default catalog
  • Discuss custom pricing implementation
  • Describe catalog assignment workflow
  • Talk about catalog synchronization

Cheat Sheet

Shared Catalog:
  Custom products + pricing
  Assigned to companies
  Synced from default catalog

Pricing:
  Price per product per catalog
  Tier pricing supported
  Discounts configurable

Assignment:
  Company → Shared Catalog
  Controls product visibility