Stock Management

All stock management must be done through the relevant services.

Reading Stock Information

Stock quantities for individual products can be queried using pickware.erp.article_detail_stock_info_provider_service, which conforms to the \Shopware\Plugins\ViisonPickwareERP\Components\StockLedger\ArticleDetailStockInfoProvider interface.

$articleDetail = $container->get('models')->getRepository(ArticleDetail::class)->findOneBy([
    'number' => 'SW10107',
]);
$defaultWarehouse = $container->get('models')->getRepository(Warehouse::class)->getDefaultWarehouse();

$stockInfoProvider = $container->get('pickware.erp.article_detail_stock_info_provider_service');
$stockInWarehouse = $stockInfoProvider->getStockInWarehouse($articleDetail, $defaultWarehouse);
$totalPhysicalStock = $stockInfoProvider->getTotalPhysicalStock($articleDetail);
$totalPhysicalStockForSale = $stockInfoProvider->getTotalPhysicalStockForSale($articleDetail);

echo 'Stock for SW10107 in default warehouse: ' . $stockInWarehouse . "\n";
echo 'Total physical stock for SW10107: ' . $totalPhysicalStock . "\n";
echo 'Total physical stock for sale for SW10107: ' . $totalPhysicalStockForSale . "\n";

In addition to the stock quantities for a product, the service can also be used to query whether a product is stock-managed, whether it is initialized and to fetch the product’s latest stock ledger entry.

Performing Stock Initialization for a Newly-Created Product

After creating a product, it needs to be stock-initialized, which entails writing the products initial stock into the default warehouse. This can be achieved using pickware.erp.stock_initialization_service, which conforms to the \Shopware\Plugins\ViisonPickwareERP\Components\StockLedger\StockInitialization interface.

// Create, persist and flush the Article\Detail and its Article first
$articleDetail = ...

// Perform stock initialization for the Article\Detail
$stockInitialization = $container->get('pickware.erp.stock_initialization_service');
$stockInitialization->initializeStocksOfArticleDetails([$articleDetail]);

Please note that the initialization call will throw if the product is already stock-initialized.

Controlling Whether a Product’s Stock Should Be Managed by Shopware ERP

For some products, it might make sense to disable stock management. This includes virtual products for which the concept of stock makes no sense, such as gift vouchers and digital downloads, products such as sets, for which stock is a derived quantity, but also products whose stock is managed outside of Shopware ERP. A typical example of the latter are drop-shipped products, for which the available stock is synchronized into Shopware via its REST API. In this scenario, disabling stock management will prevent unnecessary stock ledger entries from being written during the synchronization process. The stock management status of a product can be changed through pickware.erp.stock_ledger_service (\Shopware\Plugins\ViisonPickwareERP\Components\StockLedger\StockLedgerService).

$stockLedger = $container->get('pickware.erp.stock_ledger_service');

// To disable stock management
$stockLedger->stopRecordingStockChangesForArticleDetail($articleDetail);

// To enable stock management
$stockLedger->startRecordingStockChangesForArticleDetail($articleDetail);

Changing the Physical Stock of a Product

A product’s physical stock can be changed by using pickware.erp.stock_change_list_factory_service (see \Shopware\Plugins\ViisonPickwareERP\Components\StockLedger\StockChangeList\StockChangeListFactory) to create a list of stock changes (see \Shopware\Plugins\ViisonPickwareERP\Components\StockLedger\StockChangeList\AbstractStockChangeList), which can can then be passed into one of the stock recording methods of pickware.erp.stock_ledger_service (see \Shopware\Plugins\ViisonPickwareERP\Components\StockLedger\StockLedgerService).

Since stock for an individual product can reside on multiple bin locations within the same warehouse, removing a certain amount of stock may mean that stock has to be reduced on multiple bin locations, too. So for example, given a product which has 4 pieces on its default bin location A-3, 3 pieces on bin location F-11 and 24 pieces of stock on bin location D-15, removing 10 pieces of stock might cause all stock to be removed from bin locations A-3 and F-11, with the stock on D-15 being reduced by the remaining 3 pieces to 21. Which amount of stock should be removed from each bin location is encoded in the stock change lists which can be created using the StockChangeListFactory. The code for this use case looks like this:

// Fetch the Article\Detail and the Warehouse
$articleDetail = $container->get('models')->getRepository(ArticleDetail::class)->findOneBy([
    'number' => 'SW10107',
]);
$secondWarehouse = $container->get('models')->getRepository(Warehouse::class)->findOneBy([
    'code' => 'L2',
]);

// Create a stock change list for removing 10 pieces of stock of SW10107 from the L2 Warehouse
$stockChangeListFactory = $container->get('pickware.erp.stock_change_list_factory_service');
$stockChanges = $stockChangeListFactory->createStockChangeList($secondWarehouse, $articleDetail, -10);

// Actually perform the stock changes by recording them in the stock ledger
$stockLedgerService = $container->get('pickware.erp.stock_ledger_service');
$stockLedgerService->recordOutgoingStock($articleDetail, $stockChanges, 'Custom PHP integration');

Recording stock changes like this makes sense when the bin locations from which stock was actually removed are unknown. In other cases where the bin location is actually known, it is possible to create a stock change list which reflects this:

// Fetch the Article\Detail and the BinLocation
$articleDetail = $container->get('models')->getRepository(ArticleDetail::class)->findOneBy([
    'number' => 'SW10107',
]);
$secondWarehouse = $container->get('models')->getRepository(Warehouse::class)->findOneBy([
    'code' => 'L2',
]);
$binLocation = $container->get('models')->getRepository(BinLocation::class)->findOneBy([
    'warehouse' => $secondWarehouse,
    'code' => 'A2',
]);
$stockChangeListFactory = $container->get('pickware.erp.stock_change_list_factory_service');
$stockChanges = $stockChangeListFactory->createSingleBinLocationStockChangeList($binLocation, -10);

$stockLedgerService = $container->get('pickware.erp.stock_ledger_service');
$stockLedgerService->recordOutgoingStock($articleDetail, $stockChanges, 'Custom PHP integration');

Note that if there’s not enough stock on the given bin location, the remaining stock will be removed from the null bin location for that warehouse.