(inventory-system)=
# Inventory system

:::{figure} ../img/seller-posing-in-a-grocery-and-cosmetics-shop-converted-to-digital.png
:figwidth: 35%
:align: right
Digital inventory themed version of {numref}`spare-parts-inventory-assistant-figure` from Spare Parts Inventory Assistant <small>by ChatGPT</small>
<!--ChatGPT: Convert this image to depict a digital inventory system-->
:::

After implementing {ref}`spare-parts-inventory-assistant`, you want to create an inventory system, which has the following features:

- customers can place orders
  - for simplicity, you have a predefined set of queued orders
- the system can track your revenue
- you can process orders one by one by clicking a button
  - clicking a button merely transfers an order from the queue to a list of processed orders
  - after processing an order, your revenue is automatically updated.
- your program keeps the number or weight of items in your inventory
  - after an order has been processed, you update your stock.
- you have both countable and non-countable bulk items in your inventory. Bulk items are counted in kilograms

Your goal is to create a simple inventory system program with GUI like in the demo video below.

:::{video} ../img/inventory-system.webm
Inventory system demonstration.
:::

It must have the following classes along with their data fields and methods:

- `Item`: a general item
  - `Name`
  - `PricePerUnit`
- `BulkItem`: a bulk item sold in e.g., kg, meter
  - `MeasurementUnit`
- `UnitItem`: item sold in counts
  - `Weight`: weight of each item
- `Inventory`: tracks items in the inventory
  - `stock`: stores for each item its quantity in the inventory
  - `LowStockItems()`: gets a collection of low stock items, e.g., less than five
- `OrderLine`: item with its quantity – a single line of an `Order`.
  - `Item`: ordered item
  - `Quantity`: quantity of the ordered item
- `Order`: a buying request placed by a customer
  - `Time`: exact time of an order
  - `OrderLines`: list of order lines – a list of items that a customer wants to buy with their quantity
  - `TotalPrice()`: calculates the total price of the items
- `OrderBook`: tracks orders and total revenue
  - `QueuedOrders`: list of queued orders
  - `ProcessedOrders`: list of processed orders
  - `QueueOrder(Order)`: places an order in `QueuedOrders`
  - `ProcessNextOrder()`: removes earliest queued order and places it into processed orders
  - `TotalRevenue()`: returns total revenue from processed orders
- `Customer`
   - `Name`
   - `Orders`: list of orders that the customer have placed
   - `CreateOrder(OrderBook, Order)`: Creates the given order in the given order book. Orders are initiated by a customer.

Choose reasonable datatypes for the data fields and method return values.

Your GUI must at least have these elements:
- list of queued orders
- list of processed orders
- a process button that uses `ProcessNextOrder()`
- a field that shows total revenue

:::{activity} Visual relation between concepts
:label: visual-relation-between-concepts
This problem can be modeled using concepts that interact with each other. Use the following classes to draw a diagram that shows the relationships between concepts.

- price per unit
- item, bulk item
- inventory
- stock (e.g., *we have three pens in stock*)
- order
- order book
- customer

Example:
```{mermaid}
graph LR
inventory -->|has many| item
item -->|has a| price_per_unit
bulk_item -->|is an| item
%%inventory -->|has a| stock

%%- price
%%- item, bulk item
%%- inventory
%%- stock (e.g., *we have three pens in stock*)
%%- order
%%- order book
%%- customer
```
:::

<!--
Include toString override for complex objects
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/how-to-override-the-tostring-method

TODO, we need `public override string ToString()` so that each OrderLine's content is automatically shown on the grid. I tried it but failed. I had to introduce DataGridTextColumn

According to:
https://github.com/AvaloniaUI/Avalonia.Samples/tree/main/src/Avalonia.Samples/DataTemplates/BasicDataTemplateSample

If no DataTemplate is found that matches your object, Avalonia will call ToString() and display the result in a TextBlock. You can [override ToString()] in your own class, if you want to return a custom string.

-->