- Added main router in src/index.js to register endpoints. - Implemented GET /mayo-api/products to fetch product list with pagination and filters. - Implemented GET /mayo-api/dictionaries to fetch various dictionaries for frontend use. - Created separate files for routes, repositories, serializers, and utilities to maintain clean architecture. - Added utility functions for async handling, pagination, and order search parsing. - Introduced serializers for products and dictionaries to format data for frontend consumption. - Established repository functions for database queries related to products and dictionaries. - Updated package.json to include license information. - Created documentation for the API extension detailing current state and future implementation plans.
128 lines
3.4 KiB
JavaScript
128 lines
3.4 KiB
JavaScript
export default (router) => {
|
|
router.get('/', (req, res) => res.send('Hello, World!'));
|
|
};
|
|
|
|
|
|
export default {
|
|
id: 'mayo-api',
|
|
|
|
handler: (router, { database }) => {
|
|
router.get('/products/by-order/:orderNumber/:orderYear/:productIndex/timeline', async (req, res) => {
|
|
if (!req.accountability?.user) {
|
|
return res.status(401).json({ error: 'Unauthorized' })
|
|
}
|
|
|
|
const { orderNumber, orderYear, productIndex } = req.params
|
|
|
|
const normalizedOrderNumber = Number(orderNumber)
|
|
const normalizedOrderYear = Number(orderYear)
|
|
const normalizedProductIndex = Number(productIndex)
|
|
|
|
if (
|
|
Number.isNaN(normalizedOrderNumber) ||
|
|
Number.isNaN(normalizedOrderYear) ||
|
|
Number.isNaN(normalizedProductIndex)
|
|
) {
|
|
return res.status(400).json({ error: 'Invalid order code' })
|
|
}
|
|
|
|
const orderProduct = await database('mayo_order_products as op')
|
|
.select(
|
|
'op.id as order_product_id',
|
|
'op.product_id',
|
|
'op.produc_order_idx',
|
|
'o.id as order_id',
|
|
'o.order_number',
|
|
'o.order_year',
|
|
'p.note',
|
|
'm.id as model_id',
|
|
'm.name as model_name'
|
|
)
|
|
.join('mayo_orders as o', 'op.order_id', 'o.id')
|
|
.join('mayo_products as p', 'op.product_id', 'p.id')
|
|
.leftJoin('mayo_models as m', 'p.model_id', 'm.id')
|
|
.where('o.order_number', normalizedOrderNumber)
|
|
.where('o.order_year', normalizedOrderYear)
|
|
.where('op.produc_order_idx', normalizedProductIndex)
|
|
.first()
|
|
|
|
if (!orderProduct) {
|
|
return res.status(404).json({ error: 'Product not found' })
|
|
}
|
|
|
|
const events = await database('mayo_events as e')
|
|
.select(
|
|
'e.id',
|
|
'e.ordinal',
|
|
'e.event_kind',
|
|
'e.event_date',
|
|
'p.id as part_id',
|
|
'p.part_type'
|
|
)
|
|
.join('mayo_parts as p', 'e.part_id', 'p.id')
|
|
.where('p.product_id', orderProduct.product_id)
|
|
.orderBy('e.ordinal', 'asc')
|
|
|
|
const eventIds = events.map((event) => event.id)
|
|
|
|
const [operations, notes, photos] = await Promise.all([
|
|
database('mayo_event_operations as eo')
|
|
.select(
|
|
'eo.event_id',
|
|
'o.id as operation_id',
|
|
'o.name',
|
|
'o.description'
|
|
)
|
|
.leftJoin('mayo_operations as o', 'eo.operation_id', 'o.id')
|
|
.whereIn('eo.event_id', eventIds),
|
|
|
|
database('mayo_event_notes')
|
|
.select('event_id', 'note_type', 'note')
|
|
.whereIn('event_id', eventIds),
|
|
|
|
database('mayo_event_photos')
|
|
.select('event_id', 'photo_url')
|
|
.whereIn('event_id', eventIds),
|
|
])
|
|
|
|
const operationsByEventId = new Map(operations.map((operation) => [operation.event_id, operation]))
|
|
const notesByEventId = new Map(notes.map((note) => [note.event_id, note]))
|
|
|
|
const photosByEventId = photos.reduce((acc, photo) => {
|
|
if (!acc.has(photo.event_id)) acc.set(photo.event_id, [])
|
|
acc.get(photo.event_id).push({
|
|
file_id: photo.photo_url,
|
|
url: photo.photo_url ? `/assets/${photo.photo_url}` : null,
|
|
})
|
|
return acc
|
|
}, new Map())
|
|
|
|
const timeline = events.map((event) => ({
|
|
id: event.id,
|
|
ordinal: event.ordinal,
|
|
kind: event.event_kind,
|
|
date: event.event_date,
|
|
part: {
|
|
id: event.part_id,
|
|
type: event.part_type,
|
|
},
|
|
operation: operationsByEventId.get(event.id) ?? null,
|
|
note: notesByEventId.get(event.id) ?? null,
|
|
photos: photosByEventId.get(event.id) ?? [],
|
|
}))
|
|
|
|
return res.json({
|
|
product: {
|
|
id: orderProduct.product_id,
|
|
order_code: `${String(orderProduct.order_number).padStart(4, '0')}/${orderProduct.order_year}/${orderProduct.produc_order_idx}`,
|
|
model: {
|
|
id: orderProduct.model_id,
|
|
name: orderProduct.model_name,
|
|
},
|
|
note: orderProduct.note,
|
|
},
|
|
timeline,
|
|
})
|
|
})
|
|
},
|
|
} |