Feature: Royal Mail tracking integration (hybrid approach)
Add ability to sync shipment tracking data from Royal Mail API: - Create Royal Mail API service (src/lib/royalmail.ts) to fetch tracking status - Add sync-tracking endpoint to pull latest status from Royal Mail - Create SyncRoyalMailButton component for admin panel - Add 'Sync from Royal Mail' button on order detail page - Auto-update order status based on Royal Mail tracking status Admin workflow: 1. Create shipping label in Royal Mail Click & Drop 2. Copy tracking number into tracking form 3. Click 'Sync from Royal Mail' to fetch and update status 4. System maps Royal Mail status to our order status (SHIPPED, DELIVERED, etc) Uses Royal Mail's public tracking API - no special credentials required. Supports manual label creation workflow (hybrid approach).
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { notFound } from 'next/navigation';
|
||||
import { prisma } from '@/lib/prisma';
|
||||
import AdminNav from '@/components/AdminNav';
|
||||
import SyncRoyalMailButton from '@/components/SyncRoyalMailButton';
|
||||
import { archiveOrder, unarchiveOrder, updateOrderTracking } from '../actions';
|
||||
|
||||
function formatPrice(cents: number) {
|
||||
@@ -133,13 +134,29 @@ export default async function OrderDetailPage({ params }: { params: { id: string
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
className="bg-clay px-4 py-2 text-sm font-medium text-paper hover:bg-clay-dark"
|
||||
>
|
||||
Update Tracking Info
|
||||
</button>
|
||||
<div className="flex gap-3">
|
||||
<button
|
||||
type="submit"
|
||||
className="bg-clay px-4 py-2 text-sm font-medium text-paper hover:bg-clay-dark"
|
||||
>
|
||||
Update Tracking Info
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{order.trackingNumber && (
|
||||
<div className="mt-4 border-t border-line pt-4">
|
||||
<p className="tag-label mb-3">Royal Mail Integration</p>
|
||||
<SyncRoyalMailButton
|
||||
orderId={order.id}
|
||||
trackingNumber={order.trackingNumber}
|
||||
onSuccess={() => {
|
||||
// In a real app, we'd refresh the page or update state
|
||||
console.log('Tracking synced successfully');
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="mt-10 divide-y divide-line border-t border-line">
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { prisma } from '@/lib/prisma';
|
||||
import { fetchRoyalMailTracking, mapTrackingStatusToOrderStatus } from '@/lib/royalmail';
|
||||
|
||||
export async function POST(
|
||||
req: Request,
|
||||
{ params }: { params: { id: string } }
|
||||
) {
|
||||
try {
|
||||
const order = await prisma.order.findUnique({
|
||||
where: { id: params.id },
|
||||
});
|
||||
|
||||
if (!order) {
|
||||
return NextResponse.json({ error: 'Order not found' }, { status: 404 });
|
||||
}
|
||||
|
||||
if (!order.trackingNumber) {
|
||||
return NextResponse.json({ error: 'No tracking number set for this order' }, { status: 400 });
|
||||
}
|
||||
|
||||
// Fetch tracking data from Royal Mail
|
||||
const trackingData = await fetchRoyalMailTracking(order.trackingNumber);
|
||||
|
||||
if (!trackingData) {
|
||||
return NextResponse.json({ error: 'Could not fetch tracking data from Royal Mail' }, { status: 400 });
|
||||
}
|
||||
|
||||
// Map Royal Mail status to our order status
|
||||
const newStatus = mapTrackingStatusToOrderStatus(trackingData.status);
|
||||
|
||||
// Update order with new status
|
||||
const updated = await prisma.order.update({
|
||||
where: { id: params.id },
|
||||
data: {
|
||||
status: newStatus,
|
||||
},
|
||||
});
|
||||
|
||||
console.log(`✓ Order ${params.id} tracking synced: ${trackingData.status} → ${newStatus}`);
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
trackingData,
|
||||
orderStatus: newStatus,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('Error syncing tracking:', err);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to sync tracking data' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user