Commit eca778aa authored by Jérome Perrin's avatar Jérome Perrin

more doc, with lots of XXX

parent 469832f9
[TOC]
# Introduction # Introduction
We all remember problems we had in school, stated likes: We all remember problems we had in school, stated likes:
...@@ -11,9 +12,9 @@ The 5 base classes of ERP5, also called _Universal Business Model_ are shown in ...@@ -11,9 +12,9 @@ The 5 base classes of ERP5, also called _Universal Business Model_ are shown in
![ERP5's 5 classes](https://www.erp5.com/developer-ERP5.UBM.Picture?quality=75.0&display=small&format=png "ERP5 5 classes") ![ERP5's 5 classes](https://www.erp5.com/developer-ERP5.UBM.Picture?quality=75.0&display=small&format=png "ERP5 5 classes")
Using ERP5 Universal Business Model this simple problem will be modeled using: Using ERP5 Universal Business Model this simple problem will be modeled using:
- resource: The resource are candies - *resource:* The resource are candies
- node: Alice, Bob and the Grandmother are nodes - *node:* Alice, Bob and the Grandmother are nodes
- movements: When Alice gives 2 candies to Bob, there is a movement where Alice is _source_ and Bob is _destination_. The resource of this movement is candy. - *movements:* When Alice gives 2 candies to Bob, there is a movement where Alice is _source_ and Bob is _destination_. The resource of this movement is candy.
In our problem, there are two movements: In our problem, there are two movements:
...@@ -62,11 +63,7 @@ return portal_simulation.getInventory( ...@@ -62,11 +63,7 @@ return portal_simulation.getInventory(
) )
``` ```
# Dates
---
## Dates
We are usually interested in knowing the stock level at a certain point of time. This is rather easy, because we usually record the point in time when the movement occured. We are usually interested in knowing the stock level at a certain point of time. This is rather easy, because we usually record the point in time when the movement occured.
...@@ -113,7 +110,7 @@ SELECT SUM(quantity) from stock where Node='Alice' and Date <= Tuesday ...@@ -113,7 +110,7 @@ SELECT SUM(quantity) from stock where Node='Alice' and Date <= Tuesday
``` ```
But Carol's inventory of candies is still 0 on Wednesday: But Carol's inventory of candies is still 0 on Wednesday:
```#python ```python
>>> getInventory(node=Carol, at_date=Wednesday) >>> getInventory(node=Carol, at_date=Wednesday)
0 0
``` ```
...@@ -134,34 +131,97 @@ SELECT SUM(quantity) from stock where Node='Carol' and Date <= Thursday ...@@ -134,34 +131,97 @@ SELECT SUM(quantity) from stock where Node='Carol' and Date <= Thursday
# Complete structure of a movement # Complete structure of a movement
quantity ## Movements properties
quantity unit In our candy example, we abstracted many of properties that are needed on movements to represent the complexity of real business cases.
resource
price A more realistic example could be ``20 kilograms of *sand* delivered from supplier to warehouse where the unit price is 10€``.
price currency In that example movement, supplier organisation is the *source*, warehouse is the *destination*. The *resource* is sand, *quantity* is 20, the *quantity unit* is Kilogram, the *price* (per unit) is 10 and the *price currency* is the Euro currency. Quantity and Price properties are set on movements and we can calculate the *total price* by multiplying the quantity by the price. In that case, total price is $20*10 = 200$.
use There are movements of different types that are stored in different modules, for example there are order, delivery or invoices movements. We also separate sales, purchase and internal movements. All movements have a *portal_type* property that can be for example `Purchase Order Line` or `Sale Order Line`. Portal Type comes from Zope CMF and is used to configure technical aspects such as the available view and the applicable security rules, so there is an higher level to define what is the kind of movement; this is the *use* category.
start_date Movements have a *simulation_state* which is controlled by a simulation workflow. Movements are usually part of a *delivery* on which users with the proper accreditation can pass workflow transitions to change the state. For example, one sales agent can "confirm" a sales order, that will change the simulation state of all the movements from planned to confirmed. Typically, simulation states are used for different level of certainty and have different level of planning.
stop_date Movements have a *start_date* and a *stop_date* properties whose types are Zope DateTime instances.
simulation_state Even if in our example the total price is 200€, the "value" of this movement can be different for the supplier and for the warehouse. The supplier may want to account that the value of these 10Kg of Sand was, let's say, 110€. The *source_total_asset_price* property of a movement holds the value of this movement in the source's inventory and symetrically, the *destination_total_asset_price* the value in destination's inventory. Source asset price is always in the source's accounting currency and destination asset price always in destination's accounting currency.
Movements also have an *efficiency* property to note that a percentage of the movements quantity can be lost during the movement. For example, a movement with quantity 10 and efficiency of 95% would decrease the source's inventory by 10 and increase the inventory of the destination by 9.5. This is what we call source *inventoriated quantity* and *destination inventoriated quantity*.
XXX Difference from Amount and Movement.
XXX Reference to movement interface.
## Movements categories
Previous example just described a movement going from supplier to warehouse. The *physical* location of the resource changed from supplier to the warehouse, but we want to consider other parties. For example, the *ownership* might not be to the warehouse but be the headquarters organisation. We can also states things like "Mr Smith is the main contact for questions related to this sales"; this is *administration*; or "the paiment will be made on this bank account"; this is *payment*; or "this sand will be used for the project of XXX (better resource)"; this is *project* or it that "it will be used for production operations"; this is *function*; that it will be paid using a governement grant money; this is *funding*.
Movements have various source / destination categories and it seems that this list of categories depends on the kind of business being modeled. Some examples are summarized in the table below:
| Category | Meaning |
|--------------------|---------|
|Source/Destination | What is the physical location |
|Source Section/Destination Section | Who has ownership after this movement |
|Source Payment/Destination Payment | Which "bank account" is used to pay / who will pay |
|Source Project/Destination Project | What is the project for the source or destination |
|Source Function/Destination Function | What is the "purpose" for the source or destination |
|Source Administration/Destination Administration | Who is in charge of administrative tasks related to this movement |
XXX vector projection
# Different kind of inventories # Different kind of inventories
Depending of the level of certainty, we usually consider different ways of seeing the inventory.
## Current Inventory ## Current Inventory
## Future Inventory Current inventory is what is currently in the stock. This includes all movements that have a simulation state representing the fact that this movement has already happened.
## Available Inventory To calculate current inventory, we take into account *transit* movements with special care. A movement that is in *started* state has already decreased the inventory of the source, but not yet increased the inventory of the destination.
  • another text from email discussion with @luke

    There is a small difference in the meaning of available, but generally, that's this idea, it's based on the state of movements, which are seen here as a probability that the movement will happen. Stopped and Delivered movement really happened. Started movement really left the source and will very probably arrive at destination. Confirmed and Planned movement will probably happen.

    Current: What is really in the stock. If you go to the warehouse and count products you should see the same quantity, so it counts only movements that really happen. Of course, to see the same as Current Inventory at a specific date, set your time machine to this date before going to the warehouse.

    Available: What is available for sale to your customers. It includes what's really in the stock, what will probably go out, but not what will probably comes in (in this view, because we are not sure it will come, we don't want to tell our customer we have it for sale). In other words, what is about to be sent to customer (ex: confirmed outgoing packing lists) are considered. What's not yet in the stock but will soon be there (ex: confirmed incoming packing list) are not considered. It's like a "pessimistic"/"worst case scenario" view of the stock.

    Future: What will be the stock in the future, it considers movement that will probably decrease stock and movement that will probably increase stock as well.

Please register or sign in to reply
Current inventory is for example used for the actual quantities of goods in the warehouses.
## Future Inventory
Future inventory considers all movements that have not really happened yet, but for which we already know that their are great changes that they happen. Furure inventory takes into account *planned* or *confirmed* state and is generally used to make stocks previsions.
Please register or sign in to reply
# More axis ## Available Inventory
( section, project, payment, funding ) Available inventory is the inventory that can be offered to customers without risking to go out of stock. Available inventory counts incoming movements only if they really happened and count outgoing movements even if they are only planned.
XXX relationship with budget
# Category # Hierarchical categories
Explain node_category instead of node_uid Explain node_category instead of node_uid
# Complete API # Complete API
XXX explain that the idea is to pass parameter to represent a "perimeter" to consider.
## getInventory ## getInventory
`getInventory` sums the quantity of all movements to return the quantity of resources.
XXX more ?
This method does not check that the provided parameters leads to results that make sense in the real world. With this method, one can request the sum of kilograms of carots + litters of gasoline.
## getInventoryAssetPrice ## getInventoryAssetPrice
`getInventoryAssetPrice` returns the total "values" XXX of the movements.
## getInventoryList ## getInventoryList
`getInventoryList` can query in only one call the inventories of multiple nodes. The aggregation parameters has to be specified. For example, in the case of warehouse inventories, we want to pass `group_by_node=True` and `group_by_resource=True` to get the inventory for each node and resource.
Using one `getInventoryList` is usually much more efficient than doing multiple `getInventory`/`getInventoryAssetPrice` calls.
For example, this code:
```python
print "N1's inventory of R1 is {inventory}, value is {value}".format(
inventory=getInventory(node_uid=N1.getUid(), resource=R1.getUid(),
asset_price=getInventoryAssetPrice(node_uid=N1.getUid(), resource=R1.getUid()))
print "N2's inventory of R1 is {inventory}, value is {value}".format(
inventory=getInventory(node_uid=N2.getUid(), resource=R1.getUid(),
asset_price=getInventoryAssetPrice(node_uid=N2.getUid(), resource=R1.getUid()))
```
can be written more efficiently with `getInventoryList` this way:
```python
for brain in getInventoryList(node_uid=(N1.getUid(), N2.getUid()),
resource_uid=R1.getUid(),
group_by_node=True):
print "{node}'s inventory of R1 is {inventory}, value is {value}".format(
node=brain.node_title,
inventory=brain.total_inventory,
asset_price=brain.total_price)
```
## getMovementHistoryList ## getMovementHistoryList
## Complete List of supported parameters ## Complete List of supported parameters
...@@ -173,9 +233,55 @@ omit_input, omit_output ...@@ -173,9 +233,55 @@ omit_input, omit_output
omit_asset_increase, omit_asset_decrease omit_asset_increase, omit_asset_decrease
# Inventory "documents"
Whereas we calculate inventory by summing all the movements to date, there may be differences between the theorical stock in the database and the real stock on the warehouse floor. It is common business practice to make so called "inventory" (XXX check in dictionary) where people go on the floor and count how many items of each resources are physically present in each stock locations.
After this, they can input the actual values in an `Inventory` document.
Let's consider an example.
Many incoming purchase packing lists have increased the stocks and many outgoing sales packing lists have decreased the stock. The stock levels are as displayed in this table:
| Node | Resource | Quantity |
| ------------- | -------- | ---------:|
| N1 | R1 | 5 |
| N1 | R2 | 10 |
| N2 | R1 | 3 |
When counting the quantities of R1 and R2 in nodes N1 and N2, we notice:
| Node | Resource | Quantity |
| ------------- | -------- | ---------:|
| N1 | R1 | 4 |
| N1 | R2 | 12 |
| N2 | R1 | 3 |
This is the information that will be entered in an inventory document and this inventory will be "indexed" in the stock table like this:
| Node | Resource | Quantity |
| ------------- | -------- | ---------:|
| N1 | R1 | -1 |
| N1 | R2 | 3 |
Then, when we call `getInventory(node=N1, resource=R1)`, the following lines are considered:
| Node | Resource | Quantity |
| ------------- | -------- | ---------:|
| *N1* | *R1* | *5* |
| N1 | R2 | 10 |
| N2 | R1 | 3 |
| *N1* | *R1* | *-1* |
| N1 | R2 | 3 |
And the value returned by `getInventory` is 4, which matches what has been counted on the floor during inventory procedure.
XXX Check terminology and maybe put below.
# Flow API # Flow API
linear movements linear movements
# Example uses
## Warehouse Inventory
## Time
##
# Tracking API # Tracking API
XXX or another doc ?
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment