Improve the inventory page
This commit is contained in:
@@ -156,8 +156,8 @@ class JWTHandler:
|
||||
Decode JWT token without verification (for inspection purposes)
|
||||
"""
|
||||
try:
|
||||
# Decode without verification
|
||||
payload = jwt.decode(token, options={"verify_signature": False})
|
||||
# Decode without verification - need to provide key but disable verification
|
||||
payload = jwt.decode(token, self.secret_key, algorithms=[self.algorithm], options={"verify_signature": False})
|
||||
return payload
|
||||
except Exception as e:
|
||||
logger.error(f"Token decoding failed: {e}")
|
||||
@@ -193,12 +193,12 @@ class JWTHandler:
|
||||
Useful for quick user identification
|
||||
"""
|
||||
try:
|
||||
payload = self.decode_token_unsafe(token)
|
||||
payload = self.decode_token_no_verify(token)
|
||||
if payload:
|
||||
return payload.get("user_id")
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to extract user ID from token: {e}")
|
||||
|
||||
|
||||
return None
|
||||
|
||||
def get_token_info(self, token: str) -> Dict[str, Any]:
|
||||
@@ -217,7 +217,7 @@ class JWTHandler:
|
||||
|
||||
try:
|
||||
# Try unsafe decode first
|
||||
payload = self.decode_token_unsafe(token)
|
||||
payload = self.decode_token_no_verify(token)
|
||||
if payload:
|
||||
info.update({
|
||||
"user_id": payload.get("user_id"),
|
||||
|
||||
123
shared/database/README.md
Normal file
123
shared/database/README.md
Normal file
@@ -0,0 +1,123 @@
|
||||
# Database Demo Data
|
||||
|
||||
This directory contains comprehensive demo data for the bakery inventory system.
|
||||
|
||||
## Files
|
||||
|
||||
### `demo_inventory_data.sql`
|
||||
Complete demo dataset that creates a realistic bakery inventory scenario. This file includes:
|
||||
|
||||
**Demo Configuration:**
|
||||
- Tenant ID: `c464fb3e-7af2-46e6-9e43-85318f34199a`
|
||||
- Demo User: `demo@panaderiasanpablo.com`
|
||||
- Bakery: "Panadería San Pablo - Demo"
|
||||
|
||||
**What's Included:**
|
||||
|
||||
1. **Raw Ingredients (16 items):**
|
||||
- Flours (Wheat, Whole wheat)
|
||||
- Yeasts (Fresh, Dry active)
|
||||
- Fats (Butter, Olive oil)
|
||||
- Dairy & Eggs (Milk, Fresh eggs)
|
||||
- Sugars (White, Brown)
|
||||
- Seasonings (Salt, Chocolate, Vanilla, Cinnamon)
|
||||
- Nuts & Fruits (Walnuts, Raisins)
|
||||
|
||||
2. **Finished Products (8 items):**
|
||||
- Croissants (with par-baked and fully-baked stages)
|
||||
- Breads (Whole wheat, Toasted)
|
||||
- Pastries (Napolitanas, Palmeras, Magdalenas)
|
||||
- Other products (Empanadas, Coffee with milk)
|
||||
|
||||
3. **Stock Lots with Diverse Scenarios:**
|
||||
- **Good Stock**: Normal levels, fresh products
|
||||
- **Low Stock**: Below threshold items (Yeast, Butter, Coffee)
|
||||
- **Critical Stock**: Items needing immediate attention
|
||||
- **Out of Stock**: Completely sold out (Napolitanas)
|
||||
- **Expired Stock**: Items past expiration date (Some eggs)
|
||||
- **Expires Soon**: Items expiring today/tomorrow (Milk, some croissants)
|
||||
- **Overstock**: Items with excess inventory (Sugar, Salt)
|
||||
|
||||
4. **Production Stages:**
|
||||
- `raw_ingredient`: Base materials
|
||||
- `par_baked`: Semi-finished products from central bakery
|
||||
- `fully_baked`: Ready-to-sell products
|
||||
|
||||
5. **Stock Movements History:**
|
||||
- **Purchases**: Raw material deliveries
|
||||
- **Production Use**: Materials consumed in production
|
||||
- **Transformations**: Par-baked to fully-baked conversions
|
||||
- **Sales**: Customer purchases
|
||||
- **Waste**: Expired/damaged products
|
||||
- **Reservations**: Items reserved for specific orders
|
||||
|
||||
## Usage
|
||||
|
||||
### Run the Demo Data Script
|
||||
|
||||
```sql
|
||||
-- Connect to your PostgreSQL database
|
||||
\i shared/database/demo_inventory_data.sql
|
||||
```
|
||||
|
||||
### Expected Results
|
||||
|
||||
The script will create:
|
||||
- **24 ingredients** (16 raw + 8 finished products)
|
||||
- **25+ stock lots** with different scenarios
|
||||
- **15+ stock movements** showing transaction history
|
||||
- **Summary reports** showing inventory status
|
||||
|
||||
### Demo Scenarios Included
|
||||
|
||||
1. **Critical Alerts Testing:**
|
||||
- Expired eggs (past expiration date)
|
||||
- Low stock yeast (below 1.0kg threshold)
|
||||
- Milk expiring today
|
||||
- Out of stock napolitanas
|
||||
|
||||
2. **Production Workflow:**
|
||||
- Par-baked croissants ready for final baking
|
||||
- Fresh products baked this morning
|
||||
- Reserved stock for afternoon production
|
||||
|
||||
3. **Sales Patterns:**
|
||||
- Popular items sold out (napolitanas)
|
||||
- Steady sales of bread and pastries
|
||||
- Morning rush reflected in stock levels
|
||||
|
||||
4. **Inventory Management:**
|
||||
- Multiple batches with different expiration dates
|
||||
- FIFO rotation scenarios
|
||||
- Waste tracking for expired items
|
||||
|
||||
|
||||
## Customization
|
||||
|
||||
To modify the demo for different scenarios, edit the variables at the top of `demo_inventory_data.sql`:
|
||||
|
||||
```sql
|
||||
-- Demo Configuration Variables
|
||||
demo_tenant_id UUID := 'your-tenant-id'::UUID;
|
||||
demo_user_email VARCHAR := 'your-demo-email@domain.com';
|
||||
demo_bakery_name VARCHAR := 'Your Bakery Name';
|
||||
```
|
||||
|
||||
## Testing Scenarios
|
||||
|
||||
The demo data is designed to test all major inventory features:
|
||||
|
||||
- ✅ Stock level calculations
|
||||
- ✅ Expiration date tracking
|
||||
- ✅ Low stock alerts
|
||||
- ✅ Out of stock handling
|
||||
- ✅ Multi-batch inventory
|
||||
- ✅ Production stage tracking
|
||||
- ✅ Movement history
|
||||
- ✅ Waste management
|
||||
- ✅ Reserved stock
|
||||
- ✅ Cost calculations
|
||||
- ✅ Storage location tracking
|
||||
- ✅ Quality status monitoring
|
||||
|
||||
Perfect for demos, development, and testing!
|
||||
659
shared/database/demo_inventory_data.sql
Normal file
659
shared/database/demo_inventory_data.sql
Normal file
@@ -0,0 +1,659 @@
|
||||
-- =====================================
|
||||
-- BAKERY INVENTORY DEMO DATA
|
||||
-- Comprehensive demo dataset for inventory system
|
||||
-- Includes: Demo user/tenant, ingredients, stock with lots, movements
|
||||
-- =====================================
|
||||
|
||||
-- Demo Configuration Variables
|
||||
-- These can be modified to create data for different demo scenarios
|
||||
DO $$
|
||||
DECLARE
|
||||
-- Demo User & Tenant Configuration
|
||||
demo_tenant_id UUID := 'c464fb3e-7af2-46e6-9e43-85318f34199a'::UUID;
|
||||
demo_user_email VARCHAR := 'demo@panaderiasanpablo.com';
|
||||
demo_user_name VARCHAR := 'Demo User - Panadería San Pablo';
|
||||
demo_bakery_name VARCHAR := 'Panadería San Pablo - Demo';
|
||||
|
||||
-- Ingredient IDs (will be generated)
|
||||
harina_trigo_id UUID;
|
||||
harina_integral_id UUID;
|
||||
levadura_fresca_id UUID;
|
||||
levadura_seca_id UUID;
|
||||
mantequilla_id UUID;
|
||||
aceite_oliva_id UUID;
|
||||
huevos_id UUID;
|
||||
leche_id UUID;
|
||||
azucar_blanca_id UUID;
|
||||
azucar_morena_id UUID;
|
||||
sal_id UUID;
|
||||
chocolate_id UUID;
|
||||
vainilla_id UUID;
|
||||
canela_id UUID;
|
||||
nueces_id UUID;
|
||||
pasas_id UUID;
|
||||
|
||||
-- Finished Product IDs
|
||||
croissant_id UUID;
|
||||
pan_integral_id UUID;
|
||||
napolitana_id UUID;
|
||||
palmera_id UUID;
|
||||
pan_tostado_id UUID;
|
||||
magdalena_id UUID;
|
||||
empanada_id UUID;
|
||||
cafe_con_leche_id UUID;
|
||||
|
||||
BEGIN
|
||||
-- ===========================================
|
||||
-- 1. SETUP DEMO TENANT AND USER
|
||||
-- ===========================================
|
||||
|
||||
RAISE NOTICE 'Setting up demo data for tenant: % (%)', demo_bakery_name, demo_tenant_id;
|
||||
|
||||
-- Clean existing demo data for this tenant
|
||||
DELETE FROM stock_movements WHERE tenant_id = demo_tenant_id;
|
||||
DELETE FROM stock WHERE tenant_id = demo_tenant_id;
|
||||
DELETE FROM ingredients WHERE tenant_id = demo_tenant_id;
|
||||
|
||||
-- ===========================================
|
||||
-- 2. RAW INGREDIENTS - COMPREHENSIVE BAKERY STOCK
|
||||
-- ===========================================
|
||||
|
||||
-- Generate ingredient IDs
|
||||
harina_trigo_id := gen_random_uuid();
|
||||
harina_integral_id := gen_random_uuid();
|
||||
levadura_fresca_id := gen_random_uuid();
|
||||
levadura_seca_id := gen_random_uuid();
|
||||
mantequilla_id := gen_random_uuid();
|
||||
aceite_oliva_id := gen_random_uuid();
|
||||
huevos_id := gen_random_uuid();
|
||||
leche_id := gen_random_uuid();
|
||||
azucar_blanca_id := gen_random_uuid();
|
||||
azucar_morena_id := gen_random_uuid();
|
||||
sal_id := gen_random_uuid();
|
||||
chocolate_id := gen_random_uuid();
|
||||
vainilla_id := gen_random_uuid();
|
||||
canela_id := gen_random_uuid();
|
||||
nueces_id := gen_random_uuid();
|
||||
pasas_id := gen_random_uuid();
|
||||
|
||||
-- Insert raw ingredients
|
||||
INSERT INTO ingredients (
|
||||
id, tenant_id, name, product_type, ingredient_category, product_category,
|
||||
unit_of_measure, low_stock_threshold, reorder_point, reorder_quantity,
|
||||
is_active, is_perishable, shelf_life_days, average_cost, brand,
|
||||
storage_instructions, created_at, updated_at
|
||||
) VALUES
|
||||
-- FLOURS
|
||||
(harina_trigo_id, demo_tenant_id, 'Harina de Trigo 000', 'INGREDIENT', 'FLOUR', NULL, 'KILOGRAMS', 25.0, 50.0, 200.0, true, false, 365, 2.50, 'Molinos del Valle', 'Almacenar en lugar seco', NOW(), NOW()),
|
||||
(harina_integral_id, demo_tenant_id, 'Harina Integral', 'INGREDIENT', 'FLOUR', NULL, 'KILOGRAMS', 15.0, 30.0, 100.0, true, false, 180, 3.20, 'Bio Natural', 'Almacenar en lugar seco', NOW(), NOW()),
|
||||
|
||||
-- YEASTS
|
||||
(levadura_fresca_id, demo_tenant_id, 'Levadura Fresca', 'INGREDIENT', 'YEAST', NULL, 'KILOGRAMS', 1.0, 2.5, 10.0, true, true, 7, 8.50, 'Levapan', 'Refrigerar entre 2-8°C', NOW(), NOW()),
|
||||
(levadura_seca_id, demo_tenant_id, 'Levadura Seca Activa', 'INGREDIENT', 'YEAST', NULL, 'KILOGRAMS', 0.5, 1.0, 5.0, true, false, 730, 12.00, 'Fleischmann', 'Lugar seco, temperatura ambiente', NOW(), NOW()),
|
||||
|
||||
-- FATS
|
||||
(mantequilla_id, demo_tenant_id, 'Mantequilla', 'INGREDIENT', 'FATS', NULL, 'KILOGRAMS', 3.0, 8.0, 25.0, true, true, 30, 6.80, 'La Serenísima', 'Refrigerar', NOW(), NOW()),
|
||||
(aceite_oliva_id, demo_tenant_id, 'Aceite de Oliva Extra Virgen', 'INGREDIENT', 'FATS', NULL, 'LITROS', 2.0, 5.0, 20.0, true, false, 730, 15.50, 'Cocinero', 'Lugar fresco y oscuro', NOW(), NOW()),
|
||||
|
||||
-- DAIRY & EGGS
|
||||
(huevos_id, demo_tenant_id, 'Huevos Frescos', 'INGREDIENT', 'EGGS', NULL, 'UNITS', 36, 60, 180, true, true, 21, 0.25, 'Granja San José', 'Refrigerar', NOW(), NOW()),
|
||||
(leche_id, demo_tenant_id, 'Leche Entera', 'INGREDIENT', 'DAIRY', NULL, 'LITROS', 5.0, 12.0, 50.0, true, true, 5, 1.80, 'La Serenísima', 'Refrigerar', NOW(), NOW()),
|
||||
|
||||
-- SUGARS
|
||||
(azucar_blanca_id, demo_tenant_id, 'Azúcar Blanca', 'INGREDIENT', 'SUGAR', NULL, 'KILOGRAMS', 8.0, 20.0, 100.0, true, false, 730, 1.20, 'Ledesma', 'Lugar seco', NOW(), NOW()),
|
||||
(azucar_morena_id, demo_tenant_id, 'Azúcar Morena', 'INGREDIENT', 'SUGAR', NULL, 'KILOGRAMS', 3.0, 8.0, 25.0, true, false, 365, 2.80, 'Orgánica', 'Lugar seco', NOW(), NOW()),
|
||||
|
||||
-- SALT & FLAVORINGS
|
||||
(sal_id, demo_tenant_id, 'Sal Fina', 'INGREDIENT', 'SALT', NULL, 'KILOGRAMS', 2.0, 5.0, 20.0, true, false, 1095, 0.80, 'Celusal', 'Lugar seco', NOW(), NOW()),
|
||||
(chocolate_id, demo_tenant_id, 'Chocolate Semiamargo', 'INGREDIENT', 'ADDITIVES', NULL, 'KILOGRAMS', 1.0, 3.0, 15.0, true, false, 365, 8.50, 'Águila', 'Lugar fresco', NOW(), NOW()),
|
||||
(vainilla_id, demo_tenant_id, 'Extracto de Vainilla', 'INGREDIENT', 'SPICES', NULL, 'MILLILITERS', 100, 250, 1000, true, false, 1095, 0.15, 'McCormick', 'Lugar fresco', NOW(), NOW()),
|
||||
(canela_id, demo_tenant_id, 'Canela en Polvo', 'INGREDIENT', 'SPICES', NULL, 'GRAMS', 50, 150, 500, true, false, 730, 0.08, 'Alicante', 'Lugar seco', NOW(), NOW()),
|
||||
|
||||
-- NUTS & FRUITS
|
||||
(nueces_id, demo_tenant_id, 'Nueces Peladas', 'INGREDIENT', 'ADDITIVES', NULL, 'KILOGRAMS', 0.5, 1.5, 8.0, true, false, 180, 12.00, 'Los Nogales', 'Lugar fresco y seco', NOW(), NOW()),
|
||||
(pasas_id, demo_tenant_id, 'Pasas de Uva', 'INGREDIENT', 'ADDITIVES', NULL, 'KILOGRAMS', 1.0, 2.0, 10.0, true, false, 365, 4.50, 'Mendoza Premium', 'Lugar seco', NOW(), NOW());
|
||||
|
||||
-- ===========================================
|
||||
-- 3. FINISHED PRODUCTS
|
||||
-- ===========================================
|
||||
|
||||
-- Generate finished product IDs
|
||||
croissant_id := gen_random_uuid();
|
||||
pan_integral_id := gen_random_uuid();
|
||||
napolitana_id := gen_random_uuid();
|
||||
palmera_id := gen_random_uuid();
|
||||
pan_tostado_id := gen_random_uuid();
|
||||
magdalena_id := gen_random_uuid();
|
||||
empanada_id := gen_random_uuid();
|
||||
cafe_con_leche_id := gen_random_uuid();
|
||||
|
||||
INSERT INTO ingredients (
|
||||
id, tenant_id, name, product_type, ingredient_category, product_category,
|
||||
unit_of_measure, low_stock_threshold, reorder_point, reorder_quantity,
|
||||
is_active, is_perishable, shelf_life_days, average_cost,
|
||||
created_at, updated_at
|
||||
) VALUES
|
||||
-- BAKERY PRODUCTS
|
||||
(croissant_id, demo_tenant_id, 'Croissant Clásico', 'FINISHED_PRODUCT', NULL, 'CROISSANTS', 'PIECES', 12, 30, 80, true, true, 1, 1.20, NOW(), NOW()),
|
||||
(pan_integral_id, demo_tenant_id, 'Pan Integral', 'FINISHED_PRODUCT', NULL, 'BREAD', 'PIECES', 8, 20, 50, true, true, 3, 2.50, NOW(), NOW()),
|
||||
(napolitana_id, demo_tenant_id, 'Napolitana de Chocolate', 'FINISHED_PRODUCT', NULL, 'PASTRIES', 'PIECES', 10, 25, 60, true, true, 2, 1.80, NOW(), NOW()),
|
||||
(palmera_id, demo_tenant_id, 'Palmera de Hojaldre', 'FINISHED_PRODUCT', NULL, 'PASTRIES', 'PIECES', 8, 20, 40, true, true, 2, 2.20, NOW(), NOW()),
|
||||
(pan_tostado_id, demo_tenant_id, 'Pan Tostado', 'FINISHED_PRODUCT', NULL, 'BREAD', 'PIECES', 15, 35, 80, true, true, 5, 1.50, NOW(), NOW()),
|
||||
(magdalena_id, demo_tenant_id, 'Magdalena de Vainilla', 'FINISHED_PRODUCT', NULL, 'PASTRIES', 'PIECES', 6, 18, 50, true, true, 3, 1.00, NOW(), NOW()),
|
||||
(empanada_id, demo_tenant_id, 'Empanada de Carne', 'FINISHED_PRODUCT', NULL, 'OTHER_PRODUCTS', 'PIECES', 5, 15, 40, true, true, 1, 3.50, NOW(), NOW()),
|
||||
(cafe_con_leche_id, demo_tenant_id, 'Café con Leche', 'FINISHED_PRODUCT', NULL, 'BEVERAGES', 'UNITS', 8, 20, 50, true, true, 1, 2.80, NOW(), NOW());
|
||||
|
||||
-- ===========================================
|
||||
-- 4. STOCK LOTS - DIVERSE SCENARIOS
|
||||
-- ===========================================
|
||||
|
||||
RAISE NOTICE 'Creating stock lots with diverse scenarios...';
|
||||
|
||||
-- RAW INGREDIENTS STOCK
|
||||
|
||||
-- HARINA DE TRIGO - Good stock with multiple lots
|
||||
INSERT INTO stock (
|
||||
id, tenant_id, ingredient_id, production_stage,
|
||||
current_quantity, reserved_quantity, available_quantity,
|
||||
batch_number, received_date, expiration_date,
|
||||
unit_cost, total_cost, storage_location, is_available, is_expired, quality_status,
|
||||
created_at, updated_at
|
||||
) VALUES
|
||||
(gen_random_uuid(), demo_tenant_id, harina_trigo_id, 'raw_ingredient',
|
||||
120.0, 15.0, 105.0, 'HARINA-TRI-20241201-001', NOW() - INTERVAL '5 days', NOW() + INTERVAL '360 days',
|
||||
2.50, 300.0, 'Almacén Principal - Estante A1', true, false, 'good', NOW(), NOW()),
|
||||
(gen_random_uuid(), demo_tenant_id, harina_trigo_id, 'raw_ingredient',
|
||||
80.0, 5.0, 75.0, 'HARINA-TRI-20241125-002', NOW() - INTERVAL '12 days', NOW() + INTERVAL '353 days',
|
||||
2.50, 200.0, 'Almacén Principal - Estante A2', true, false, 'good', NOW(), NOW());
|
||||
|
||||
-- HARINA INTEGRAL - Normal stock
|
||||
INSERT INTO stock (
|
||||
id, tenant_id, ingredient_id, production_stage,
|
||||
current_quantity, reserved_quantity, available_quantity,
|
||||
batch_number, received_date, expiration_date,
|
||||
unit_cost, total_cost, storage_location, is_available, is_expired, quality_status,
|
||||
created_at, updated_at
|
||||
) VALUES
|
||||
(gen_random_uuid(), demo_tenant_id, harina_integral_id, 'raw_ingredient',
|
||||
45.0, 8.0, 37.0, 'HARINA-INT-20241128-001', NOW() - INTERVAL '9 days', NOW() + INTERVAL '171 days',
|
||||
3.20, 144.0, 'Almacén Principal - Estante A3', true, false, 'good', NOW(), NOW());
|
||||
|
||||
-- LEVADURA FRESCA - CRITICAL LOW (below threshold, expires soon)
|
||||
INSERT INTO stock (
|
||||
id, tenant_id, ingredient_id, production_stage,
|
||||
current_quantity, reserved_quantity, available_quantity,
|
||||
batch_number, received_date, expiration_date,
|
||||
unit_cost, total_cost, storage_location, is_available, is_expired, quality_status,
|
||||
created_at, updated_at
|
||||
) VALUES
|
||||
(gen_random_uuid(), demo_tenant_id, levadura_fresca_id, 'raw_ingredient',
|
||||
0.8, 0.3, 0.5, 'LEVAD-FRE-20241204-001', NOW() - INTERVAL '2 days', NOW() + INTERVAL '5 days',
|
||||
8.50, 6.8, 'Cámara Fría - Nivel 2', true, false, 'good', NOW(), NOW());
|
||||
|
||||
-- LEVADURA SECA - Good stock
|
||||
INSERT INTO stock (
|
||||
id, tenant_id, ingredient_id, production_stage,
|
||||
current_quantity, reserved_quantity, available_quantity,
|
||||
batch_number, received_date, expiration_date,
|
||||
unit_cost, total_cost, storage_location, is_available, is_expired, quality_status,
|
||||
created_at, updated_at
|
||||
) VALUES
|
||||
(gen_random_uuid(), demo_tenant_id, levadura_seca_id, 'raw_ingredient',
|
||||
2.5, 0.0, 2.5, 'LEVAD-SEC-20241115-001', NOW() - INTERVAL '22 days', NOW() + INTERVAL '708 days',
|
||||
12.00, 30.0, 'Almacén Principal - Estante B1', true, false, 'good', NOW(), NOW());
|
||||
|
||||
-- MANTEQUILLA - Low stock, expires soon
|
||||
INSERT INTO stock (
|
||||
id, tenant_id, ingredient_id, production_stage,
|
||||
current_quantity, reserved_quantity, available_quantity,
|
||||
batch_number, received_date, expiration_date,
|
||||
unit_cost, total_cost, storage_location, is_available, is_expired, quality_status,
|
||||
created_at, updated_at
|
||||
) VALUES
|
||||
(gen_random_uuid(), demo_tenant_id, mantequilla_id, 'raw_ingredient',
|
||||
2.5, 0.5, 2.0, 'MANT-20241203-001', NOW() - INTERVAL '3 days', NOW() + INTERVAL '27 days',
|
||||
6.80, 17.0, 'Cámara Fría - Nivel 1', true, false, 'good', NOW(), NOW());
|
||||
|
||||
-- ACEITE DE OLIVA - Good stock
|
||||
INSERT INTO stock (
|
||||
id, tenant_id, ingredient_id, production_stage,
|
||||
current_quantity, reserved_quantity, available_quantity,
|
||||
batch_number, received_date, expiration_date,
|
||||
unit_cost, total_cost, storage_location, is_available, is_expired, quality_status,
|
||||
created_at, updated_at
|
||||
) VALUES
|
||||
(gen_random_uuid(), demo_tenant_id, aceite_oliva_id, 'raw_ingredient',
|
||||
12.0, 2.0, 10.0, 'ACEITE-20241120-001', NOW() - INTERVAL '17 days', NOW() + INTERVAL '713 days',
|
||||
15.50, 186.0, 'Almacén Principal - Estante C1', true, false, 'good', NOW(), NOW());
|
||||
|
||||
-- HUEVOS - Multiple lots, one EXPIRED
|
||||
INSERT INTO stock (
|
||||
id, tenant_id, ingredient_id, production_stage,
|
||||
current_quantity, reserved_quantity, available_quantity,
|
||||
batch_number, received_date, expiration_date,
|
||||
unit_cost, total_cost, storage_location, is_available, is_expired, quality_status,
|
||||
created_at, updated_at
|
||||
) VALUES
|
||||
-- Fresh eggs
|
||||
(gen_random_uuid(), demo_tenant_id, huevos_id, 'raw_ingredient',
|
||||
60, 6, 54, 'HUEVOS-20241205-001', NOW() - INTERVAL '1 day', NOW() + INTERVAL '20 days',
|
||||
0.25, 15.0, 'Cámara Fría - Cajón 1', true, false, 'good', NOW(), NOW()),
|
||||
-- EXPIRED eggs - should trigger alert
|
||||
(gen_random_uuid(), demo_tenant_id, huevos_id, 'raw_ingredient',
|
||||
18, 0, 18, 'HUEVOS-20241115-002', NOW() - INTERVAL '22 days', NOW() - INTERVAL '1 day',
|
||||
0.25, 4.5, 'Cámara Fría - Cajón 2', true, true, 'expired', NOW(), NOW());
|
||||
|
||||
-- LECHE - Expires TODAY (critical)
|
||||
INSERT INTO stock (
|
||||
id, tenant_id, ingredient_id, production_stage,
|
||||
current_quantity, reserved_quantity, available_quantity,
|
||||
batch_number, received_date, expiration_date,
|
||||
unit_cost, total_cost, storage_location, is_available, is_expired, quality_status,
|
||||
created_at, updated_at
|
||||
) VALUES
|
||||
(gen_random_uuid(), demo_tenant_id, leche_id, 'raw_ingredient',
|
||||
8.0, 1.0, 7.0, 'LECHE-20241202-001', NOW() - INTERVAL '4 days', NOW() + INTERVAL '12 hours',
|
||||
1.80, 14.4, 'Cámara Fría - Nivel 3', true, false, 'expires_today', NOW(), NOW());
|
||||
|
||||
-- AZUCAR BLANCA - Overstock
|
||||
INSERT INTO stock (
|
||||
id, tenant_id, ingredient_id, production_stage,
|
||||
current_quantity, reserved_quantity, available_quantity,
|
||||
batch_number, received_date, expiration_date,
|
||||
unit_cost, total_cost, storage_location, is_available, is_expired, quality_status,
|
||||
created_at, updated_at
|
||||
) VALUES
|
||||
(gen_random_uuid(), demo_tenant_id, azucar_blanca_id, 'raw_ingredient',
|
||||
150.0, 10.0, 140.0, 'AZUC-BLA-20241110-001', NOW() - INTERVAL '27 days', NOW() + INTERVAL '703 days',
|
||||
1.20, 180.0, 'Almacén Principal - Estante D1', true, false, 'good', NOW(), NOW());
|
||||
|
||||
-- OTHER INGREDIENTS - Various scenarios
|
||||
INSERT INTO stock (
|
||||
id, tenant_id, ingredient_id, production_stage,
|
||||
current_quantity, reserved_quantity, available_quantity,
|
||||
batch_number, received_date, expiration_date,
|
||||
unit_cost, total_cost, storage_location, is_available, is_expired, quality_status,
|
||||
created_at, updated_at
|
||||
) VALUES
|
||||
-- Azúcar morena - Good
|
||||
(gen_random_uuid(), demo_tenant_id, azucar_morena_id, 'raw_ingredient',
|
||||
15.0, 2.0, 13.0, 'AZUC-MOR-20241125-001', NOW() - INTERVAL '12 days', NOW() + INTERVAL '353 days',
|
||||
2.80, 42.0, 'Almacén Principal - Estante D2', true, false, 'good', NOW(), NOW()),
|
||||
-- Sal - Overstock
|
||||
(gen_random_uuid(), demo_tenant_id, sal_id, 'raw_ingredient',
|
||||
25.0, 1.0, 24.0, 'SAL-20240915-001', NOW() - INTERVAL '82 days', NOW() + INTERVAL '1013 days',
|
||||
0.80, 20.0, 'Almacén Principal - Estante E1', true, false, 'good', NOW(), NOW()),
|
||||
-- Chocolate - Normal
|
||||
(gen_random_uuid(), demo_tenant_id, chocolate_id, 'raw_ingredient',
|
||||
4.5, 0.5, 4.0, 'CHOC-20241201-001', NOW() - INTERVAL '5 days', NOW() + INTERVAL '360 days',
|
||||
8.50, 38.25, 'Almacén Principal - Estante F1', true, false, 'good', NOW(), NOW());
|
||||
|
||||
-- ===========================================
|
||||
-- 5. FINISHED PRODUCTS STOCK - REALISTIC BAKERY SCENARIOS
|
||||
-- ===========================================
|
||||
|
||||
-- CROISSANTS - Central bakery model with different stages
|
||||
INSERT INTO stock (
|
||||
id, tenant_id, ingredient_id, production_stage,
|
||||
current_quantity, reserved_quantity, available_quantity,
|
||||
batch_number, received_date, expiration_date, original_expiration_date,
|
||||
unit_cost, total_cost, storage_location, is_available, is_expired, quality_status,
|
||||
created_at, updated_at
|
||||
) VALUES
|
||||
-- Par-baked croissants (frozen, good stock)
|
||||
(gen_random_uuid(), demo_tenant_id, croissant_id, 'par_baked',
|
||||
75, 0, 75, 'CROIS-PAR-20241205-001', NOW() - INTERVAL '1 day', NOW() + INTERVAL '4 days', NOW() + INTERVAL '4 days',
|
||||
0.85, 63.75, 'Congelador - Sección A', true, false, 'good', NOW(), NOW()),
|
||||
-- Par-baked croissants (older batch, some reserved)
|
||||
(gen_random_uuid(), demo_tenant_id, croissant_id, 'par_baked',
|
||||
40, 15, 25, 'CROIS-PAR-20241203-002', NOW() - INTERVAL '3 days', NOW() + INTERVAL '2 days', NOW() + INTERVAL '2 days',
|
||||
0.85, 34.0, 'Congelador - Sección B', true, false, 'good', NOW(), NOW()),
|
||||
-- Fresh croissants (baked this morning)
|
||||
(gen_random_uuid(), demo_tenant_id, croissant_id, 'fully_baked',
|
||||
35, 5, 30, 'CROIS-FRESH-20241206-001', NOW() - INTERVAL '4 hours', NOW() + INTERVAL '20 hours',
|
||||
1.20, 42.0, 'Vitrina Principal - Nivel 1', true, false, 'good', NOW(), NOW()),
|
||||
-- Croissants from yesterday (expires soon, low stock)
|
||||
(gen_random_uuid(), demo_tenant_id, croissant_id, 'fully_baked',
|
||||
8, 0, 8, 'CROIS-FRESH-20241205-002', NOW() - INTERVAL '28 hours', NOW() + INTERVAL '8 hours',
|
||||
1.20, 9.6, 'Vitrina Principal - Nivel 2', true, false, 'expires_today', NOW(), NOW());
|
||||
|
||||
-- PAN INTEGRAL - Different batches
|
||||
INSERT INTO stock (
|
||||
id, tenant_id, ingredient_id, production_stage,
|
||||
current_quantity, reserved_quantity, available_quantity,
|
||||
batch_number, received_date, expiration_date,
|
||||
unit_cost, total_cost, storage_location, is_available, is_expired, quality_status,
|
||||
created_at, updated_at
|
||||
) VALUES
|
||||
-- Fresh bread
|
||||
(gen_random_uuid(), demo_tenant_id, pan_integral_id, 'fully_baked',
|
||||
25, 3, 22, 'PAN-INT-20241206-001', NOW() - INTERVAL '6 hours', NOW() + INTERVAL '66 hours',
|
||||
2.50, 62.5, 'Estantería Pan - Nivel 1', true, false, 'good', NOW(), NOW()),
|
||||
-- Day-old bread
|
||||
(gen_random_uuid(), demo_tenant_id, pan_integral_id, 'fully_baked',
|
||||
12, 1, 11, 'PAN-INT-20241205-002', NOW() - INTERVAL '30 hours', NOW() + INTERVAL '42 hours',
|
||||
2.50, 30.0, 'Estantería Pan - Nivel 2', true, false, 'good', NOW(), NOW());
|
||||
|
||||
-- NAPOLITANAS - OUT OF STOCK (sold out scenario)
|
||||
INSERT INTO stock (
|
||||
id, tenant_id, ingredient_id, production_stage,
|
||||
current_quantity, reserved_quantity, available_quantity,
|
||||
batch_number, received_date, expiration_date,
|
||||
unit_cost, total_cost, storage_location, is_available, is_expired, quality_status,
|
||||
created_at, updated_at
|
||||
) VALUES
|
||||
(gen_random_uuid(), demo_tenant_id, napolitana_id, 'fully_baked',
|
||||
0, 0, 0, 'NAPO-20241206-001', NOW() - INTERVAL '6 hours', NOW() + INTERVAL '42 hours',
|
||||
1.80, 0.0, 'Vitrina Pasteles - Nivel 1', false, false, 'sold_out', NOW(), NOW());
|
||||
|
||||
-- PALMERAS - Good stock
|
||||
INSERT INTO stock (
|
||||
id, tenant_id, ingredient_id, production_stage,
|
||||
current_quantity, reserved_quantity, available_quantity,
|
||||
batch_number, received_date, expiration_date,
|
||||
unit_cost, total_cost, storage_location, is_available, is_expired, quality_status,
|
||||
created_at, updated_at
|
||||
) VALUES
|
||||
(gen_random_uuid(), demo_tenant_id, palmera_id, 'fully_baked',
|
||||
28, 4, 24, 'PALM-20241206-001', NOW() - INTERVAL '3 hours', NOW() + INTERVAL '45 hours',
|
||||
2.20, 61.6, 'Vitrina Pasteles - Nivel 2', true, false, 'good', NOW(), NOW());
|
||||
|
||||
-- PAN TOSTADO - Multiple batches
|
||||
INSERT INTO stock (
|
||||
id, tenant_id, ingredient_id, production_stage,
|
||||
current_quantity, reserved_quantity, available_quantity,
|
||||
batch_number, received_date, expiration_date,
|
||||
unit_cost, total_cost, storage_location, is_available, is_expired, quality_status,
|
||||
created_at, updated_at
|
||||
) VALUES
|
||||
-- Fresh batch
|
||||
(gen_random_uuid(), demo_tenant_id, pan_tostado_id, 'fully_baked',
|
||||
42, 6, 36, 'PAN-TOS-20241206-001', NOW() - INTERVAL '2 hours', NOW() + INTERVAL '118 hours',
|
||||
1.50, 63.0, 'Estantería Pan Tostado - A', true, false, 'good', NOW(), NOW()),
|
||||
-- Older batch
|
||||
(gen_random_uuid(), demo_tenant_id, pan_tostado_id, 'fully_baked',
|
||||
18, 2, 16, 'PAN-TOS-20241204-002', NOW() - INTERVAL '26 hours', NOW() + INTERVAL '94 hours',
|
||||
1.50, 27.0, 'Estantería Pan Tostado - B', true, false, 'good', NOW(), NOW());
|
||||
|
||||
-- MAGDALENAS - Low stock
|
||||
INSERT INTO stock (
|
||||
id, tenant_id, ingredient_id, production_stage,
|
||||
current_quantity, reserved_quantity, available_quantity,
|
||||
batch_number, received_date, expiration_date,
|
||||
unit_cost, total_cost, storage_location, is_available, is_expired, quality_status,
|
||||
created_at, updated_at
|
||||
) VALUES
|
||||
(gen_random_uuid(), demo_tenant_id, magdalena_id, 'fully_baked',
|
||||
5, 1, 4, 'MAGD-20241206-001', NOW() - INTERVAL '5 hours', NOW() + INTERVAL '67 hours',
|
||||
1.00, 5.0, 'Vitrina Pasteles - Nivel 3', true, false, 'good', NOW(), NOW());
|
||||
|
||||
-- EMPANADAS - Fresh, good stock
|
||||
INSERT INTO stock (
|
||||
id, tenant_id, ingredient_id, production_stage,
|
||||
current_quantity, reserved_quantity, available_quantity,
|
||||
batch_number, received_date, expiration_date,
|
||||
unit_cost, total_cost, storage_location, is_available, is_expired, quality_status,
|
||||
created_at, updated_at
|
||||
) VALUES
|
||||
(gen_random_uuid(), demo_tenant_id, empanada_id, 'fully_baked',
|
||||
20, 3, 17, 'EMP-20241206-001', NOW() - INTERVAL '1 hour', NOW() + INTERVAL '23 hours',
|
||||
3.50, 70.0, 'Vitrina Empanadas', true, false, 'good', NOW(), NOW());
|
||||
|
||||
-- CAFÉ CON LECHE - Low stock
|
||||
INSERT INTO stock (
|
||||
id, tenant_id, ingredient_id, production_stage,
|
||||
current_quantity, reserved_quantity, available_quantity,
|
||||
batch_number, received_date, expiration_date,
|
||||
unit_cost, total_cost, storage_location, is_available, is_expired, quality_status,
|
||||
created_at, updated_at
|
||||
) VALUES
|
||||
(gen_random_uuid(), demo_tenant_id, cafe_con_leche_id, 'fully_baked',
|
||||
9, 1, 8, 'CAFE-20241206-001', NOW() - INTERVAL '2 hours', NOW() + INTERVAL '22 hours',
|
||||
2.80, 25.2, 'Máquina de Café', true, false, 'good', NOW(), NOW());
|
||||
|
||||
RAISE NOTICE 'Stock lots created successfully with diverse scenarios';
|
||||
|
||||
END $$;
|
||||
|
||||
-- ===========================================
|
||||
-- 6. STOCK MOVEMENTS - REALISTIC TRANSACTION HISTORY
|
||||
-- ===========================================
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
demo_tenant_id UUID := 'c464fb3e-7af2-46e6-9e43-85318f34199a'::UUID;
|
||||
movement_record RECORD;
|
||||
BEGIN
|
||||
RAISE NOTICE 'Creating realistic stock movement history...';
|
||||
|
||||
-- PURCHASES - Raw materials received
|
||||
INSERT INTO stock_movements (
|
||||
id, tenant_id, ingredient_id, stock_id, movement_type, quantity,
|
||||
unit_cost, total_cost, quantity_before, quantity_after,
|
||||
reference_number, notes, movement_date, created_at, created_by
|
||||
)
|
||||
SELECT
|
||||
gen_random_uuid(),
|
||||
demo_tenant_id,
|
||||
s.ingredient_id,
|
||||
s.id,
|
||||
'PURCHASE',
|
||||
s.current_quantity + s.reserved_quantity,
|
||||
s.unit_cost,
|
||||
s.total_cost,
|
||||
0.0,
|
||||
s.current_quantity + s.reserved_quantity,
|
||||
'PO-' || TO_CHAR(s.received_date, 'YYYY-MM-DD-') || LPAD((ROW_NUMBER() OVER (ORDER BY s.received_date))::text, 3, '0'),
|
||||
CASE
|
||||
WHEN s.production_stage = 'raw_ingredient' THEN 'Recepción de materia prima - ' || i.name
|
||||
ELSE 'Producción interna - ' || i.name
|
||||
END,
|
||||
s.received_date,
|
||||
s.received_date,
|
||||
NULL
|
||||
FROM stock s
|
||||
JOIN ingredients i ON s.ingredient_id = i.id
|
||||
WHERE s.tenant_id = demo_tenant_id
|
||||
AND s.production_stage = 'raw_ingredient';
|
||||
|
||||
-- PRODUCTION USE - Raw materials consumed
|
||||
INSERT INTO stock_movements (
|
||||
id, tenant_id, ingredient_id, stock_id, movement_type, quantity,
|
||||
unit_cost, total_cost, quantity_before, quantity_after,
|
||||
reference_number, notes, movement_date, created_at, created_by
|
||||
) VALUES
|
||||
-- Flour used for daily production
|
||||
(gen_random_uuid(), demo_tenant_id,
|
||||
(SELECT id FROM ingredients WHERE name = 'Harina de Trigo 000' AND tenant_id = demo_tenant_id),
|
||||
(SELECT id FROM stock WHERE ingredient_id = (SELECT id FROM ingredients WHERE name = 'Harina de Trigo 000' AND tenant_id = demo_tenant_id) LIMIT 1),
|
||||
'PRODUCTION_USE', -35.0, 2.50, -87.5, 155.0, 120.0,
|
||||
'PROD-20241206-001', 'Consumo para producción diaria de pan y pasteles',
|
||||
NOW() - INTERVAL '6 hours', NOW() - INTERVAL '6 hours', NULL),
|
||||
|
||||
-- Yeast used (contributing to low stock)
|
||||
(gen_random_uuid(), demo_tenant_id,
|
||||
(SELECT id FROM ingredients WHERE name = 'Levadura Fresca' AND tenant_id = demo_tenant_id),
|
||||
(SELECT id FROM stock WHERE ingredient_id = (SELECT id FROM ingredients WHERE name = 'Levadura Fresca' AND tenant_id = demo_tenant_id) LIMIT 1),
|
||||
'PRODUCTION_USE', -2.2, 8.50, -18.7, 3.0, 0.8,
|
||||
'PROD-20241206-002', 'Consumo para fermentación - stock crítico',
|
||||
NOW() - INTERVAL '4 hours', NOW() - INTERVAL '4 hours', NULL),
|
||||
|
||||
-- Butter used
|
||||
(gen_random_uuid(), demo_tenant_id,
|
||||
(SELECT id FROM ingredients WHERE name = 'Mantequilla' AND tenant_id = demo_tenant_id),
|
||||
(SELECT id FROM stock WHERE ingredient_id = (SELECT id FROM ingredients WHERE name = 'Mantequilla' AND tenant_id = demo_tenant_id) LIMIT 1),
|
||||
'PRODUCTION_USE', -1.5, 6.80, -10.2, 4.0, 2.5,
|
||||
'PROD-20241206-003', 'Consumo para croissants y pasteles',
|
||||
NOW() - INTERVAL '5 hours', NOW() - INTERVAL '5 hours', NULL);
|
||||
|
||||
-- TRANSFORMATIONS - Par-baked to fully baked
|
||||
INSERT INTO stock_movements (
|
||||
id, tenant_id, ingredient_id, stock_id, movement_type, quantity,
|
||||
unit_cost, total_cost, quantity_before, quantity_after,
|
||||
reference_number, notes, movement_date, created_at, created_by
|
||||
) VALUES
|
||||
-- Morning croissant batch
|
||||
(gen_random_uuid(), demo_tenant_id,
|
||||
(SELECT id FROM ingredients WHERE name = 'Croissant Clásico' AND tenant_id = demo_tenant_id),
|
||||
(SELECT id FROM stock WHERE ingredient_id = (SELECT id FROM ingredients WHERE name = 'Croissant Clásico' AND tenant_id = demo_tenant_id) AND production_stage = 'fully_baked' AND batch_number LIKE 'CROIS-FRESH-20241206%'),
|
||||
'PRODUCTION_USE', 35.0, 1.20, 42.0, 0.0, 35.0,
|
||||
'TRANS-20241206-001', 'Horneado final de croissants congelados - lote mañana',
|
||||
NOW() - INTERVAL '4 hours', NOW() - INTERVAL '4 hours', NULL);
|
||||
|
||||
-- SALES - Products sold to customers
|
||||
INSERT INTO stock_movements (
|
||||
id, tenant_id, ingredient_id, stock_id, movement_type, quantity,
|
||||
unit_cost, total_cost, quantity_before, quantity_after,
|
||||
reference_number, notes, movement_date, created_at, created_by
|
||||
) VALUES
|
||||
-- Napolitanas sold out completely
|
||||
(gen_random_uuid(), demo_tenant_id,
|
||||
(SELECT id FROM ingredients WHERE name = 'Napolitana de Chocolate' AND tenant_id = demo_tenant_id),
|
||||
(SELECT id FROM stock WHERE ingredient_id = (SELECT id FROM ingredients WHERE name = 'Napolitana de Chocolate' AND tenant_id = demo_tenant_id)),
|
||||
'SALE', -30.0, 1.80, -54.0, 30.0, 0.0,
|
||||
'SALE-20241206-001', 'Venta completa - napolitanas muy populares hoy',
|
||||
NOW() - INTERVAL '2 hours', NOW() - INTERVAL '2 hours', NULL),
|
||||
|
||||
-- Croissant sales
|
||||
(gen_random_uuid(), demo_tenant_id,
|
||||
(SELECT id FROM ingredients WHERE name = 'Croissant Clásico' AND tenant_id = demo_tenant_id),
|
||||
(SELECT id FROM stock WHERE ingredient_id = (SELECT id FROM ingredients WHERE name = 'Croissant Clásico' AND tenant_id = demo_tenant_id) AND production_stage = 'fully_baked' AND batch_number LIKE 'CROIS-FRESH-20241206%'),
|
||||
'SALE', -5.0, 1.20, -6.0, 40.0, 35.0,
|
||||
'SALE-20241206-002', 'Ventas matutinas de croissants frescos',
|
||||
NOW() - INTERVAL '3 hours', NOW() - INTERVAL '3 hours', NULL),
|
||||
|
||||
-- Palmera sales
|
||||
(gen_random_uuid(), demo_tenant_id,
|
||||
(SELECT id FROM ingredients WHERE name = 'Palmera de Hojaldre' AND tenant_id = demo_tenant_id),
|
||||
(SELECT id FROM stock WHERE ingredient_id = (SELECT id FROM ingredients WHERE name = 'Palmera de Hojaldre' AND tenant_id = demo_tenant_id)),
|
||||
'SALE', -4.0, 2.20, -8.8, 32.0, 28.0,
|
||||
'SALE-20241206-003', 'Ventas de palmeras - desayuno',
|
||||
NOW() - INTERVAL '2 hours', NOW() - INTERVAL '2 hours', NULL);
|
||||
|
||||
-- WASTE - Expired or damaged products
|
||||
INSERT INTO stock_movements (
|
||||
id, tenant_id, ingredient_id, stock_id, movement_type, quantity,
|
||||
unit_cost, total_cost, quantity_before, quantity_after,
|
||||
reference_number, notes, movement_date, created_at, created_by
|
||||
) VALUES
|
||||
-- Expired eggs marked as waste
|
||||
(gen_random_uuid(), demo_tenant_id,
|
||||
(SELECT id FROM ingredients WHERE name = 'Huevos Frescos' AND tenant_id = demo_tenant_id),
|
||||
(SELECT id FROM stock WHERE ingredient_id = (SELECT id FROM ingredients WHERE name = 'Huevos Frescos' AND tenant_id = demo_tenant_id) AND is_expired = true),
|
||||
'WASTE', -18.0, 0.25, -4.5, 18.0, 0.0,
|
||||
'WASTE-20241206-001', 'Huevos vencidos - descarte por caducidad',
|
||||
NOW() - INTERVAL '1 hour', NOW() - INTERVAL '1 hour', NULL);
|
||||
|
||||
-- RESERVATIONS - Products reserved for specific orders
|
||||
INSERT INTO stock_movements (
|
||||
id, tenant_id, ingredient_id, stock_id, movement_type, quantity,
|
||||
unit_cost, total_cost, quantity_before, quantity_after,
|
||||
reference_number, notes, movement_date, created_at, created_by
|
||||
) VALUES
|
||||
-- Croissants reserved for afternoon baking
|
||||
(gen_random_uuid(), demo_tenant_id,
|
||||
(SELECT id FROM ingredients WHERE name = 'Croissant Clásico' AND tenant_id = demo_tenant_id),
|
||||
(SELECT id FROM stock WHERE ingredient_id = (SELECT id FROM ingredients WHERE name = 'Croissant Clásico' AND tenant_id = demo_tenant_id) AND production_stage = 'par_baked' AND batch_number LIKE 'CROIS-PAR-20241203%'),
|
||||
'RESERVATION', -15.0, 0.85, -12.75, 40.0, 25.0,
|
||||
'RESER-20241206-001', 'Reserva para horneado de la tarde - pedido especial',
|
||||
NOW() - INTERVAL '30 minutes', NOW() - INTERVAL '30 minutes', NULL);
|
||||
|
||||
RAISE NOTICE 'Stock movements history created successfully';
|
||||
|
||||
END $$;
|
||||
|
||||
-- ===========================================
|
||||
-- 7. SUMMARY REPORTS
|
||||
-- ===========================================
|
||||
|
||||
\echo ''
|
||||
\echo '========================================='
|
||||
\echo 'DEMO INVENTORY DATA SUMMARY'
|
||||
\echo '========================================='
|
||||
|
||||
SELECT 'INGREDIENTS OVERVIEW' as report_section;
|
||||
SELECT
|
||||
product_type,
|
||||
COALESCE(ingredient_category::text, product_category::text, 'N/A') as category,
|
||||
COUNT(*) as total_items,
|
||||
COUNT(CASE WHEN is_active THEN 1 END) as active_items
|
||||
FROM ingredients
|
||||
WHERE tenant_id = 'c464fb3e-7af2-46e6-9e43-85318f34199a'::UUID
|
||||
GROUP BY product_type, COALESCE(ingredient_category::text, product_category::text, 'N/A')
|
||||
ORDER BY product_type, category;
|
||||
|
||||
\echo ''
|
||||
SELECT 'STOCK SUMMARY BY STAGE' as report_section;
|
||||
SELECT
|
||||
production_stage,
|
||||
COUNT(*) as total_lots,
|
||||
SUM(current_quantity) as total_quantity,
|
||||
SUM(available_quantity) as available_quantity,
|
||||
SUM(reserved_quantity) as reserved_quantity,
|
||||
ROUND(SUM(total_cost), 2) as total_value
|
||||
FROM stock
|
||||
WHERE tenant_id = 'c464fb3e-7af2-46e6-9e43-85318f34199a'::UUID
|
||||
GROUP BY production_stage
|
||||
ORDER BY production_stage;
|
||||
|
||||
\echo ''
|
||||
SELECT 'CRITICAL STOCK ALERTS' as report_section;
|
||||
SELECT
|
||||
i.name,
|
||||
s.production_stage,
|
||||
s.current_quantity,
|
||||
s.available_quantity,
|
||||
i.low_stock_threshold,
|
||||
s.batch_number,
|
||||
s.expiration_date,
|
||||
CASE
|
||||
WHEN s.available_quantity = 0 THEN 'OUT_OF_STOCK'
|
||||
WHEN s.is_expired THEN 'EXPIRED'
|
||||
WHEN s.expiration_date <= NOW() + INTERVAL '24 hours' THEN 'EXPIRES_SOON'
|
||||
WHEN s.available_quantity <= i.low_stock_threshold THEN 'LOW_STOCK'
|
||||
ELSE 'OK'
|
||||
END as alert_status,
|
||||
s.storage_location
|
||||
FROM stock s
|
||||
JOIN ingredients i ON s.ingredient_id = i.id
|
||||
WHERE s.tenant_id = 'c464fb3e-7af2-46e6-9e43-85318f34199a'::UUID
|
||||
AND (
|
||||
s.available_quantity = 0
|
||||
OR s.is_expired
|
||||
OR s.expiration_date <= NOW() + INTERVAL '48 hours'
|
||||
OR s.available_quantity <= i.low_stock_threshold
|
||||
)
|
||||
ORDER BY
|
||||
CASE
|
||||
WHEN s.available_quantity = 0 THEN 1
|
||||
WHEN s.is_expired THEN 2
|
||||
WHEN s.expiration_date <= NOW() + INTERVAL '24 hours' THEN 3
|
||||
WHEN s.available_quantity <= i.low_stock_threshold THEN 4
|
||||
ELSE 5
|
||||
END,
|
||||
s.expiration_date ASC;
|
||||
|
||||
\echo ''
|
||||
SELECT 'MOVEMENT ACTIVITY (Last 24 hours)' as report_section;
|
||||
SELECT
|
||||
i.name,
|
||||
sm.movement_type,
|
||||
ABS(sm.quantity) as quantity,
|
||||
sm.reference_number,
|
||||
sm.notes,
|
||||
sm.movement_date
|
||||
FROM stock_movements sm
|
||||
JOIN ingredients i ON sm.ingredient_id = i.id
|
||||
WHERE sm.tenant_id = 'c464fb3e-7af2-46e6-9e43-85318f34199a'::UUID
|
||||
AND sm.movement_date >= NOW() - INTERVAL '24 hours'
|
||||
ORDER BY sm.movement_date DESC
|
||||
LIMIT 15;
|
||||
|
||||
\echo ''
|
||||
\echo '========================================='
|
||||
\echo 'DEMO DATA CREATION COMPLETED SUCCESSFULLY'
|
||||
\echo 'Tenant ID: c464fb3e-7af2-46e6-9e43-85318f34199a'
|
||||
\echo 'Total Ingredients: ' || (SELECT COUNT(*) FROM ingredients WHERE tenant_id = 'c464fb3e-7af2-46e6-9e43-85318f34199a'::UUID)::text
|
||||
\echo 'Total Stock Lots: ' || (SELECT COUNT(*) FROM stock WHERE tenant_id = 'c464fb3e-7af2-46e6-9e43-85318f34199a'::UUID)::text
|
||||
\echo 'Total Movements: ' || (SELECT COUNT(*) FROM stock_movements WHERE tenant_id = 'c464fb3e-7af2-46e6-9e43-85318f34199a'::UUID)::text
|
||||
\echo '========================================='
|
||||
Reference in New Issue
Block a user