feat: add order ack detail/PDF, BOL detail/PDF, coil activity usage & receipts
C-005: Order Acknowledgement Detail + PDF
- Order detail page with full line items, releases, addresses, paint codes
- PDF export via Puppeteer matching legacy format
- Clickable order # links and PDF icons in orders table
C-007: BOL Detail + PDF
- BOL detail page with ship-from/to, line items, weights
- PDF export matching legacy BOL format
- PDF icon column in shipments table
C-008: Coil Activity - Usage Report
- Date range picker (max 31 days, default last 10 days)
- Reusable UI: Popover, Calendar (react-day-picker v9), DateRangePicker
- SQL from legacy portal_CoilActivityUsage.sql with OnHandQty dedup
- 11-column sortable table with search and CSV export
C-009: Coil Activity - Receipts Report
- VGL customer exception (special SQL vs portal view)
- 10-column sortable table with search and CSV export
- Shared date range picker component
Also: dashboard API route, shipments API route, HDC→HDM mapping,
Puppeteer PDF infrastructure, improved error handling.
Progress: 9/16 Phase 2 tasks complete.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 09:14:52 -05:00
|
|
|
import { NextRequest, NextResponse } from 'next/server';
|
|
|
|
|
import { getCoilReceipts } from '@/services/coil-activity';
|
|
|
|
|
import { getQuestSession, getActiveCompany } from '@/lib/permissions';
|
feat: add Redis caching layer, fix connection pools, add loading skeletons
- Create src/lib/redis.ts (singleton client) and src/lib/cache.ts
(cachedQuery with graceful degradation on Redis failure)
- Wrap all 12 API routes and 7 RSC pages with cachedQuery (TTLs:
120s-900s by data type — dashboard 3min, inventory/orders/shipments
5min, BOL/order-ack/traveler 10min, ship-to 15min, avail-coils 2min)
- Fix redundant connection pools in dashboard.ts and shipments.ts
(were creating their own sql.connect instead of using shared pool)
- Add pool tuning to epicor.ts (max:15, min:2, 60s idle, 30s acquire)
- Parallelize session checks (getQuestSession + getActiveCompany +
isSubUser) with Promise.all across all inventory and orders pages
- Add loading.tsx skeletons for dashboard, inventory detail, orders,
and shipments pages for instant shell rendering via Next.js streaming
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 07:40:07 -05:00
|
|
|
import { cachedQuery } from '@/lib/cache';
|
feat: add order ack detail/PDF, BOL detail/PDF, coil activity usage & receipts
C-005: Order Acknowledgement Detail + PDF
- Order detail page with full line items, releases, addresses, paint codes
- PDF export via Puppeteer matching legacy format
- Clickable order # links and PDF icons in orders table
C-007: BOL Detail + PDF
- BOL detail page with ship-from/to, line items, weights
- PDF export matching legacy BOL format
- PDF icon column in shipments table
C-008: Coil Activity - Usage Report
- Date range picker (max 31 days, default last 10 days)
- Reusable UI: Popover, Calendar (react-day-picker v9), DateRangePicker
- SQL from legacy portal_CoilActivityUsage.sql with OnHandQty dedup
- 11-column sortable table with search and CSV export
C-009: Coil Activity - Receipts Report
- VGL customer exception (special SQL vs portal view)
- 10-column sortable table with search and CSV export
- Shared date range picker component
Also: dashboard API route, shipments API route, HDC→HDM mapping,
Puppeteer PDF infrastructure, improved error handling.
Progress: 9/16 Phase 2 tasks complete.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 09:14:52 -05:00
|
|
|
|
|
|
|
|
export const dynamic = 'force-dynamic';
|
|
|
|
|
|
|
|
|
|
export async function GET(request: NextRequest) {
|
|
|
|
|
const session = await getQuestSession();
|
|
|
|
|
const activeCompany = await getActiveCompany();
|
|
|
|
|
|
|
|
|
|
if (!session || !activeCompany) {
|
|
|
|
|
return NextResponse.json({ error: 'No active company' }, { status: 401 });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { searchParams } = new URL(request.url);
|
|
|
|
|
const startDate = searchParams.get('startDate');
|
|
|
|
|
const endDate = searchParams.get('endDate');
|
|
|
|
|
|
|
|
|
|
if (!startDate || !endDate) {
|
|
|
|
|
return NextResponse.json(
|
|
|
|
|
{ error: 'startDate and endDate query parameters are required' },
|
|
|
|
|
{ status: 400 }
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const start = new Date(startDate);
|
|
|
|
|
const end = new Date(endDate);
|
|
|
|
|
if (isNaN(start.getTime()) || isNaN(end.getTime())) {
|
|
|
|
|
return NextResponse.json({ error: 'Invalid date format' }, { status: 400 });
|
|
|
|
|
}
|
|
|
|
|
if (end < start) {
|
|
|
|
|
return NextResponse.json(
|
|
|
|
|
{ error: 'endDate must be after startDate' },
|
|
|
|
|
{ status: 400 }
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
const diffDays = Math.ceil(
|
|
|
|
|
(end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24)
|
|
|
|
|
);
|
|
|
|
|
if (diffDays > 31) {
|
|
|
|
|
return NextResponse.json(
|
|
|
|
|
{ error: 'Date range cannot exceed 31 days' },
|
|
|
|
|
{ status: 400 }
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
feat: add Redis caching layer, fix connection pools, add loading skeletons
- Create src/lib/redis.ts (singleton client) and src/lib/cache.ts
(cachedQuery with graceful degradation on Redis failure)
- Wrap all 12 API routes and 7 RSC pages with cachedQuery (TTLs:
120s-900s by data type — dashboard 3min, inventory/orders/shipments
5min, BOL/order-ack/traveler 10min, ship-to 15min, avail-coils 2min)
- Fix redundant connection pools in dashboard.ts and shipments.ts
(were creating their own sql.connect instead of using shared pool)
- Add pool tuning to epicor.ts (max:15, min:2, 60s idle, 30s acquire)
- Parallelize session checks (getQuestSession + getActiveCompany +
isSubUser) with Promise.all across all inventory and orders pages
- Add loading.tsx skeletons for dashboard, inventory detail, orders,
and shipments pages for instant shell rendering via Next.js streaming
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 07:40:07 -05:00
|
|
|
const custId = activeCompany.epicor_cust_id;
|
|
|
|
|
|
feat: add order ack detail/PDF, BOL detail/PDF, coil activity usage & receipts
C-005: Order Acknowledgement Detail + PDF
- Order detail page with full line items, releases, addresses, paint codes
- PDF export via Puppeteer matching legacy format
- Clickable order # links and PDF icons in orders table
C-007: BOL Detail + PDF
- BOL detail page with ship-from/to, line items, weights
- PDF export matching legacy BOL format
- PDF icon column in shipments table
C-008: Coil Activity - Usage Report
- Date range picker (max 31 days, default last 10 days)
- Reusable UI: Popover, Calendar (react-day-picker v9), DateRangePicker
- SQL from legacy portal_CoilActivityUsage.sql with OnHandQty dedup
- 11-column sortable table with search and CSV export
C-009: Coil Activity - Receipts Report
- VGL customer exception (special SQL vs portal view)
- 10-column sortable table with search and CSV export
- Shared date range picker component
Also: dashboard API route, shipments API route, HDC→HDM mapping,
Puppeteer PDF infrastructure, improved error handling.
Progress: 9/16 Phase 2 tasks complete.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 09:14:52 -05:00
|
|
|
try {
|
feat: add Redis caching layer, fix connection pools, add loading skeletons
- Create src/lib/redis.ts (singleton client) and src/lib/cache.ts
(cachedQuery with graceful degradation on Redis failure)
- Wrap all 12 API routes and 7 RSC pages with cachedQuery (TTLs:
120s-900s by data type — dashboard 3min, inventory/orders/shipments
5min, BOL/order-ack/traveler 10min, ship-to 15min, avail-coils 2min)
- Fix redundant connection pools in dashboard.ts and shipments.ts
(were creating their own sql.connect instead of using shared pool)
- Add pool tuning to epicor.ts (max:15, min:2, 60s idle, 30s acquire)
- Parallelize session checks (getQuestSession + getActiveCompany +
isSubUser) with Promise.all across all inventory and orders pages
- Add loading.tsx skeletons for dashboard, inventory detail, orders,
and shipments pages for instant shell rendering via Next.js streaming
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 07:40:07 -05:00
|
|
|
const data = await cachedQuery(
|
|
|
|
|
{ key: `coil:${custId}:receipts:${startDate}:${endDate}`, ttlSeconds: 300 },
|
|
|
|
|
() => getCoilReceipts(custId, startDate, endDate)
|
feat: add order ack detail/PDF, BOL detail/PDF, coil activity usage & receipts
C-005: Order Acknowledgement Detail + PDF
- Order detail page with full line items, releases, addresses, paint codes
- PDF export via Puppeteer matching legacy format
- Clickable order # links and PDF icons in orders table
C-007: BOL Detail + PDF
- BOL detail page with ship-from/to, line items, weights
- PDF export matching legacy BOL format
- PDF icon column in shipments table
C-008: Coil Activity - Usage Report
- Date range picker (max 31 days, default last 10 days)
- Reusable UI: Popover, Calendar (react-day-picker v9), DateRangePicker
- SQL from legacy portal_CoilActivityUsage.sql with OnHandQty dedup
- 11-column sortable table with search and CSV export
C-009: Coil Activity - Receipts Report
- VGL customer exception (special SQL vs portal view)
- 10-column sortable table with search and CSV export
- Shared date range picker component
Also: dashboard API route, shipments API route, HDC→HDM mapping,
Puppeteer PDF infrastructure, improved error handling.
Progress: 9/16 Phase 2 tasks complete.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 09:14:52 -05:00
|
|
|
);
|
|
|
|
|
return NextResponse.json(data);
|
|
|
|
|
} catch (err) {
|
|
|
|
|
const message = err instanceof Error ? err.message : String(err);
|
|
|
|
|
let details = '';
|
|
|
|
|
if (err && typeof err === 'object' && 'originalError' in err) {
|
|
|
|
|
const originalError = (err as { originalError: unknown }).originalError;
|
|
|
|
|
details =
|
|
|
|
|
originalError instanceof Error
|
|
|
|
|
? originalError.message
|
|
|
|
|
: String(originalError);
|
|
|
|
|
}
|
|
|
|
|
console.error('Coil receipts error:', err);
|
|
|
|
|
return NextResponse.json({ error: message, details }, { status: 500 });
|
|
|
|
|
}
|
|
|
|
|
}
|