- π«π·France cassien
I'm interested.
I need to offer subscription products with multiple recurrence periods. If the product is released for the day, it must also be released for the week and the months since it is temporarily unavailable. - π¦πΉAustria mvonfrie
I'm interested as well.
I have a voucher product with the value chosen by the user. To make it easier for both the users and companies providing the vouchers, there will be a product X with variations like 10β¬, 20β¬ and 50β¬. There is no separate stock for the different variations but only a total value per product.Example: Stock for product X is 180β¬, then this can be:
- 18 x 10β¬
- 9 x 20β¬
- 3 x 50β¬ + 3 x 10β¬
- 3 x 50β¬ + 10β¬ + 20β¬
- ... any other possible combinations
- π¦πΉAustria mvonfrie
I installed
commerce_stock
as the dev version is D10 compatible now and looked a bit into the code to understand how things work and how to quirk a solution for my example into my site. As I have a deadline for the project I can't wait until this feature is implemented but have to find a custom solution in the meantime.But I have an idea for a concept how to implement this properly. This can't be fully implemented in
commerce_stock
though as it would require changes incommerce
/commerce_product
which then are permanent and would make things even more complicated. So the concept will always require custom code by the site developer.Currently all stock logic is connected to the
PurchasableEntityInterface
which basically (only) is the product variation entity (but can be extended by contrib modules to nodes for example). But of course we don't want (and don't need) to make the product entity purchasable in order to let it handle the stock of it's variations.So we need two new interfaces plus traits providing their implementations for commerce products:
/** * Defines the interface for stockable entities. * * The entity type implementing this interface should always be implementing \Drupal\commerce\PurchasableEntityInterface * as well. An implementation for commerce product variations is provided by StockableProductVariationTrait. */ interface StockableEntityInterface extends \Drupal\Core\Entity\ContentEntityInterface { /* * Returns the entity handling the stock level for this entity. * * @return StockedEntityInterface|null */ public function getStockedEntity(): ?StockedEntityInterface; } /** * The entity type handling the stock level for a purchasable entity, for example the commerce product for its product variations. * * An implementation for commerce products is provided by StockedProductTrait. */ interface StockedEntityInterface extends \Drupal\Core\Entity\ContentEntityInterface { // Everything we need here for stock handling... } /** * Implementation of StockableEntityInterface for commerce products. */ trait StockableProductVariationTrait { /** * {@inheritdoc} */ public function getStockedEntity(): ?StockedEntityInterface { $stocked_entity = $this->getProduct(); return $stocked_entity instanceof StockedEntityInterface ? $stocked_entity : NULL; } } /** * Implementation of StockedEntityInterface for commerce products. */ trait StockedProductTrait { // Everything we need here for stock handling... }
Then stock checking and stock processing has to check: The given entity or purchased entity of the given order item
- implements
PurchasableEntityInterface
but notStockableEntityInterface
--> use it for stock handling - implements both interfaces --> use
StockableEntityInterface::getStockedEntity()
- the return value implements
StockedEntityInterface
--> use that entity for stock handling - the return value is NULL --> fall back to the parent entity implementing
PurchasableEntityInterface
- the return value implements
- implements
StockableEntityInterface
but notPurchasableEntityInterface
- the return value implements
StockedEntityInterface
--> use that entity for stock handling - the return value is
NULL
--> don't handle stock for it.
- the return value implements
Of course this requires changes to all sub-modules of
commerce_stock
and is quite complex. But the same time it is very flexible as it allows to decide whether the product variation or product should handle the stock (or maybe a totally different entity implementingStockedEntityInterface
and being return byStockableEntityInterface::getStockedEntity()
) on a per-bundle basis.The site developer would just need to create custom product and product variation classes implementing the interfaces and registering them properly. This can be done using hooks or more easier with the Bundle Class Annotations β module.
/** * Custom product variation implementation using delegating its stock handling. * * @Bundle( * entity_type = "commerce_product_variation", * bundle = "my_product_variation_bundle", * label = @Translation("Stock delegating product variation"), * ) class StockableProductVariation extends \Drupal\commerce_product\Entity\ProductVariation implements \Drupal\commerce_stock\Entity\StockableEntityInterface { use \Drupal\commerce_stock\Entity\StockableProductVariationTrait; } /** * Custom product implementation handling stock for its variations. * * @Bundle( * entity_type = "commerce_product", * bundle = "my_product_bundle", * label = @Translation("Stock handling product"), * ) class StockableProductVariation extends \Drupal\commerce_product\Entity\Product implements \Drupal\commerce_stock\Entity\StockedEntityInterface { use \Drupal\commerce_stock\Entity\StockedProductTrait; }
It would even be possible to mix this for a product type, for example a book product type with three different variation types
book
,ebook
(like ePub, PDF, ...) andamazon_kindle_book
.book
andebook
variations could handle their stock on product level by implementingStockableEntityInterface
(i. e. using local stock) whileamazon_kindle_book
handles its stock on the variation by using a custom amazon kindle stock implementation. - implements
- π§πͺBelgium matthieu_collet
Hello @mvonfrie
Two months later do you think your solution is working ? We have the same need - π©πͺGermany a.dmitriiev
I am trying now to implement this without too much changes. I ended up creating new Stock Service that will return stock of the product whenever the stock of its product variation is requested.
I still had to override couple of classes and one of them needs the patch that is attached. I will write more when I finish.
- π©πͺGermany a.dmitriiev
More places where the changes are needed in a new patch
- π©πͺGermany a.dmitriiev
I assume that product stock is using commerce_stock_local module. Here is the module for tracking stock for product and not product variation based on local stock.
What module has:
1. Field storage configs for field_stock_level and commerce_stock_always_in_stock for product entity type.
2. New service to set for product variation here/admin/commerce/config/stock/settings
called "Product local stock". It should still be attached to product variation, because of the module architecture, and I didn't want to change it.
3. New widget "Simple stock transaction for products" that you should use for field "Stock Level" for product entity type.
4. Overrides for queue worker class and stock level field type (to use new class for computed stock level processor.After you install the module, go to product type that you want to have stock level management. Add 2 fields "Stock Level" and "Always in stock?" from existing fields (the storages are installed with the module). Set widget "Simple stock transaction for products" that you should use for field "Stock Level" for product entity type. Then you need to set here
/admin/commerce/config/stock/settings
the service called "Product local stock" for your product variation that corresponds to product type.On product edit form you will now see two new fields. And that is basically it. Stock level will change whenever any variation that belongs to product will be bought, but level will be attached to the product and not to variation.
When checking the availability of the product variation, then the stock level for product will be checked as well.
P.S. Don't forget to apply the patch from #16 to commerce_stock module. Without it the module commerce_stock_product from the comment will not work properly.
- πΊπΈUnited States rsnyd
@a.dmitriiev,
Thank you for the patch and module. I'm working on this same challenge. I've updated commerce_stock with the patch from #16, downloaded, unzipped and installed your commerce_stock_product from #17. I've added the two reusable fields to my default product bundle and set the field widget to "Simple stock transaction for products". Finally, I've configured commerce_stock here: /admin/commerce/config/stock/settings to use the "Product local stock" service for both the default service and the Product Variation.The fields show on my product edit form, but I'm unable to change the value of the stock level. No errors, but if I enter 5 into the field and save, Current stock level: remains at 0. I've also tried adding a stock level field to the product variation type for the default product bundle, but that doesn't seem to work either. Can you please suggest what I may be doing wrong?
- πͺπΈSpain uridrupal
@rsnyd
I couldn't make it work, but you're using the wrong Field Widget. You need to use the proper one, I think it's called "Product stock level". Also, the stock is set at variation if I recall correctly, and then it will show properly. - π©πͺGermany a.dmitriiev
For product type that should have the stock per product you should have these fields:
Manage form display page has these 2 fields with corresponding widgets:
On Stock configuration page the settings are:
See setting for product variation "Side event".
As stock management is local, you need also to create location here `/admin/commerce/commerce_stock_location` of any type from here `/admin/commerce/config/commerce_stock_location_type`
No settings on product variation type are needed.
Then you can manage stock on product page (not product variation):
And when you fill the field "Stock level adjustment (all languages)" with 10, to increase the stock on 10 items, and save the product, it will be displayed like this afterwards:
- πΊπΈUnited States rsnyd
@a.dmitriiev/@UriDrupal,
I've followed the screen captures below, installed the fields on the product type, set the configuration for my product variation type, and I've ensured the patch was installed. The field shows on the product edit form, but will not save the value entered. After debugging, I found this error:
Error message Warning: Undefined variable $multiplier1 in Drupal\commerce_stock_product\ProductLocalStockUpdater->createTransaction() (line 69 of modules/custom/commerce_stock_product/src/ProductLocalStockUpdater.php). Drupal\commerce_stock_product\ProductLocalStockUpdater->createTransaction(Object, '1', '', 2, 0, NULL, 1, Array) (Line: 125) Drupal\commerce_stock\StockServiceManager->createTransaction(Object, '1', '', 2, 0, NULL, 1, Array) (Line: 182) Drupal\commerce_stock_field\Plugin\Field\FieldType\StockLevel->createTransaction(Object, Array) (Line: 42) Drupal\commerce_stock_product\Plugin\Field\FieldType\StockLevel->postSave(1) call_user_func_array(Array, Array) (Line: 233) Drupal\Core\Field\FieldItemList->delegateMethod('postSave', 1) (Line: 198) Drupal\Core\Field\FieldItemList->postSave(1) call_user_func_array(Array, Array) (Line: 938) Drupal\Core\Entity\ContentEntityStorageBase->invokeFieldMethod('postSave', Object, 1) (Line: 984) Drupal\Core\Entity\ContentEntityStorageBase->invokeFieldPostSave(Object, 1) (Line: 896) Drupal\Core\Entity\ContentEntityStorageBase->invokeHook('update', Object) (Line: 56) Drupal\commerce\CommerceContentEntityStorage->invokeHook('update', Object) (Line: 564) Drupal\Core\Entity\EntityStorageBase->doPostSave(Object, 1) (Line: 781) Drupal\Core\Entity\ContentEntityStorageBase->doPostSave(Object, 1) (Line: 489) Drupal\Core\Entity\EntityStorageBase->save(Object) (Line: 806) Drupal\Core\Entity\Sql\SqlContentEntityStorage->save(Object) (Line: 352) Drupal\Core\Entity\EntityBase->save() (Line: 237) Drupal\commerce_product\Form\ProductForm->save(Array, Object)
Removing the $multiplier variable for now allows me to save the value. I will continue testing. @UriDrupal, does this also help you to get it working?
- π©πͺGermany a.dmitriiev
@rsnyd, I think multiplier is a leftover of my custom code, as the module was copied from solution where there is also people count and quantity is multiplied in case it is a ticket for couples, family, etc.
- Status changed to Needs review
3 months ago 8:01am 28 August 2024 - πΈπ°Slovakia kaszarobert
Removing that invalid $multiplier variable fixes the problem and your solution with the attached module from commerce_stock_product.tar_.gz + patch #16 works fine. With needing patch #16 it seems the module is not flexible enough for setting up other entities for stock level management. There are entity_id and entity_type columns in the commerce_stock_transaction database table, so the schema can handle this use case but the module cannot.