Skip to content

rhinock/WarehouseManagementSystem

Repository files navigation

Warehouse Management System

The system provides next functionality:

  • view list of warehouses, items and warehouse items
  • add or edit an item with particular price
  • add, edit or delete an item to/from warehouse with particular amount

Note. Warehouses, Items and WarehouseItems -- are different tables.

Languages, technologies, instruments, etc.:

  • OOP and SOLID principles
  • only server side (WebAPI controllers)
  • .NET Core
  • EF Core
  • PostgreSQL
  • integration tests (webhost, xUnit)
  • docker
  • docker-compose
  • kubernetes (minikube)
  • helm
  • curl
  • PowerShell

PostgreSQL

Diagram

Initial Data

Items

Id Name Price
1 pencil 10.00
2 pen 20.00
3 felt-tip pen 30.00

Warehouses

Id Name MaximumItems
1 miniature 100
2 decent 10000
3 hefty 1000000

WarehouseItems

Id WarehouseId ItemId Count
1 1 1 50
2 2 2 5000
3 3 3 500000

dotnet

dotnet run --project WMS.UI/WMS.UI.csproj

RESTful APIs

# GET POST PUT DELETE
Warehouses ✔️ ❌ ❌ ❌
Items ✔️ ✔️ ✔️ ❌
WarehouseItems ✔️ ✔️ ✔️ ✔️

Docker

Build image and push to hub.docker.com

docker build -t wms:latest .
# docker tag <image>:<tag> <login>/<image>:<tag>
docker tag wms:latest rhinock/wms:latest
# docker push <login>/<image>:<tag>
docker push rhinock/wms:latest

docker image ls -a

Remove Dockerfile generated items

docker image rm rhinock/wms:latest
docker image rm wms:latest
docker image rm mcr.microsoft.com/dotnet/sdk:3.1-alpine
docker image rm mcr.microsoft.com/dotnet/aspnet:3.1-alpine
docker image prune -f
docker volume prune -f

docker image ls -a
docker volume ls

Run application with bridge network driver

docker network create app --driver bridge

docker run --name postgres -e POSTGRES_PASSWORD=1234 -e POSTGRES_DB=WMS -d --network=app postgres:12-alpine

docker run --name wms -e ConnectionStrings__WmsDbContextPostgres="Host=postgres;Port=5432;Database=WMS;Username=postgres;Password=1234" -d --network=app -p 8080:80 rhinock/wms:latest

docker network ls
docker image ls -a
docker container ls -a

Remove Dockerfile generated items

docker container rm -f wms
docker container rm -f postgres
docker image rm postgres:12-alpine
docker image rm rhinock/wms:latest
docker network rm app
docker volume prune -f

docker network ls
docker image ls -a
docker volume ls
docker container ls -a

Run application without bridge network driver

docker run --name postgres -e POSTGRES_PASSWORD=1234 -e POSTGRES_DB=WMS -d postgres:12-alpine

docker run --name wms -e ConnectionStrings__WmsDbContextPostgres="Host=postgres;Port=5432;Database=WMS;Username=postgres;Password=1234" -d -p 8080:80 --link postgres:postgres rhinock/wms:latest

docker image ls -a
docker container ls -a

env variables

docker exec postgres env | grep 'POSTGRES_PASSWORD\|POSTGRES_DB'
docker exec wms env | grep ConnectionStrings__WmsDbContextPostgres

psql

docker exec -it postgres psql -U postgres
# list databases
\l
# connect to database 'WMS'
\c WMS
# list all schemas
\dn
# list all tables in schema 'public'
\dt public.*
# select data from all tables
SELECT * FROM public."Items";
SELECT * FROM public."Warehouses";
SELECT * FROM public."WarehouseItems";
# delete non-initial data
DELETE FROM public."Items" WHERE "Id">3;
DELETE FROM public."WarehouseItems" WHERE "Id">3;

Remove Dockerfile generated items

docker container rm -f wms
docker container rm -f postgres
docker image rm postgres:12-alpine
docker image rm rhinock/wms:latest
docker volume prune -f

docker image ls -a
docker volume ls
docker container ls -a

Docker Compose

Build images locally

docker-compose up -d

docker network ls
docker image ls -a
docker container ls -a

Remove Docker Compose generated items

docker-compose down
docker image rm rhinock/wms:latest
docker image rm postgres:12-alpine
docker image rm mcr.microsoft.com/dotnet/sdk:3.1-alpine
docker image rm mcr.microsoft.com/dotnet/aspnet:3.1-alpine
docker image prune -f
docker volume prune -f

docker network ls
docker image ls -a
docker volume ls
docker container ls -a

Pull images from hub.docker.com

docker-compose pull
docker-compose up -d

docker network ls
docker image ls -a
docker volume ls
docker container ls -a

Remove Docker Compose generated items

docker-compose down
docker image rm postgres:12-alpine
docker image rm rhinock/wms:latest
docker volume prune -f

docker network ls
docker volume ls
docker image ls -a
docker container ls -a

Kubernetes (minikube)

hosts file

# <minikube ip> wms.com
192.168.49.2 wms.com

Apply manifests

k apply -f k8s/

Remove Kubernetes generated items

k delete -f k8s/
k delete pvc pg-data-postgres-statefulset-0

Get Kubernetes generated items

k get sc
k get pv
k get pvc
k get sts
k get deploy
k get rs
k get svc
k get ingress
k get endpoints
k get po

Helm

Generate helm templates from chart

helm template chart

Create helm chart

helm create chart

Compress helm chart

tar -cvzf chart.tgz chart

Output:

chart/
chart/Chart.yaml
chart/values.yaml
chart/.helmignore
chart/templates/
chart/templates/ingress.yaml
chart/templates/wms-service.yml
chart/templates/wms-deployment.yml
chart/templates/postgres-statefulset.yaml
chart/templates/postgres-service.yaml
chart/templates/storageClass.yaml

Install helm chart from archive

helm install wms chart.tgz

Install helm chart from folder

helm install wms chart/

Upgrade helm chart

helm upgrade wms chart/

Get history of helm charts

helm history wms

Rollback helm chart

helm rollback wms 1

Uninstall helm chart

helm uninstall wms
k delete pvc pg-data-wms-postgres-statefulset-0

Get helm items

helm list
helm get manifest wms
helm get manifest wms --revision 1
helm get manifest wms --revision 2

Get kubernetes items generated by helm

k get sc
k get pv
k get pvc
k get sts
k get deploy
k get rs
k get svc
k get ingress
k get endpoints
k get po

PowerShell Modules [Windows only]

Creating the Module Folder and Files

New-Item -Type Directory -Name PowerShell

Creating the PowerShell Module Manifest (PSD1)

# Use splatting technique to make it more readable
$ModuleManifestParams = @{
    Path            = "PowerShell\WMS.psd1" # Notice that the psd1 file has the same name as the folder it resides in
    Guid            = [GUID]::NewGuid().Guid # A unique GUID for the module for identification
    Author          = "Your Name Here" # Optional
    CompanyName     = "Company Name here" # Optional
    ModuleVersion   = "0.0.1" # Semantic versioning as recommended best practice for PowerShell modules
    Description     = "A PowerShell module to interact with the HttpBin API" # A short description of what the module does
}

# Run New-ModuleManifest with the splatted parameters
New-ModuleManifest @ModuleManifestParams

Creating the PowerShell Module (PSM1)

New-Item -ItemType File -Path PowerShell\ -Name WMS.psm1

The .psm1 file is the file that will hold all module functions. Creating the PowerShell module file (.psm1) is just as simple as using PowerShell editor of our choice to create a new, blank text file at the C:.psm1 path.

Adding the Base URI the the Module

$script:BaseUri = "api"
$script:InvokeParams = @{
    ContentType = "application/json"
}

Writing the Functions

Importing the Module

Now that you've created the first function in the module, it's time to start using it. Import the module using the Import-Module command as shown below.

Import-Module -Name .\PowerShell\WMS.psm1 -Verbose -Force

curl | PowerShell [Windows only]

curl variables:

# local deployment
HOST=localhost:5000
# docker and docker-compose
HOST=localhost:8080
# kubernetes (minikube) and helm
HOST=wms.com:80

PowerShell parameters:

# local deployment
-Protocol https
-Host localhost
-Port 44385
# docker and docker-compose
-Protocol http
-Host localhost
-Port 8080
# kubernetes (minikube) and helm
-Protocol http
-Host wms.com
-Port 80

Warehouses

GET

Success

curl -v -H "Content-Type: application/json" http://$HOST/api/warehouses
curl -v -H "Content-Type: application/json" http://$HOST/api/warehouses/1
GetObjects -Objects Warehouses
GetObjects -Objects Warehouses -Id 1

Fail

curl -v -H "Content-Type: application/json" http://$HOST/api/warehouses/999
GetObjects -Objects Warehouses -Id 999

Items

GET

Success

curl -v -H "Content-Type: application/json" http://$HOST/api/items
curl -v -H "Content-Type: application/json" http://$HOST/api/items/1
GetObjects -Objects Items
GetObjects -Objects Items -Id 1

Fail

curl -v -H "Content-Type: application/json" http://$HOST/api/items/999
GetObjects -Objects Items -Id 999

POST

Success

curl -v -H "Content-Type: application/json" -X POST http://$HOST/api/items -d @"payload/CreateItem.json"
PostOrPutObject -Objects Items -Method Post -JsonFilePath .\payload\CreateItem.json

Fail

curl -v -H "Content-Type: application/json" -X POST http://$HOST/api/items -d @"payload/CreateItemWithId.json"
curl -v -H "Content-Type: application/json" -X POST http://$HOST/api/items -d @"payload/CreateItemWithNegativePrice.json"
PostOrPutObject -Objects Items -Method Post -JsonFilePath .\payload\CreateItemWithId.json
PostOrPutObject -Objects Items -Method Post -JsonFilePath .\payload\CreateItemWithNegativePrice.json

PUT

Success

curl -v -H "Content-Type: application/json" -X PUT http://$HOST/api/items -d @"payload/UpdateItem.json"
PostOrPutObject -Objects Items -Method Put -JsonFilePath .\payload\UpdateItem.json

Fail

curl -v -H "Content-Type: application/json" -X PUT http://$HOST/api/items -d @"payload/UpdateItemWithIncorrectId.json"
curl -v -H "Content-Type: application/json" -X PUT http://$HOST/api/items -d @"payload/UpdateItemWithIncorrectData.json"
PostOrPutObject -Objects Items -Method Put -JsonFilePath .\payload\UpdateItemWithIncorrectId.json
PostOrPutObject -Objects Items -Method Put -JsonFilePath .\payload\UpdateItemWithIncorrectData.json

WarehouseItems

GET

Success

curl -v -H "Content-Type: application/json" http://$HOST/api/WarehouseItems
curl -v -H "Content-Type: application/json" http://$HOST/api/WarehouseItems/1
GetObjects -Objects WarehouseItems
GetObjects -Objects WarehouseItems -Id 1

Fail

curl -v -H "Content-Type: application/json" http://$HOST/api/WarehouseItems/999
GetObjects -Objects WarehouseItems -Id 999

POST

Success

curl -v -H "Content-Type: application/json" -X POST http://$HOST/api/warehouseitems -d @"payload/CreateWarehouseItem.json"
PostOrPutObject -Objects WarehouseItems -Method Post -JsonFilePath .\payload\CreateWarehouseItem.json

Fail

curl -v -H "Content-Type: application/json" -X POST http://$HOST/api/warehouseitems -d @"payload/CreateWarehouseItemWithId.json"
curl -v -H "Content-Type: application/json" -X POST http://$HOST/api/warehouseitems -d @"payload/CreateWarehouseItemWithNegativeCount.json"
PostOrPutObject -Objects WarehouseItems -Method Post -JsonFilePath .\payload\CreateWarehouseItemWithId.json
PostOrPutObject -Objects WarehouseItems -Method Post -JsonFilePath .\payload\CreateWarehouseItemWithNegativeCount.json

PUT

Success

curl -v -H "Content-Type: application/json" -X PUT http://$HOST/api/warehouseitems -d @"payload/UpdateWarehouseItem.json"
PostOrPutObject -Objects WarehouseItems -Method Put -JsonFilePath .\payload\UpdateWarehouseItem.json

Fail

curl -v -H "Content-Type: application/json" -X PUT http://$HOST/api/warehouseitems -d @"payload/UpdateWarehouseItemWithIncorrectId.json"
curl -v -H "Content-Type: application/json" -X PUT http://$HOST/api/warehouseitems -d @"payload/UpdateWarehouseItemWithIncorrectIds.json"
curl -v -H "Content-Type: application/json" -X PUT http://$HOST/api/warehouseitems -d @"payload/UpdateWarehouseItemWithIncorrectData.json"
PostOrPutObject -Objects WarehouseItems -Method Put -JsonFilePath .\payload\UpdateWarehouseItemWithIncorrectId.json
PostOrPutObject -Objects WarehouseItems -Method Put -JsonFilePath .\payload\UpdateWarehouseItemWithIncorrectIds.json
PostOrPutObject -Objects WarehouseItems -Method Put -JsonFilePath .\payload\UpdateWarehouseItemWithIncorrectData.json

DELETE

Success

curl -v -H "Content-Type: application/json" -X DELETE http://$HOST/api/warehouseitems/1
DeleteObject -Objects WarehouseItems -Id 1

Fail

curl -v -H "Content-Type: application/json" -X DELETE http://$HOST/api/warehouseitems/999
DeleteObject -Objects WarehouseItems -Id 999