Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions database/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
services:
# database:
# image: 'postgres:latest'
# ports:
# - 5432:5432
# env_file:
# - .env
# networks:
# - postgres-network
# volumes:
# - ${PWD}/db-data/:/var/lib/postgresql/data/

pgadmin:
image: dpage/pgadmin4
ports:
- 15433:80
env_file:
- .env
networks:
- postgres-network
volumes:
- ${PWD}/pgadmin-data/:/var/lib/pgadmin/

psql-client:
image: postgres:latest
entrypoint: ["bash"]
tty: true
stdin_open: true
networks:
- postgres-network

networks:
postgres-network:
driver: bridge
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ psycopg2-binary
python-dotenv
dj-database-url
requests
django-cors-headers
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
from django.core.management.base import BaseCommand
from product.models import ProductCategory, Product, SupplierProduct
from warehouse.models import Warehouse, WarehouseInventory,InventoryTransaction
from warehouse.models import Warehouse, WarehouseInventory, InventoryTransaction
from decimal import Decimal
from django.utils import timezone
import random
from datetime import timedelta


class Command(BaseCommand):
help = 'Delete old data and populate categories, products, suppliers, warehouses, and inventory'

def handle(self, *args, **kwargs):
self.stdout.write("🧹 Deleting existing data...")
# SupplierProduct.objects.all().delete()
# Product.objects.all().delete()
# ProductCategory.objects.all().delete()
# WarehouseInventory.objects.all().delete()
# Warehouse.objects.all().delete()
# InventoryTransaction.objects.all().delete()

InventoryTransaction.objects.all().delete()
WarehouseInventory.objects.all().delete()
SupplierProduct.objects.all().delete()
Product.objects.all().delete()
ProductCategory.objects.all().delete()
Warehouse.objects.all().delete()

self.stdout.write("🧪 Populating new data...")

# Product categories
category_names = ['Cinnamon', 'Pepper', 'Cardamom', 'Chili']
Expand All @@ -28,45 +34,81 @@ def handle(self, *args, **kwargs):

# Products
products = []
for i in range(10):
for i in range(10): # more products
category = random.choice(categories)
product = Product.objects.create(
product_SKU=f"SKU{i + 1:03}",
product_name=f"{category.category_name} Product {i + 1}",
unit_price=round(random.uniform(100, 2000), 2),
category=category
)
products.append(product)

# Warehouses
warehouse1 = Warehouse.objects.create(
warehouse_name="Colombo Central", location_x="6.9271° N", location_y="79.8612° E"
)
warehouse2 = Warehouse.objects.create(
warehouse_name="Kandy Depot", location_x="7.2906° N", location_y="80.6337° E"
)
warehouse3 = Warehouse.objects.create(
warehouse_name="Kurunegala Rock", location_x="7.0032° N", location_y="80.1102° E"
)
warehouses = [warehouse1, warehouse2, warehouse3]
warehouse_data = [
("Colombo Central", "6.9271° N", "79.8612° E"),
("Kandy Depot", "7.2906° N", "80.6337° E"),
("Kurunegala Rock", "7.0032° N", "80.1102° E"),
]
warehouses = []
for name, x, y in warehouse_data:
warehouse = Warehouse.objects.create(
warehouse_name=name,
location_x=x,
location_y=y,
capacity=Decimal("1000000.00")
)
warehouses.append(warehouse)

# Supplier products & warehouse inventory
# SupplierProduct, WarehouseInventory, and InventoryTransaction
for product in products:
for supplier_id in [101, 102]:
for supplier_id in [101, 102, 103]:
# SupplierProduct
max_capacity = random.randint(300000, 600000)
lead_time = random.randint(3, 10)
SupplierProduct.objects.create(
supplier_id=supplier_id,
product=product,
maximum_capacity=random.randint(300000, 600000),
maximum_capacity=max_capacity,
supplier_price=round(random.uniform(80, 1500), 2),
lead_time_days=random.randint(3, 10)
lead_time_days=lead_time
)

# For each warehouse, create inventory & transactions
for warehouse in warehouses:
WarehouseInventory.objects.create(
quantity = Decimal(random.uniform(100000, 400000))
last_restocked = timezone.now() - timedelta(days=random.randint(1, 60))

inventory = WarehouseInventory.objects.create(
warehouse=warehouse,
product=product,
supplier_id=supplier_id,
quantity=Decimal(random.uniform(100000, 400000)),
quantity=quantity,
last_restocked=last_restocked,
minimum_stock_level=Decimal("100000.00")
)

self.stdout.write(self.style.SUCCESS("✅ Successfully seeded all data!"))
# Create 1-2 incoming and 1 outgoing transactions per inventory
for _ in range(random.randint(1, 2)):
qty_in = Decimal(random.uniform(10000, 50000))
InventoryTransaction.objects.create(
inventory=inventory,
transaction_type='INCOMING',
quantity_change=qty_in,
reference_number=f"REF-{random.randint(1000,9999)}",
notes="Initial delivery",
created_by=f"Supplier {supplier_id}"
)

if random.choice([True, False]):
qty_out = Decimal(random.uniform(5000, 20000))
InventoryTransaction.objects.create(
inventory=inventory,
transaction_type='OUTGOING',
quantity_change=qty_out,
reference_number=f"OUT-{random.randint(1000,9999)}",
notes="Customer shipment",
created_by="System"
)

self.stdout.write(self.style.SUCCESS("✅ Successfully seeded all data including inventory and transactions!"))
18 changes: 18 additions & 0 deletions warehouse_managment/product/migrations/0002_product_product_sku.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.2 on 2025-05-07 14:25

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('product', '0001_initial'),
]

operations = [
migrations.AddField(
model_name='product',
name='product_SKU',
field=models.CharField(default='SKU000', max_length=30, unique=True),
),
]
1 change: 1 addition & 0 deletions warehouse_managment/product/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class Meta:
db_table = 'product_category'

class Product(models.Model):
product_SKU = models.CharField(max_length=30, unique=True, default='SKU000')
product_name = models.CharField(max_length=60)
unit_price = models.DecimalField(max_digits=10, decimal_places=2)
category = models.ForeignKey(ProductCategory, on_delete=models.CASCADE)
Expand Down
13 changes: 5 additions & 8 deletions warehouse_managment/product/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,26 +75,23 @@ def update_supplier_product(request):
except SupplierProduct.DoesNotExist:
return Response({"error": "SupplierProduct not found"}, status=404)


@api_view(['GET'])
def product_stock_summary(request, sku_code):

# Ensure SKU format is valid (e.g., SKU001)
# Optional: Validate SKU format if needed
if not sku_code.startswith("SKU") or not sku_code[3:].isdigit():
return Response({'error': 'Invalid SKU format'}, status=400)

product_id = int(sku_code[3:]) # SKU001 → 1

try:
product = Product.objects.get(id=product_id)
product = Product.objects.get(product_SKU=sku_code)
except Product.DoesNotExist:
return Response({'error': 'Product not found'}, status=status.HTTP_404_NOT_FOUND)

total_stock = WarehouseInventory.objects.filter(product_id=product_id).aggregate(
total_stock = WarehouseInventory.objects.filter(product=product).aggregate(
total=Sum('quantity')
)['total'] or 0

return Response({
"product_name": product.product_name,
"product_SKU": product.product_SKU,
"current_stock": float(total_stock)
}, status=status.HTTP_200_OK)
}, status=status.HTTP_200_OK)
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.2 on 2025-05-07 14:25

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('warehouse', '0001_initial'),
]

operations = [
migrations.AddField(
model_name='warehouse',
name='capacity',
field=models.DecimalField(blank=True, decimal_places=2, max_digits=12, null=True),
),
]
1 change: 1 addition & 0 deletions warehouse_managment/warehouse/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class Warehouse(models.Model):
location_x = models.CharField(max_length=64)
location_y = models.CharField(max_length=64)
warehouse_name = models.CharField(max_length=100, blank=True)
capacity = models.DecimalField(max_digits=12, decimal_places=2, blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True)

class Meta:
Expand Down
9 changes: 9 additions & 0 deletions warehouse_managment/warehouse/supplier_names.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# supplier_names.py

SUPPLIER_NAME_MAP = {
101: "Supplier A",
102: "Supplier B",
103: "Supplier C",
104: "Supplier D",
# Add more supplier IDs as needed
}
41 changes: 35 additions & 6 deletions warehouse_managment/warehouse/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from product.models import Product, SupplierProduct, ProductCategory
from django.db.models import Sum
from .models import Warehouse, WarehouseInventory, InventoryTransaction
from .supplier_names import SUPPLIER_NAME_MAP
from .serializers import (
WarehouseSerializer,
WarehouseInventorySerializer,
Expand All @@ -23,13 +24,41 @@ def warehouse_list(request):
def warehouse_inventory_list(request):
warehouse_id = request.query_params.get('warehouse_id')

if warehouse_id:
inventory = WarehouseInventory.objects.filter(warehouse_id=warehouse_id)
else:
inventory = WarehouseInventory.objects.all()
if not warehouse_id:
return Response({"error": "warehouse_id is required"}, status=400)

try:
warehouse = Warehouse.objects.get(id=warehouse_id)
except Warehouse.DoesNotExist:
return Response({"error": "Warehouse not found"}, status=404)

inventory = WarehouseInventory.objects.filter(warehouse_id=warehouse_id)

current_stock_level = inventory.aggregate(total=Sum('quantity'))['total'] or 0
minimum_stock_level = inventory.aggregate(min_level=Sum('minimum_stock_level'))['min_level'] or 0
last_restocked = inventory.order_by('-last_restocked').values_list('last_restocked', flat=True).first()

inventory_product_details = []
for item in inventory:
inventory_product_details.append({
"product_name": item.product.product_name,
"category": item.product.category.category_name,
"supplied_by": SUPPLIER_NAME_MAP.get(item.supplier_id, f"Supplier {item.supplier_id}"),
"supplied_date": item.created_at.date() if item.created_at else None,
"product_count": int(item.quantity),
})

result = {
"warehouse_city": warehouse.warehouse_name,
"warehouse_capacity": float(warehouse.capacity),
"minimum_stock_level": float(minimum_stock_level),
"last_restocked": last_restocked.date() if last_restocked else None,
"current_stock_level": float(current_stock_level),
"inventory_product_details": inventory_product_details
}

return Response(result, status=200)

serializer = WarehouseInventorySerializer(inventory, many=True)
return Response(serializer.data)


@api_view(['GET'])
Expand Down
4 changes: 4 additions & 0 deletions warehouse_managment/warehouse_managment/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@

'rest_framework', # Django REST framework
'django.contrib.postgres',
'corsheaders', # CORS headers
]

MIDDLEWARE = [
Expand All @@ -58,8 +59,11 @@
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'corsheaders.middleware.CorsMiddleware', # CORS middleware
]

CORS_ALLOW_ALL_ORIGINS = True

ROOT_URLCONF = 'warehouse_managment.urls'

TEMPLATES = [
Expand Down
Loading