Skip to content
Open
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
1,365 changes: 1,365 additions & 0 deletions architecture.html

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions client/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
<router-link to="/demand" :class="{ active: $route.path === '/demand' }">
{{ t('nav.demandForecast') }}
</router-link>
<router-link to="/restocking" :class="{ active: $route.path === '/restocking' }">
{{ t('nav.restocking') }}
</router-link>
<router-link to="/reports" :class="{ active: $route.path === '/reports' }">
Reports
</router-link>
Expand Down
18 changes: 18 additions & 0 deletions client/src/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,5 +102,23 @@ export const api = {
async getPurchaseOrderByBacklogItem(backlogItemId) {
const response = await axios.get(`${API_BASE_URL}/purchase-orders/${backlogItemId}`)
return response.data
},

async getRestockRecommendations(budget) {
const response = await axios.get(`${API_BASE_URL}/restock/recommendations?budget=${budget}`)
return response.data
},

async submitRestockOrder(items, totalBudget) {
const response = await axios.post(`${API_BASE_URL}/orders/restock`, {
items,
total_budget: totalBudget
})
return response.data
},

async getRestockOrders() {
const response = await axios.get(`${API_BASE_URL}/orders/restock`)
return response.data
}
}
44 changes: 44 additions & 0 deletions client/src/locales/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export default {
orders: 'Orders',
finance: 'Finance',
demandForecast: 'Demand Forecast',
restocking: 'Restocking',
companyName: 'Catalyst Components',
subtitle: 'Inventory Management System'
},
Expand Down Expand Up @@ -204,6 +205,7 @@ export default {
shipped: 'Shipped',
processing: 'Processing',
backordered: 'Backordered',
submitted: 'Submitted',
inStock: 'In Stock',
lowStock: 'Low Stock',
adequate: 'Adequate'
Expand Down Expand Up @@ -311,6 +313,48 @@ export default {
selectLanguage: 'Select Language'
},

// Restocking
restocking: {
title: 'Restocking',
description: 'Plan and submit restocking orders based on demand forecasts',
budget: 'Available Budget',
budgetUsed: 'Budget Used',
budgetRemaining: 'Remaining',
remaining: 'Remaining',
recommendations: 'Recommended Items',
noRecommendations: 'No items to recommend at this budget level',
placeOrder: 'Place Order',
submitting: 'Submitting...',
orderSuccess: 'Restocking order submitted successfully',
orderError: 'Failed to submit restocking order',
demandGap: 'Demand Gap',
recommendedQty: 'Rec. Qty',
estCost: 'Est. Cost',
selected: 'Selected',
selectedItems: 'Selected Items',
totalCost: 'Total Cost',
itemsSelected: '{count} items selected',
itemsAvailable: 'items available',
leadTime: 'Lead Time',
days: '{count} days',
submittedOrders: 'Submitted Orders',
noSubmittedOrders: 'No submitted restocking orders yet',
orderNumber: 'Order #',
submitDate: 'Submit Date',
expectedDelivery: 'Expected Delivery',
confirmTitle: 'Confirm Restocking Order',
confirmMessage: 'Submit restocking order for {count} items totaling {total}?',
table: {
sku: 'SKU',
itemName: 'Item Name',
trend: 'Trend',
demandGap: 'Demand Gap',
unitCost: 'Unit Cost',
recQty: 'Rec. Qty',
estCost: 'Est. Cost'
}
},

// Common
common: {
loading: 'Loading...',
Expand Down
44 changes: 44 additions & 0 deletions client/src/locales/ja.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export default {
orders: '注文',
finance: '財務',
demandForecast: '需要予測',
restocking: '補充',
companyName: '触媒コンポーネンツ',
subtitle: '在庫管理システム'
},
Expand Down Expand Up @@ -204,6 +205,7 @@ export default {
shipped: '出荷済み',
processing: '処理中',
backordered: 'バックオーダー',
submitted: '提出済み',
inStock: '在庫あり',
lowStock: '在庫僅少',
adequate: '適量'
Expand Down Expand Up @@ -311,6 +313,48 @@ export default {
selectLanguage: '言語を選択'
},

// Restocking
restocking: {
title: '補充',
description: '需要予測に基づいて補充注文を計画・提出',
budget: '利用可能予算',
budgetUsed: '使用済み予算',
budgetRemaining: '残り',
remaining: '残り',
recommendations: '推奨品目',
noRecommendations: 'この予算レベルでは推奨品目はありません',
placeOrder: '注文する',
submitting: '送信中...',
orderSuccess: '補充注文が正常に送信されました',
orderError: '補充注文の送信に失敗しました',
demandGap: '需要ギャップ',
recommendedQty: '推奨数量',
estCost: '見積費用',
selected: '選択済み',
selectedItems: '選択品目',
totalCost: '合計費用',
itemsSelected: '{count}品目選択',
itemsAvailable: '品目利用可能',
leadTime: 'リードタイム',
days: '{count}日',
submittedOrders: '提出済み注文',
noSubmittedOrders: '提出済みの補充注文はありません',
orderNumber: '注文番号',
submitDate: '提出日',
expectedDelivery: '予定配達日',
confirmTitle: '補充注文の確認',
confirmMessage: '{count}品目、合計{total}の補充注文を送信しますか?',
table: {
sku: 'SKU',
itemName: '品目名',
trend: 'トレンド',
demandGap: '需要ギャップ',
unitCost: '単価',
recQty: '推奨数量',
estCost: '見積費用'
}
},

// Common
common: {
loading: '読み込み中...',
Expand Down
4 changes: 3 additions & 1 deletion client/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Orders from './views/Orders.vue'
import Demand from './views/Demand.vue'
import Spending from './views/Spending.vue'
import Reports from './views/Reports.vue'
import Restocking from './views/Restocking.vue'

const router = createRouter({
history: createWebHistory(),
Expand All @@ -16,7 +17,8 @@ const router = createRouter({
{ path: '/orders', component: Orders },
{ path: '/demand', component: Demand },
{ path: '/spending', component: Spending },
{ path: '/reports', component: Reports }
{ path: '/reports', component: Reports },
{ path: '/restocking', component: Restocking }
]
})

Expand Down
75 changes: 73 additions & 2 deletions client/src/views/Orders.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,43 @@
<div v-if="loading" class="loading">{{ t('common.loading') }}</div>
<div v-else-if="error" class="error">{{ error }}</div>
<div v-else>

<!-- Submitted Restock Orders -->
<div v-if="restockOrders.length" class="card">
<div class="card-header">
<h3 class="card-title">{{ t('restocking.submittedOrders') }}</h3>
<span class="restock-count">{{ restockOrders.length }}</span>
</div>
<div class="table-container">
<table class="restock-orders-table">
<thead>
<tr>
<th>{{ t('orders.table.orderNumber') }}</th>
<th>{{ t('orders.table.items') }}</th>
<th>{{ t('orders.table.status') }}</th>
<th>{{ t('restocking.submitDate') }}</th>
<th>{{ t('orders.table.expectedDelivery') }}</th>
<th>{{ t('restocking.leadTime') }}</th>
<th>{{ t('orders.table.totalValue') }}</th>
</tr>
</thead>
<tbody>
<tr v-for="order in restockOrders" :key="order.id">
<td><strong>{{ order.order_number }}</strong></td>
<td>{{ t('orders.itemsCount', { count: order.items.length }) }}</td>
<td>
<span class="badge submitted">{{ t('status.submitted') }}</span>
</td>
<td>{{ formatDate(order.order_date) }}</td>
<td>{{ formatDate(order.expected_delivery) }}</td>
<td>{{ t('restocking.days', { count: order.lead_time_days }) }}</td>
<td><strong>{{ currencySymbol }}{{ order.total_value.toLocaleString() }}</strong></td>
</tr>
</tbody>
</table>
</div>
</div>

<div class="stats-grid">
<div class="stat-card success">
<div class="stat-label">{{ t('status.delivered') }}</div>
Expand Down Expand Up @@ -95,6 +132,7 @@ export default {
const loading = ref(true)
const error = ref(null)
const orders = ref([])
const restockOrders = ref([])

// Use shared filters
const {
Expand Down Expand Up @@ -124,9 +162,18 @@ export default {
}
}

const loadRestockOrders = async () => {
try {
restockOrders.value = await api.getRestockOrders()
} catch (err) {
console.error('Failed to load restock orders:', err)
}
}

// Watch for filter changes and reload data
watch([selectedPeriod, selectedLocation, selectedCategory, selectedStatus], () => {
loadOrders()
loadRestockOrders()
})

const getOrdersByStatus = (status) => {
Expand All @@ -138,7 +185,8 @@ export default {
'Delivered': 'success',
'Shipped': 'info',
'Processing': 'warning',
'Backordered': 'danger'
'Backordered': 'danger',
'Submitted': 'submitted'
}
return statusMap[status] || 'info'
}
Expand All @@ -153,13 +201,17 @@ export default {
})
}

onMounted(loadOrders)
onMounted(() => {
loadOrders()
loadRestockOrders()
})

return {
t,
loading,
error,
orders,
restockOrders,
getOrdersByStatus,
getOrderStatusClass,
formatDate,
Expand All @@ -172,6 +224,25 @@ export default {
</script>

<style scoped>
.badge.submitted {
background: #e0e7ff;
color: #3730a3;
}

.restock-count {
font-size: 0.875rem;
color: #64748b;
font-weight: 500;
background: #f1f5f9;
padding: 0.25rem 0.625rem;
border-radius: 999px;
}

.restock-orders-table {
table-layout: auto;
width: 100%;
}

/* Fixed table layout to prevent column shifting */
.orders-table {
table-layout: fixed;
Expand Down
Loading