Hi everyone,
I don’t even know how to correctly state my issue in one scentence (topic), but I’ll try:
I need to make a query that takes a sum of an associated model as a variable for the query.
First, the situation (of course: simplyfied):
I have a PRODUCTS table
with field ‘id’ and ‘name’
I have a PRODUCT_STOCKS table (joined with PRODUCTS through ‘product_id’)
with fields ‘free_stock’ and ‘minimum_stock’
The ‘free_stock’ are the number of items I actually have in stock right now. The ‘minimum_stock’ is the number of items I want to have in stock as a minimum to have enough items to sell that day
I have a ORDER_ITEMS table (joined with PRODUCTS through ‘product_id’)
with fields ‘qty_in_backorder’ and ‘status_id’
(status_id can be 1=ordered and 2=cancelled)
At the start of the day, I want to know my stockvalues, so I do this query:
<?php
$query = $this->Products
->find('all')
->contain(['ProductStocks']);
?>
The result could be:
id | name | free_stock | minimum_stock |
---|---|---|---|
1 | ItemA | 5 | 5 |
2 | ItemB | 1 | 1 |
3 | ItemC | 2 | 2 |
3 | ItemD | 7 | 3 |
That day, I only sell 3 ItemA, and nothing more.
At the end of the day, I want to know what to re-order at my suppliers.
So I do the the following query on my Products:
<?php
$query = $this->Products
->find('all')
->contain(['ProductStocks'])
->where('ProductStocks.stock_free < ProductStocks.stock_minimum');
?>
And I get:
id | name | free_stock | minimum_stock | to_be_ordered (calculated field) |
---|---|---|---|---|
1 | ItemA | 2 | 5 | 3 |
So, I now know to order ItemA three times. So far so good. I will now start ordering these products.
My supplier-A can sell me just 1 ItemA.
Supplier-B (who is more expensive) can also supply 1 of ItemA (and there are no other suppliers).
So, I order accordingly.
My OrderItems table (which was empty before) now has these rows:
id | supplier | product_id | status_id | qty_in_backorder (items ordered but not yet received) |
---|---|---|---|---|
1 | supplier-A | 1 | 1 (ordered) | 1 |
1 | supplier-B | 1 | 1 (ordered) | 1 |
So: I now have ordered ItemA 2 times. At 2 different suppliers, both having status_id 1 (ordered)
Let’s say, the next day I do not sell anything. And at the end of the day, I want to make the same ‘what to re-order’ query.
But I now already have ordered ItemA 2 times.
So I would like to know how many I have to re-order. In this case that would be: 1
Because: I want 5 (minimum stock), I have 2 in stock. I already ordered 2 (so: 4 in total), so, I now only need 1 to meet my minimum_stock.
What I would like the outcome to be, is:
id | name | free_stock | minimum_stock | already ordered (in backorder) | to_be_ordered (calculated field) |
---|---|---|---|---|---|
1 | ItemA | 2 | 5 | 2 | 1 |
So, written out in plain text, that would be something like:
1: Make a query on the Products table and find all items that have a free_stock < minimum_stock.
2: for each item that meets those criteria: Store the difference between free_stock and minimum_stock in a variable ‘to_be_ordered’
3: Then, for each item in step 1: check in OrderItems table if there are any items on there with that product_id AND with status=1. And SUM all ‘qty_in_backorder’ to find out how many have already been ordered (and store that SUM in variable ‘sum_allready_ordered’).
4: Now, if (minimum_stock > (‘sum_allready_ordered’'+‘free_stock’)) THEN show that product, and suggest the number 1 to be ordered (not 3). But if not, don’t show product at all (because: I already ordered the number of items that I want. I just did not yet receive them).
Before you ask: What kind of query do you have now… To be honest: nothing. I simply don’t know how to build such a query. I don’t know to use matching, notMatching, having, etc.
My best guess would be something like:
<?php
$query = $this->Products
->find('all')
->contain([
'ProductStocks',
'OrderItems' => function ($q) {
return $q
->select([
'OrderItems.id',
'OrderItems.product_id',
'total_backorder' => 'SUM(OrderItems.qty_in_backorder)'
])
->where(['OrderItems.status_id' => 1]);
}
])
->where(['ProductStocks.stock_minimum > ' => ('total_backorder + ProductStocks.stock_free')]);
Hopefuly someone has the time and patience to help me out. Thanks for your attention!
P.S I am using CakePHP 3.8.*