@@ -59,12 +59,12 @@
| {{ item.quantity_available }} |
- {{ item.quantity_needed - item.quantity_available }} units short
+ {{ item.quantity_needed - item.quantity_available }} {{ t('backlog.table.unitsShort') }}
|
- {{ item.days_delayed }} days
+ {{ item.days_delayed }} {{ t('backlog.table.days') }}
|
@@ -85,10 +85,12 @@
import { ref, onMounted, watch, computed } from 'vue'
import { api } from '../api'
import { useFilters } from '../composables/useFilters'
+import { useI18n } from '../composables/useI18n'
export default {
name: 'Backlog',
setup() {
+ const { t } = useI18n()
const loading = ref(true)
const error = ref(null)
const allBacklogItems = ref([])
@@ -142,6 +144,7 @@ export default {
onMounted(loadBacklog)
return {
+ t,
loading,
error,
backlogItems,
diff --git a/client/src/views/Orders.vue b/client/src/views/Orders.vue
index 7413f6e6..5f31d0ec 100644
--- a/client/src/views/Orders.vue
+++ b/client/src/views/Orders.vue
@@ -8,6 +8,39 @@
{{ t('common.loading') }}
{{ error }}
+
+ Loading submitted orders...
+ {{ restockingError }}
+
+
+
+
+
+
+ | Order Number |
+ Items |
+ Total Cost |
+ Order Date |
+ Expected Delivery |
+ Status |
+
+
+
+
+ | {{ order.order_number }} |
+ {{ order.items.length }} items |
+ ${{ order.total_cost.toLocaleString() }} |
+ {{ formatDate(order.order_date) }} |
+ {{ formatDate(order.expected_delivery) }} |
+ {{ order.status }} |
+
+
+
+
+
+
{{ t('status.delivered') }}
@@ -95,6 +128,9 @@ export default {
const loading = ref(true)
const error = ref(null)
const orders = ref([])
+ const restockingOrders = ref([])
+ const restockingLoading = ref(true)
+ const restockingError = ref(null)
// Use shared filters
const {
@@ -124,6 +160,17 @@ export default {
}
}
+ const loadRestockingOrders = async () => {
+ try {
+ restockingLoading.value = true
+ restockingOrders.value = await api.getRestockingOrders()
+ } catch (err) {
+ restockingError.value = 'Failed to load restocking orders: ' + err.message
+ } finally {
+ restockingLoading.value = false
+ }
+ }
+
// Watch for filter changes and reload data
watch([selectedPeriod, selectedLocation, selectedCategory, selectedStatus], () => {
loadOrders()
@@ -153,7 +200,10 @@ export default {
})
}
- onMounted(loadOrders)
+ onMounted(() => {
+ loadOrders()
+ loadRestockingOrders()
+ })
return {
t,
@@ -165,7 +215,10 @@ export default {
formatDate,
currencySymbol,
translateProductName,
- translateCustomerName
+ translateCustomerName,
+ restockingOrders,
+ restockingLoading,
+ restockingError
}
}
}
diff --git a/client/src/views/Reports.vue b/client/src/views/Reports.vue
index 35187eaf..f9a460bd 100644
--- a/client/src/views/Reports.vue
+++ b/client/src/views/Reports.vue
@@ -1,35 +1,35 @@
- Loading reports...
+ {{ t('common.loading') }}
{{ error }}
- | Quarter |
- Total Orders |
- Total Revenue |
- Avg Order Value |
- Fulfillment Rate |
+ {{ t('reports.quarter') }} |
+ {{ t('reports.totalOrders') }} |
+ {{ t('reports.totalRevenue') }} |
+ {{ t('reports.avgOrderValue') }} |
+ {{ t('reports.fulfillmentRate') }} |
-
+
| {{ q.quarter }} |
{{ q.total_orders }} |
- ${{ formatNumber(q.total_revenue) }} |
- ${{ formatNumber(q.avg_order_value) }} |
+ {{ formatCurrency(q.total_revenue, selectedCurrency) }} |
+ {{ formatCurrency(q.avg_order_value, selectedCurrency) }} |
{{ q.fulfillment_rate }}%
@@ -44,16 +44,16 @@
-
+
{{ formatMonth(month.month) }}
@@ -65,24 +65,24 @@
- | Month |
- Orders |
- Revenue |
- Change |
- Growth Rate |
+ {{ t('reports.month') }} |
+ {{ t('reports.orders') }} |
+ {{ t('reports.revenue') }} |
+ {{ t('reports.change') }} |
+ {{ t('reports.growthRate') }} |
-
+
| {{ formatMonth(month.month) }} |
{{ month.order_count }} |
- ${{ formatNumber(month.revenue) }} |
+ {{ formatCurrency(month.revenue, selectedCurrency) }} |
{{ getChangeValue(month.revenue, monthlyData[index - 1].revenue) }}
@@ -104,19 +104,19 @@
- Total Revenue (YTD)
- ${{ formatNumber(totalRevenue) }}
+ {{ t('reports.stats.totalRevenueYTD') }}
+ {{ formatCurrency(totalRevenue, selectedCurrency) }}
- Avg Monthly Revenue
- ${{ formatNumber(avgMonthlyRevenue) }}
+ {{ t('reports.stats.avgMonthlyRevenue') }}
+ {{ formatCurrency(avgMonthlyRevenue, selectedCurrency) }}
- Total Orders (YTD)
+ {{ t('reports.stats.totalOrdersYTD') }}
{{ totalOrders }}
- Best Performing Quarter
+ {{ t('reports.stats.bestQuarter') }}
{{ bestQuarter }}
@@ -125,192 +125,148 @@
+
+
diff --git a/dashboard-screenshot.png b/dashboard-screenshot.png
new file mode 100644
index 00000000..128efb2a
Binary files /dev/null and b/dashboard-screenshot.png differ
diff --git a/demand-forecast-screenshot.png b/demand-forecast-screenshot.png
new file mode 100644
index 00000000..d00c19b1
Binary files /dev/null and b/demand-forecast-screenshot.png differ
diff --git a/finance-screenshot.png b/finance-screenshot.png
new file mode 100644
index 00000000..94ca095c
Binary files /dev/null and b/finance-screenshot.png differ
diff --git a/inventory-screenshot.png b/inventory-screenshot.png
new file mode 100644
index 00000000..be9b5d44
Binary files /dev/null and b/inventory-screenshot.png differ
diff --git a/orders-full.png b/orders-full.png
new file mode 100644
index 00000000..12424084
Binary files /dev/null and b/orders-full.png differ
diff --git a/orders-screenshot.png b/orders-screenshot.png
new file mode 100644
index 00000000..34cc8261
Binary files /dev/null and b/orders-screenshot.png differ
diff --git a/reports-fixed-screenshot.png b/reports-fixed-screenshot.png
new file mode 100644
index 00000000..8731fa9d
Binary files /dev/null and b/reports-fixed-screenshot.png differ
diff --git a/reports-screenshot.png b/reports-screenshot.png
new file mode 100644
index 00000000..94ca095c
Binary files /dev/null and b/reports-screenshot.png differ
diff --git a/restocking-screenshot.png b/restocking-screenshot.png
new file mode 100644
index 00000000..527307cf
Binary files /dev/null and b/restocking-screenshot.png differ
diff --git a/server/data/demand_forecasts.json b/server/data/demand_forecasts.json
index e1b38838..540aef5b 100644
--- a/server/data/demand_forecasts.json
+++ b/server/data/demand_forecasts.json
@@ -1,83 +1,11 @@
[
- {
- "id": "1",
- "item_sku": "WDG-001",
- "item_name": "Industrial Widget Type A",
- "current_demand": 300,
- "forecasted_demand": 450,
- "trend": "increasing",
- "period": "Next 30 days"
- },
- {
- "id": "2",
- "item_sku": "BRG-102",
- "item_name": "Steel Bearing Assembly",
- "current_demand": 150,
- "forecasted_demand": 152,
- "trend": "stable",
- "period": "Next 30 days"
- },
- {
- "id": "3",
- "item_sku": "GSK-203",
- "item_name": "High-Temperature Gasket",
- "current_demand": 500,
- "forecasted_demand": 600,
- "trend": "increasing",
- "period": "Next 30 days"
- },
- {
- "id": "4",
- "item_sku": "MTR-304",
- "item_name": "Electric Motor 5HP",
- "current_demand": 50,
- "forecasted_demand": 35,
- "trend": "decreasing",
- "period": "Next 30 days"
- },
- {
- "id": "5",
- "item_sku": "FLT-405",
- "item_name": "Oil Filter Cartridge",
- "current_demand": 800,
- "forecasted_demand": 950,
- "trend": "increasing",
- "period": "Next 30 days"
- },
- {
- "id": "6",
- "item_sku": "VLV-506",
- "item_name": "Pressure Relief Valve",
- "current_demand": 120,
- "forecasted_demand": 121,
- "trend": "stable",
- "period": "Next 30 days"
- },
- {
- "id": "7",
- "item_sku": "PSU-501",
- "item_name": "5V 10A Switching Power Supply",
- "current_demand": 250,
- "forecasted_demand": 252,
- "trend": "stable",
- "period": "Next 30 days"
- },
- {
- "id": "8",
- "item_sku": "SNR-420",
- "item_name": "Temperature Sensor Module",
- "current_demand": 180,
- "forecasted_demand": 182,
- "trend": "stable",
- "period": "Next 30 days"
- },
- {
- "id": "9",
- "item_sku": "CTL-330",
- "item_name": "Logic Controller Board",
- "current_demand": 95,
- "forecasted_demand": 96,
- "trend": "stable",
- "period": "Next 30 days"
- }
+ {"id":"1","item_sku":"WDG-001","item_name":"Industrial Widget Type A","current_demand":2000,"forecasted_demand":3200,"trend":"increasing","period":"Next 30 days","unit_cost":12.50},
+ {"id":"2","item_sku":"BRG-102","item_name":"Steel Bearing Assembly","current_demand":500,"forecasted_demand":750,"trend":"stable","period":"Next 30 days","unit_cost":38.75},
+ {"id":"3","item_sku":"GSK-203","item_name":"High-Temperature Gasket","current_demand":1500,"forecasted_demand":2000,"trend":"increasing","period":"Next 30 days","unit_cost":4.20},
+ {"id":"4","item_sku":"MTR-304","item_name":"Electric Motor 5HP","current_demand":100,"forecasted_demand":50,"trend":"decreasing","period":"Next 30 days","unit_cost":285.00},
+ {"id":"5","item_sku":"FLT-405","item_name":"Oil Filter Cartridge","current_demand":3000,"forecasted_demand":5200,"trend":"increasing","period":"Next 30 days","unit_cost":8.90},
+ {"id":"6","item_sku":"VLV-506","item_name":"Pressure Relief Valve","current_demand":120,"forecasted_demand":160,"trend":"stable","period":"Next 30 days","unit_cost":67.00},
+ {"id":"7","item_sku":"PSU-501","item_name":"5V 10A Switching Power Supply","current_demand":250,"forecasted_demand":350,"trend":"stable","period":"Next 30 days","unit_cost":18.99},
+ {"id":"8","item_sku":"SNR-420","item_name":"Temperature Sensor Module","current_demand":180,"forecasted_demand":220,"trend":"stable","period":"Next 30 days","unit_cost":22.00},
+ {"id":"9","item_sku":"CTL-330","item_name":"Logic Controller Board","current_demand":95,"forecasted_demand":120,"trend":"stable","period":"Next 30 days","unit_cost":158.00}
]
diff --git a/server/main.py b/server/main.py
index a0c2d8c5..ed2f536a 100644
--- a/server/main.py
+++ b/server/main.py
@@ -89,6 +89,7 @@ class DemandForecast(BaseModel):
forecasted_demand: int
trend: str
period: str
+ unit_cost: float
class BacklogItem(BaseModel):
id: str
@@ -120,6 +121,32 @@ class CreatePurchaseOrderRequest(BaseModel):
expected_delivery_date: str
notes: Optional[str] = None
+class RestockingOrderItem(BaseModel):
+ item_sku: str
+ item_name: str
+ quantity: int
+ unit_cost: float
+ subtotal: float
+
+class RestockingOrder(BaseModel):
+ id: str
+ order_number: str
+ items: List[RestockingOrderItem]
+ total_cost: float
+ budget: float
+ order_date: str
+ expected_delivery: str
+ status: str
+
+class CreateRestockingOrderRequest(BaseModel):
+ items: List[RestockingOrderItem]
+ total_cost: float
+ budget: float
+
+# In-memory store for restocking orders
+restocking_orders: List[dict] = []
+restocking_order_counter = 0
+
# API endpoints
@app.get("/")
def root():
@@ -304,6 +331,36 @@ def get_monthly_trends():
result.sort(key=lambda x: x['month'])
return result
+@app.post("/api/restocking-orders", response_model=RestockingOrder)
+def create_restocking_order(request: CreateRestockingOrderRequest):
+ """Create a new restocking order from budget recommendations."""
+ global restocking_order_counter
+ from datetime import date, timedelta
+
+ restocking_order_counter += 1
+ order_date = date.today().isoformat()
+ expected_delivery = (date.today() + timedelta(days=14)).isoformat()
+ order_number = f"RST-{date.today().year}-{restocking_order_counter:04d}"
+
+ new_order = {
+ "id": str(restocking_order_counter),
+ "order_number": order_number,
+ "items": [item.model_dump() for item in request.items],
+ "total_cost": round(request.total_cost, 2),
+ "budget": round(request.budget, 2),
+ "order_date": order_date,
+ "expected_delivery": expected_delivery,
+ "status": "Submitted"
+ }
+
+ restocking_orders.append(new_order)
+ return new_order
+
+@app.get("/api/restocking-orders", response_model=List[RestockingOrder])
+def get_restocking_orders():
+ """Get all submitted restocking orders."""
+ return restocking_orders
+
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8001)
| | |