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
3 changes: 3 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,6 @@ npm install && npm run dev
- Status: green/blue/yellow/red
- Charts: Custom SVG, CSS Grid for layouts
- No emojis in UI

## Code Style
- Always document non-obvious logic changes with comments
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
20 changes: 20 additions & 0 deletions client/src/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,5 +102,25 @@ export const api = {
async getPurchaseOrderByBacklogItem(backlogItemId) {
const response = await axios.get(`${API_BASE_URL}/purchase-orders/${backlogItemId}`)
return response.data
},

async getRestockRecommendations(budget, filters = {}) {
const params = new URLSearchParams()
params.append('budget', budget)
if (filters.warehouse && filters.warehouse !== 'all') params.append('warehouse', filters.warehouse)
if (filters.category && filters.category !== 'all') params.append('category', filters.category)

const response = await axios.get(`${API_BASE_URL}/restocking/recommendations?${params.toString()}`)
return response.data
},

async createRestockOrder(payload) {
const response = await axios.post(`${API_BASE_URL}/restocking/orders`, payload)
return response.data
},

async getRestockOrders() {
const response = await axios.get(`${API_BASE_URL}/restocking/orders`)
return response.data
}
}
30 changes: 29 additions & 1 deletion 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 @@ -112,6 +113,9 @@ export default {
onTimeDelivery: 'On-Time Delivery',
itemsCount: '{count} items',
quantity: 'Qty',
submittedOrders: 'Submitted Orders',
noSubmittedOrders: 'No restocking orders submitted yet',
daysCount: '{count} days',
table: {
orderNumber: 'Order Number',
orderId: 'Order ID',
Expand All @@ -125,7 +129,8 @@ export default {
totalValue: 'Total Value',
status: 'Status',
expectedDelivery: 'Expected Delivery',
actualDelivery: 'Actual Delivery'
actualDelivery: 'Actual Delivery',
leadTime: 'Lead Time'
}
},

Expand Down Expand Up @@ -188,6 +193,29 @@ export default {
}
},

// Restocking
restocking: {
title: 'Restocking',
description: 'Set a budget and restock the highest-priority items from the demand forecast',
budgetLabel: 'Available Budget',
recommendedCount: 'Recommended Items',
recommendedItems: 'Recommended Items',
totalCost: 'Total Cost',
remainingBudget: 'Remaining Budget',
noRecommendations: 'No items to recommend at this budget',
placeOrder: 'Place Order',
orderPlaced: 'Order {orderNumber} submitted — see it in Orders → Submitted Orders',
table: {
sku: 'SKU',
itemName: 'Item Name',
trend: 'Trend',
forecastedDemand: 'Forecasted Demand',
recommendedQty: 'Recommended Qty',
unitCost: 'Unit Cost',
lineTotal: 'Line Total'
}
},

// Filters
filters: {
timePeriod: 'Time Period',
Expand Down
30 changes: 29 additions & 1 deletion 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 @@ -112,6 +113,9 @@ export default {
onTimeDelivery: '定時配達',
itemsCount: '{count}件',
quantity: '数量',
submittedOrders: '提出済み注文',
noSubmittedOrders: 'まだ再入荷注文はありません',
daysCount: '{count}日',
table: {
orderNumber: '注文番号',
orderId: '注文ID',
Expand All @@ -125,7 +129,8 @@ export default {
totalValue: '合計金額',
status: 'ステータス',
expectedDelivery: '予定配達日',
actualDelivery: '実際の配達日'
actualDelivery: '実際の配達日',
leadTime: 'リードタイム'
}
},

Expand Down Expand Up @@ -188,6 +193,29 @@ export default {
}
},

// Restocking
restocking: {
title: '再入荷',
description: '予算を設定し、需要予測から優先度の高い商品を再入荷',
budgetLabel: '利用可能な予算',
recommendedCount: '推奨品目',
recommendedItems: '推奨品目',
totalCost: '合計コスト',
remainingBudget: '残り予算',
noRecommendations: 'この予算で推奨できる品目はありません',
placeOrder: '注文する',
orderPlaced: '注文{orderNumber}を提出しました — 注文 → 提出済み注文でご確認ください',
table: {
sku: 'SKU',
itemName: '品目名',
trend: 'トレンド',
forecastedDemand: '予測需要',
recommendedQty: '推奨数量',
unitCost: '単価',
lineTotal: '小計'
}
},

// Filters
filters: {
timePeriod: '期間',
Expand Down
2 changes: 2 additions & 0 deletions 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 @@ -15,6 +16,7 @@ const router = createRouter({
{ path: '/inventory', component: Inventory },
{ path: '/orders', component: Orders },
{ path: '/demand', component: Demand },
{ path: '/restocking', component: Restocking },
{ path: '/spending', component: Spending },
{ path: '/reports', component: Reports }
]
Expand Down
60 changes: 59 additions & 1 deletion client/src/views/Orders.vue
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,51 @@
</table>
</div>
</div>

<div class="card">
<div class="card-header">
<h3 class="card-title">{{ t('orders.submittedOrders') }} ({{ submittedOrders.length }})</h3>
</div>
<div v-if="submittedOrders.length === 0" class="loading">{{ t('orders.noSubmittedOrders') }}</div>
<div v-else class="table-container">
<table class="submitted-orders-table">
<thead>
<tr>
<th>{{ t('orders.table.orderNumber') }}</th>
<th>{{ t('orders.table.items') }}</th>
<th>{{ t('orders.table.totalValue') }}</th>
<th>{{ t('orders.table.orderDate') }}</th>
<th>{{ t('orders.table.leadTime') }}</th>
<th>{{ t('orders.table.expectedDelivery') }}</th>
<th>{{ t('orders.table.status') }}</th>
</tr>
</thead>
<tbody>
<tr v-for="order in submittedOrders" :key="order.id">
<td><strong>{{ order.order_number }}</strong></td>
<td>
<details class="items-details">
<summary class="items-summary">
{{ t('orders.itemsCount', { count: order.items.length }) }}
</summary>
<div class="items-dropdown">
<div v-for="(item, idx) in order.items" :key="idx" class="item-entry">
<span class="item-name">{{ item.item_name }}</span>
<span class="item-meta">{{ t('orders.quantity') }}: {{ item.quantity }} @ {{ currencySymbol }}{{ item.unit_cost }}</span>
</div>
</div>
</details>
</td>
<td><strong>{{ currencySymbol }}{{ order.total_cost.toLocaleString() }}</strong></td>
<td>{{ formatDate(order.created_date) }}</td>
<td>{{ t('orders.daysCount', { count: order.lead_time_days }) }}</td>
<td>{{ formatDate(order.expected_delivery_date) }}</td>
<td><span class="badge info">{{ order.status }}</span></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</template>
Expand All @@ -95,6 +140,7 @@ export default {
const loading = ref(true)
const error = ref(null)
const orders = ref([])
const submittedOrders = ref([])

// Use shared filters
const {
Expand Down Expand Up @@ -129,6 +175,14 @@ export default {
loadOrders()
})

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

const getOrdersByStatus = (status) => {
return orders.value.filter(order => order.status === status)
}
Expand All @@ -153,13 +207,17 @@ export default {
})
}

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

return {
t,
loading,
error,
orders,
submittedOrders,
getOrdersByStatus,
getOrderStatusClass,
formatDate,
Expand Down
Loading