How to mass update the stock quantity of a batch of products in PrestaShop 1.7.6? - prestashop

I work in the integration of an ERP (Random) and PrestaShop, one of the points considered by the integration is the stock level of the products. When there are movements in the stock of the products in the ERP originating outside of PrestaShop (for example, transfers between warehouses, purchases, external sales, etc.), these stock variations must be synchronized with the physical stock (physical_stock) of PrestaShop, because the reserved stock (stock_reserved) exists only in the PrestaShop context and is related to the reserved products in orders that have not yet been dispatched, while the available stock (stock_available) does not consider the reserved stock by design, then if the Stock that comes from the ERP is assigned to the available stock, the stock reserved until now would double. On the other hand, the physical stock considers both the available stock and the reserved stock, then the stock that comes from the ERP is assigned to the physical stock, the reserved stock is maintained and the available stock will vary depending on the following relation:
stock_available.quantity = stock_available.physical_quantity - stock_available.reserved_quantity
This is currently working correctly in production, however, what I am looking for is to design these operations in the best way through a PrestaShop module, which through a FrontController receives an ajax request where one of the request parameters (Request->_ POST['stock_quantity_changes']) is an input in array format, for example:
[
$id_stock_avaiblable_1 => $new_quantity_1,
$id_stock_avaiblable_2 => $new_quantity_2,
...
]
with which I would like to update the set of stocks that it contains in a single operation. So far, I found method src/PrestaShopBundle/Entity/Repository/StockRepository.php->bulkUpdateStock (https://github.com/PrestaShop/PrestaShop/blob/100c5c028b05c579f5788a036041e45cef510e1d/src/PrestaShopBundle/Entity/Repository/StockRepository.php#L102), that would allow me to do what I need, however I have not figured out how to create a proper instance of this class (StockRepository) yet. The StockRepository-> bulkUpdateStock method receives a set of stock movements (MovementsCollection) and with it, updates a set of available stocks, both in individual products and in pack's if necessary, in addition, records the stock movements (StockMvt's), executes the actionUpdateQuantity hook for each modified stock and removes the value of each modified stock from the cache, all this can be checked in /src/Core/Stock/StockManager.php->updateQuantity (https://github.com/PrestaShop/PrestaShop/blob/100c5c028b05c579f5788a036041e45cef510e1d/src/Core/Stock/StockManager.php#L153). Finally the method bulkUpdateStock synchronize the level of physical stock with the available stock + reserved stock. I am interested in using all this logic when updating a set of stock to adapt it to PrestaShop's operation, since currently only updating the values ​​of the stock_available table I am not registering the StockMvt's, cleaning the cache or executing the actionUpdateQuantity hook.
In summary, I found the StockRepository class that contains the bulkUpdateStock method that would allow me to correctly update the levels of a set of stocks in a single operation, however, to instantiate this class requires a set of parameters, which can be verified in https://github.com/PrestaShop/PrestaShop/blob/100c5c028b05c579f5788a036041e45cef510e1d/src/PrestaShopBundle/Entity/Repository/StockRepository.php#L72, and so far I have not found any instantiation examples for this class in the source code, I have only found code that uses this class already instantiated, as you can check in src/PrestaShopBundle/Controller/Api/StockController.php (https://github.com/PrestaShop/PrestaShop/blob/100c5c028b05c579f5788a036041e45cef510e1d/src/PrestaShopBundle/Controller/Api/StockController.php#L126). So the question finally is, how can I properly instantiate the StockRepository class ?, or is there any alternative to do what I need ?, regards :)

Related

Adding new product with category tree - specific price problems

I installed an add-on for bulk action (called ba_importer v 1.1.24), I upload an Excel file with my data and create a group of products.
I can set the categories' tree or manually add ID of main categories and associated. I tried with no luck to use the tree features (like Home/Products/etc) and so I use all the ID of main category and all the associated. The result is a product with the correct categories set, but with no specific price from the customer group linked to a category.
I tried to edit a single product, remove all categories and set it one by one (set one, save, set one, save etc.) and then the specific price from the group linked to a category appears to the product.
Is there a better solution? I'm thinking about make a personal PHP page that reads an Excel file and sets all the information about the product, but I'm scared to face the same problem with the specific price. 
There is no such thing as "category-related specific price",
if you have specific prices tied to customer groups , these are created as a result of the add/update product action with ps_specific_price DB entries having id_group with your restricted ID.
It is likely that the bulk module acts directly with DB queries to speed up things and bypasses this operation, I've seen this behaviour with those kind of modules in the past.
Since you are talking of a paid add-on, I would definitely seek help from the developer.

DDD - Entity vs ValueObject

I was reading about DDD and I realize that sometimes an entity might be a VO or VO might be an entity. You can know which one is better depends on the context. I was checking different examples. For example, shopping cart DDD example. Product is an aggregate root, Cart is an aggregate root and items is a entity of Cart, so if you want to add a product to the cart you would do something like this:
$cart->addProduct(id $id, $name, $price)
class Cart
{
private items;
function addProduct(ProductId $id, ProductName $name, ProductPrice $price) {
this->items[] = new Item(
new ItemProductId($id->ToString()),
new ItemName($name->ToString()),
new ItemPrice($price->ToString()),
new ItemCartId(this->id->ToString())
);
}
}
There are two reasons why I think it is a VO:
You cannot modify the value's item ( only if the product's
price has been modify there is a event that would modify its price).
The item doesn't have id, it's has a reference of the
product(ItemProductId) and a reference of the cart (ItemCartId)
I was reading about DDD and I realize that sometimes an entity might be a VO or VO might be an entity. You can know which one is better depends on the context.
Usually its pretty clear whats entity and whats an value object. If it contains data that's fixed at the time of assignation, its a value object. For example "order address" on the order aggregate. When the order is placed, the address is set. "Addresses" may be an entity in user aggregate (i.e. a list of his common addresses), but for an order its an value object since its not supposed to change when the user edits or deletes one of his addresses.
cart->addProduct(id $id, $name, $price)
class Cart
{
private items;
function addProduct(ProductId $id, ProductName $name, ProductPrice $price) {
this->items[] = new Item(
new ItemProductId($id->ToString()),
new ItemName($name->ToString()),
new ItemPrice($price->ToString()),
new ItemCartId(this->id->ToString())
);
}
}
That's a pretty bad example. Why would or should the value object be ItemPrice? Does that makes it any special? Why string? A price is usually just a numeric value but also involves a currency, passing it as string kinda beats that.
On top of that, having ItemCartId in the it does
a) leak data persistence knowledge into your domain. The fact, it's contained inside this->items[] already establishes a relationship between the entity (or aggregate) and the value object. ItemCartId as no meaning in the domain, other than that it's required for relational database engines (=persistence knowledge)
There are two reasons why I think it is a VO:
You cannot modify the value's item ( only if the product's price has been modify there is a event that would modify its price).
You sure? Why would a eCommerce business want to have the prices in the card anyways?
Prices are informational only, they could change before the order is placed. Same as availability.
A lot of users put stuff in their cart and check on next day. In that time, the price could change.
No company would want to sell a product for the price when it was put into the shopping cart, if the price increased in the time since it was put in there. That would mean a financial loss.
Prices in the shopping carts are informational, not compulsory. You need know the exact process of the company.
The item doesn't have id, it's has a reference of the product(ItemProductId) and a reference of the cart (ItemCartId)
Again. Why do you think ItemCartId belongs to the Item object? That's leaked persistence knowledge, since its only important for relational database systems.
All you really need in a shopping cart is
* product or article number (not necessary the id, that's typically db knowledge)
* quantity
Nothing else. If you may want to change the user when the price changed and show the old and new price, the take the price (=currency value object, not ItemPrice) to it too as a value to compare to an old state.
Finally and probably most importantly: Consider if the shopping cart is an aggregate at all (or does fit into ddd).
After all, most shopping carts are only a value bag w/o a lot of business logic into it. The real logic (checking the real price, product availability, asking for shipping location, calculation of taxes and shipping costs) happens during the checkout process, not while putting stuff into the cart.
For example you can check out eShops on Containers demo project showing an example shopping service based on microservices and ddd.
Some microservices apply DDD (such as Ordering microservice), where others don't (Catalog microservice or the Basket (cart) Microservice).
Applying DDD doesn't mean everything needs to be done with DDD. If its simple crud based services, then you don't need DDD for these. DDD adds a value where you have complex systems and complex business logic.
A catalog has neither, it just presents data which come from a different system (i.e. ERP which on other side may be built on using DDD).
I don't understand what are you asking exactly, but the code you are providing could be improved.
First of all I suggest you to read the red book by Vaughn Vernon https://www.amazon.co.uk/Implementing-Domain-Driven-Design-Vaughn-Vernon/dp/0321834577: you can find 3 chapters describing how to define entities, value objects and aggregates, with some rules of thumbs.
One of those advices, is to keep your aggregates as small as possible, in order to improve your performance and keep the code easy to read and maintain. Imagine that you have a Blog aggregate that contains a list of Post entities: if you manage all of them in a single aggregate, when you want to modify the blog Author, for example, you are forced to retrieve all of the blog's post, without any reason, and that means that you are doing a join and slowing down your application. The more your aggregates grows, the slower those queries with their joins.
So, in the case of the Cart, I suggest you to build the cart without any item or product, instead you can add the CartId to the Item. Cart does not know which items it contains, but items know in which cart they are.
About value objects: is a tool that allows you to wrap some validation and business logic inside a class that is represented by its state and not by its id (like entities), so in the case of the cart, if you put two identical bottles of water inside it, how can you know that they are different? Do you need to know that they are different? Are they different if they are physically (or logically different) or are they different if some of their attribute is different?
In my opinion an item or a product, in your case, are entities because they are not measuring anything, and when you put an item twice, you actually have two different items (and you use an id to recognize them).
This is not necessary like this, sometime you can use a value object and sometimes an entity, it depends on your context. A good example to understand that difference is with money:
if you want to measure an amount, for example 10 dollars, probably a value object will work for you, because you don't care if it a bill or another, you just want to measure 10 dollars; in this case if you have 10 dollars, is not important if you have a bill or another, the important thing is that is 10 and not 5
in the case that you need to recognize different physical bills, for any reason (you need to track money for the police), you should use an entity, because any printed bill has a unique serial number, and a 10 dollar bill, in this context, is actually different from another 10 dollar bill
Hope this can help you.
Goodbye!

Openerp MRP module: assigning employees to work orders

In the MRP module, I would like to assign different employees to the work orders of a manufacturing order, so I can tarck the amount of hours and the cost for every employee (beause they will have different service products with different costs) and create analytic journal items based on this.
My question is: Is there any option or extra module for this or should I customize the MRP module?
Thanks in advance.
Regards
I see this question is from some time ago but I would like to know if you found and answer?
This is a long winded reply, but I am also needing this capability and searching any such existing module or planning develop this capability
Currently and soon to be completed is a new module with many enhancements to manufacturing order>>work order lines these include.
The ability to link a BOM component/consumed products to a routing work line on the BoM Component lines.
A constraint where by MFG Work Orders can only start when the component/consumed products assigned to them are available. This gives ability to start individual work orders as there individual consumed component products become available and to stage multiple works orders from many manufacturing orders base on which products have been picked and transfer to production.
The ability to define a constraint that previous work orders in sequence must complete before a work order can start.
New statuses on work order that waiting for product, waiting for previous work and ready.
The ability to assign warehouse locations to routing work center lines and to generate Internal Pickings not just to a specific Manufacturing orders but also to Work center work orders so that pickings can be schedule to all the current jobs needing consumable products.
What I am also planning in phase 2 of this development are feature similar to your question
allowing to define group of employees link to Routing work center lines. many2many from routing work center to employees
adding to search view on the Work Orders List View for search and group by for assigned employee or employee group.
Add ability to assign an employee to a work order
If logged in as other than the assigned employee Attempts to set work order to In Progress system will warn that they are not the assign employee for this work order. constraint can be overridden if user has manger permission he has choice to reassign work to himself or start work for the assigned employee.
Adding linkage to hr_timesheet so that time when work order is in progress is entered on employees time sheet.
Have logic that confirms employee is signed in on attendance or will automatically sign them in when a work order assigned to them is set to In Progress.
To have work order status set to paused automatically when assigned employees signs out in time sheet attendance.
to log time work was in progress on their Time sheet when work is set to pause or Finished
Regards
SL

Calculate available inventory in OpenERP

I am developing a custom module for OpenERP 7 that will track hardware installed in various venues. I have the total stock levels recorded in the Warehouse module, but I want to be able to calculate and display amount of each product that is available and the amount that is currently deployed. I'm having trouble figuring out how to do this. I have been looking at this rent module and they seem to do something with stock picking and workflows, but I'm new to OpenERP and not really sure how that works.
The other way I was thinking of was to loop through the deployments and simply calculate the amount of each item, and use functional fields to display it, but I'm not sure if that would even work, or how to do it without hard-coding all the various items.
Have a look at product.py in the stock module, specifically the get_product_available method. This allows you to pack various filter parameters into the context and then it calculates and returns stock as the net of inbound and outbound stock moves.
This method also gets used in the functional fields qty_available, virtual_available, incoming_qty and outgoing_qty. There is reasonably good explanations in the help comments in the module.
In OpenERP, something is in your stock when there's a stock move (object stock.move) with that product to your physical location as destination location, defined on Warehouse object for "Inventory Location" field. Let's say you have recorded 2 moves:
Move 1
Source Location: Supplier
Destination Location: Stock
Qty: 2
Move 2
Source Location: Stock
Destination Location: Deployed Products
Qty: 1
If you open your products list you'll see that you have 1qty of your product available. OpenERP sums all the moves for that product to and from your Stock location. So if you have no other specific needs, recording moves to some sort "Deployed Products" location should be enough.

Prestashop: use BlockLayered class methods and/or DB tables for price range button?

I've got to build a standalone menu button with submenu that contains links to price ranges.
I activated the blocklayered module (not for this task, only for regular left-column filters). So the relative db tables are in place and populated.
I want to make a controller specific for price ranges. So I've got to do the right query and maybe set up the same url vars as the blocklayered module so they wil not conflict.
Would it be too crazy to import blocklayered or blocklayered-ajax in my controller and use part of their functionality? Maybe not good because of object duplication or other issues?
Or maybe, would it be a bad idea to use the blocklayered tables (for example layered_price_index) to help me get filtered products? I'm wandering if it would be a better solution than re-doing all by myself, or if instead it's not good for some reason.
Any idea?
It really depends on which amount (among the ones below) you would like to take into account in your price range filter:
Amount without taxes
Amount including taxes
Amount including discount/promotion
Amount in several currencies or only one currency
Amount for a specific customer group or for everyone
Amount base on any other product price rule
The easy way:
You can build a price range controller easily by yourself, handling only a single currency and prices without taxes and reduction. It will probably be 90% accurate (because of the missing discounts a product might not show up for a certain range).
In that case, you can easily build a query on the ps_product and ps_specific_price tables and SELECT in real-time the right products for a given range.
The proper way:
You want to handle discounts, price rules, specific prices, etc. If you build a real-time query including all these calculations and parameters, it may slow down the server.
Build a product price cache or re-use the one setup by the Block Layered module.