Skip to content
Closed
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
7 changes: 1 addition & 6 deletions warehouse_managment/product/admin.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from django.contrib import admin
from .models import ProductCategory, Product, SupplierProduct
from .models import ProductCategory, Product

@admin.register(ProductCategory)
class ProductCategoryAdmin(admin.ModelAdmin):
Expand All @@ -11,8 +11,3 @@ class ProductAdmin(admin.ModelAdmin):
list_display = ('id', 'product_name', 'unit_price', 'category', 'created_at', 'updated_at')
search_fields = ('product_name',)
list_filter = ('category',)

@admin.register(SupplierProduct)
class SupplierProductAdmin(admin.ModelAdmin):
list_display = ('id', 'supplier_id', 'product', 'maximum_capacity', 'supplier_price', 'lead_time_days')
list_filter = ('supplier_id',)
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
from django.core.management.base import BaseCommand
from product.models import ProductCategory, Product, SupplierProduct
from warehouse.models import Warehouse, WarehouseInventory, InventoryTransaction, WarehouseSupplier
from product.models import ProductCategory, Product
from warehouse.models import Warehouse, WarehouseInventory, InventoryTransaction, SupplierProduct
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...")

# InventoryTransaction.objects.all().delete()
# WarehouseInventory.objects.all().delete()
# SupplierProduct.objects.all().delete()
# Product.objects.all().delete()
# ProductCategory.objects.all().delete()
# WarehouseSupplier.objects.all().delete()
# Warehouse.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...")

Expand All @@ -40,12 +38,12 @@ def handle(self, *args, **kwargs):
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),
unit_price=round(Decimal(random.uniform(100, 2000)), 2),
category=category
)
products.append(product)

# Warehouses (Randomly assigning warehouses to suppliers)
# Warehouses
warehouse_data = [
("Colombo Central", "6.9271° N", "79.8612° E"),
("Kandy Depot", "7.2906° N", "80.6337° E"),
Expand All @@ -61,37 +59,32 @@ def handle(self, *args, **kwargs):
)
warehouses.append(warehouse)

# SupplierProduct, WarehouseInventory, InventoryTransaction, WarehouseSupplier
created_pairs = set()
# SupplierProduct, WarehouseInventory, InventoryTransaction
created_inventories = set()

for product in products:
# Randomly assign suppliers (not for all suppliers)
suppliers = random.sample([101, 102, 103], k=random.randint(1, 3)) # Randomly pick 1 to 3 suppliers
# Random suppliers
suppliers = random.sample([101, 102, 103], k=random.randint(1, 3))
for supplier_id in suppliers:
# SupplierProduct (Randomly create it for some suppliers)
warehouse = random.choice(warehouses)

# SupplierProduct
if random.choice([True, False]):
max_capacity = random.randint(300000, 600000)
lead_time = random.randint(3, 10)
SupplierProduct.objects.create(
supplier_id=supplier_id,
product=product,
warehouse=warehouse,
maximum_capacity=max_capacity,
supplier_price=round(random.uniform(80, 1500), 2),
supplier_price=round(Decimal(random.uniform(80, 1500)), 2),
lead_time_days=lead_time
)

# WarehouseSupplier (Randomly assign warehouses for this supplier)
warehouse = random.choice(warehouses) # Randomly pick one warehouse for this supplier
if (warehouse.id, supplier_id) not in created_pairs:
WarehouseSupplier.objects.create(
warehouse=warehouse,
supplier_id=supplier_id
)
created_pairs.add((warehouse.id, supplier_id))

# Inventory - ensure unique product_id and warehouse_id combination
if not WarehouseInventory.objects.filter(warehouse=warehouse, product=product).exists():
quantity = Decimal(random.uniform(100000, 400000))
# WarehouseInventory
key = (warehouse.id, product.id)
if key not in created_inventories:
quantity = round(Decimal(random.uniform(100000, 400000)), 2)
last_restocked = timezone.now() - timedelta(days=random.randint(1, 60))

inventory = WarehouseInventory.objects.create(
Expand All @@ -101,10 +94,11 @@ def handle(self, *args, **kwargs):
last_restocked=last_restocked,
minimum_stock_level=Decimal("100000.00")
)
created_inventories.add(key)

# Transactions
for _ in range(random.randint(1, 2)):
qty_in = Decimal(random.uniform(10000, 50000))
qty_in = round(Decimal(random.uniform(10000, 50000)), 2)
InventoryTransaction.objects.create(
inventory=inventory,
transaction_type='INCOMING',
Expand All @@ -115,7 +109,7 @@ def handle(self, *args, **kwargs):
)

if random.choice([True, False]):
qty_out = Decimal(random.uniform(5000, 20000))
qty_out = round(Decimal(random.uniform(5000, 20000)), 2)
InventoryTransaction.objects.create(
inventory=inventory,
transaction_type='OUTGOING',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Generated by Django 5.2 on 2025-05-16 07:39

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('product', '0002_product_product_sku'),
]

operations = [
migrations.DeleteModel(
name='SupplierProduct',
),
]
12 changes: 0 additions & 12 deletions warehouse_managment/product/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,3 @@ class Product(models.Model):
class Meta:
db_table = 'product'

class SupplierProduct(models.Model):
supplier_id = models.IntegerField()
product = models.ForeignKey(Product, on_delete=models.CASCADE)
maximum_capacity = models.IntegerField()
supplier_price = models.DecimalField(max_digits=10, decimal_places=2)
lead_time_days = models.IntegerField(blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True)

class Meta:
db_table = 'supplier_product'
unique_together = (('supplier_id', 'product'),)

11 changes: 1 addition & 10 deletions warehouse_managment/product/serializers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from rest_framework import serializers
from .models import ProductCategory, Product, SupplierProduct
from .models import ProductCategory, Product

class ProductCategorySerializer(serializers.ModelSerializer):
class Meta:
Expand All @@ -11,11 +11,6 @@ class Meta:
model = Product
fields = '__all__'

class SupplierProductSerializer(serializers.ModelSerializer):
class Meta:
model = SupplierProduct
fields = '__all__'

class ProductCategorySerializer(serializers.ModelSerializer):
class Meta:
model = ProductCategory
Expand All @@ -26,7 +21,3 @@ class Meta:
model = Product
fields = '__all__'

class SupplierProductSerializer(serializers.ModelSerializer):
class Meta:
model = SupplierProduct
fields = '__all__'
10 changes: 10 additions & 0 deletions warehouse_managment/product/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
supplier_product_list,
update_supplier_product,
product_stock_summary,
get_suppliers_for_product,
get_products_for_supplier
)

urlpatterns = [
Expand All @@ -23,8 +25,16 @@

# Supplier product endpoints
path('supplier-products/', supplier_product_list, name='supplier-product-list'),

# Change the Supplier's maximum capacity to a new value
path('supplier-products/update/', update_supplier_product, name='update-supplier-product'),

# Product count endpoint
path('product-stock-summary/<str:sku_code>/', product_stock_summary),

# GET SupplierIds for a product Id
path('suppliers-by-product', get_suppliers_for_product, name='get-suppliers-for-product'),

# GET Product Ids for a supplier ID
path('products-by-supplier', get_products_for_supplier, name='get-products-for-supplier'),
]
78 changes: 66 additions & 12 deletions warehouse_managment/product/views.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status
from .models import ProductCategory, Product, SupplierProduct
from .serializers import ProductCategorySerializer, ProductSerializer, SupplierProductSerializer
from .models import ProductCategory, Product
from .serializers import ProductCategorySerializer, ProductSerializer
from warehouse.serializers import SupplierProductSerializer
from django.db.models import Sum
from warehouse.models import WarehouseInventory
from warehouse.models import WarehouseInventory, SupplierProduct

@api_view(['GET'])
def root(request):
Expand Down Expand Up @@ -52,32 +53,41 @@ def category_detail(request, pk):

@api_view(['GET'])
def supplier_product_list(request):

sp = SupplierProduct.objects.all()
serializer = SupplierProductSerializer(sp, many=True)
return Response(serializer.data)

@api_view(['POST'])
def update_supplier_product(request):
supplier_id = request.data.get('supplier_id')
product_id = request.data.get('product_id')
warehouse_id = request.data.get('warehouse_id')
new_capacity = request.data.get('maximum_capacity')

supplier_id = request.query_params.get('supplier_id')
product_id = request.query_params.get('product_id')
new_capacity = request.query_params.get('maximum_capacity')

if not all([supplier_id, product_id, new_capacity]):
if not all([supplier_id, product_id, warehouse_id, new_capacity]):
return Response({"error": "Missing fields"}, status=400)

if not WarehouseInventory.objects.filter(product_id=product_id, warehouse_id=warehouse_id).exists():
return Response(
{"error": "This product is not currently stocked in the given warehouse."},
status=400
)

try:
sp = SupplierProduct.objects.get(supplier_id=supplier_id, product_id=product_id)
sp = SupplierProduct.objects.get(
supplier_id=supplier_id,
product_id=product_id,
warehouse_id=warehouse_id
)
sp.maximum_capacity = new_capacity
sp.save()
return Response({"status": "success"}, status=200)
except SupplierProduct.DoesNotExist:
return Response({"error": "SupplierProduct not found"}, status=404)



@api_view(['GET'])
def product_stock_summary(request, sku_code):
# 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)

Expand All @@ -95,3 +105,47 @@ def product_stock_summary(request, sku_code):
"product_SKU": product.product_SKU,
"current_stock": float(total_stock)
}, status=status.HTTP_200_OK)


@api_view(['GET'])
def get_suppliers_for_product(request):
product_id = request.query_params.get('product_id')
if not product_id:
return Response({"error": "product_id is required"}, status=400)

supplier_ids = (
SupplierProduct.objects
.filter(product_id=product_id)
.values_list('supplier_id', flat=True)
.distinct()
)

return Response({
"product_id": int(product_id),
"supplier_ids": list(supplier_ids)
})



@api_view(['GET'])
def get_products_for_supplier(request):
supplier_id = request.query_params.get('supplier_id')
if not supplier_id:
return Response({"error": "supplier_id is required"}, status=400)

products = (
SupplierProduct.objects
.filter(supplier_id=supplier_id)
.values('product_id', 'supplier_price')
.distinct()
)

return Response({
"supplier_id": int(supplier_id),
"products": [
{
"product_id": item["product_id"],
"supplier_price": float(item["supplier_price"])
} for item in products
]
})
12 changes: 7 additions & 5 deletions warehouse_managment/warehouse/admin.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from django.contrib import admin
from .models import Warehouse, WarehouseInventory, InventoryTransaction, WarehouseSupplier
from .models import Warehouse, WarehouseInventory, InventoryTransaction, SupplierProduct

@admin.register(Warehouse)
class WarehouseAdmin(admin.ModelAdmin):
Expand All @@ -15,7 +15,9 @@ class InventoryTransactionAdmin(admin.ModelAdmin):
list_display = ('id', 'inventory', 'transaction_type', 'quantity_change', 'created_at', 'created_by')
list_filter = ('transaction_type', 'created_by')

@admin.register(WarehouseSupplier)
class WarehouseSupplierAdmin(admin.ModelAdmin):
list_display = ('id', 'warehouse', 'supplier_id')
list_filter = ('warehouse',)
@admin.register(SupplierProduct)
class SupplierProductAdmin(admin.ModelAdmin):
list_display = ('id', 'supplier_id', 'product', 'warehouse', 'maximum_capacity', 'supplier_price', 'lead_time_days')
list_filter = ('warehouse', 'supplier_id')
search_fields = ('supplier_id', 'product__product_name')

Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Generated by Django 5.2 on 2025-05-16 07:39

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('product', '0003_delete_supplierproduct'),
('warehouse', '0003_remove_warehouseinventory_supplier_id_and_more'),
]

operations = [
migrations.CreateModel(
name='SupplierProduct',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('supplier_id', models.IntegerField()),
('maximum_capacity', models.IntegerField()),
('supplier_price', models.DecimalField(decimal_places=2, max_digits=10)),
('lead_time_days', models.IntegerField(blank=True, null=True)),
('created_at', models.DateTimeField(auto_now_add=True)),
('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='product.product')),
('warehouse', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='warehouse.warehouse')),
],
options={
'db_table': 'supplier_product',
'unique_together': {('supplier_id', 'product', 'warehouse')},
},
),
migrations.DeleteModel(
name='WarehouseSupplier',
),
]
Loading
Loading