Download ops/backend-dm/controllers/deliveryController.js from MouleeswaranM/FairRelay: direct link, hf CLI and curl.
- Browser
- Download file 14.7 kB
-
https://huggingface.co/MouleeswaranM/FairRelay/resolve/refs%2Fpr%2F21/ops/backend-dm/controllers/deliveryController.js
- Command line
-
hf download hf://MouleeswaranM/FairRelay@refs/pr/21/ops/backend-dm/controllers/deliveryController.js
-
curl -L -o deliveryController.js https://huggingface.co/MouleeswaranM/FairRelay/resolve/refs%2Fpr%2F21/ops/backend-dm/controllers/deliveryController.js
14.7 kB
| const prisma = require('../config/database'); | |
| const Joi = require('joi'); | |
| /** | |
| * GET /api/deliveries/assigned - Driver's active/pending deliveries | |
| */ | |
| const getAssignedDeliveries = async (req, res) => { | |
| try { | |
| const deliveries = await prisma.delivery.findMany({ | |
| where: { | |
| driverId: req.user.id, | |
| status: { | |
| not: 'COMPLETED', | |
| }, | |
| }, | |
| include: { | |
| shipment: true, | |
| truck: true, | |
| }, | |
| orderBy: { | |
| createdAt: 'desc', | |
| }, | |
| }); | |
| res.status(200).json({ | |
| success: true, | |
| data: deliveries, | |
| }); | |
| } catch (error) { | |
| console.error('Get assigned deliveries error:', error); | |
| res.status(500).json({ | |
| success: false, | |
| message: 'Failed to fetch assigned deliveries', | |
| }); | |
| } | |
| }; | |
| /** | |
| * POST /api/deliveries/:id/accept - Driver accepts delivery | |
| */ | |
| const acceptDelivery = async (req, res) => { | |
| try { | |
| const { id } = req.params; | |
| const delivery = await prisma.delivery.findUnique({ | |
| where: { id }, | |
| include: { shipment: true }, | |
| }); | |
| if (!delivery || delivery.driverId !== req.user.id) { | |
| return res.status(404).json({ | |
| success: false, | |
| message: 'Delivery not found', | |
| }); | |
| } | |
| if (delivery.status !== 'PENDING') { | |
| return res.status(400).json({ | |
| success: false, | |
| message: 'Delivery is already accepted or in progress', | |
| }); | |
| } | |
| // Update delivery and shipment status | |
| const updatedDelivery = await prisma.$transaction([ | |
| prisma.delivery.update({ | |
| where: { id }, | |
| data: { status: 'EN_ROUTE_TO_PICKUP' }, | |
| }), | |
| prisma.shipment.update({ | |
| where: { id: delivery.shipmentId }, | |
| data: { status: 'DRIVER_ACCEPTED' }, | |
| }), | |
| ]); | |
| res.status(200).json({ | |
| success: true, | |
| message: 'Delivery accepted', | |
| data: updatedDelivery[0], | |
| }); | |
| } catch (error) { | |
| console.error('Accept delivery error:', error); | |
| res.status(500).json({ | |
| success: false, | |
| message: 'Failed to accept delivery', | |
| }); | |
| } | |
| }; | |
| /** | |
| * POST /api/deliveries/:id/reject - Driver rejects delivery | |
| */ | |
| const rejectDelivery = async (req, res) => { | |
| try { | |
| const { id } = req.params; | |
| const delivery = await prisma.delivery.findUnique({ | |
| where: { id }, | |
| }); | |
| if (!delivery || delivery.driverId !== req.user.id) { | |
| return res.status(404).json({ | |
| success: false, | |
| message: 'Delivery not found', | |
| }); | |
| } | |
| // Rejection usually means unassigning the driver or marking as cancelled | |
| await prisma.$transaction([ | |
| prisma.delivery.update({ | |
| where: { id }, | |
| data: { status: 'CANCELLED' }, | |
| }), | |
| prisma.shipment.update({ | |
| where: { id: delivery.shipmentId }, | |
| data: { status: 'DRIVER_REJECTED' }, | |
| }), | |
| ]); | |
| res.status(200).json({ | |
| success: true, | |
| message: 'Delivery rejected', | |
| }); | |
| } catch (error) { | |
| console.error('Reject delivery error:', error); | |
| res.status(500).json({ | |
| success: false, | |
| message: 'Failed to reject delivery', | |
| }); | |
| } | |
| }; | |
| /** | |
| * POST /api/deliveries/:id/start - Start navigation to pickup | |
| */ | |
| const startDelivery = async (req, res) => { | |
| try { | |
| const { id } = req.params; | |
| const delivery = await prisma.delivery.findUnique({ | |
| where: { id }, | |
| }); | |
| if (!delivery || delivery.driverId !== req.user.id) { | |
| return res.status(404).json({ | |
| success: false, | |
| message: 'Delivery not found', | |
| }); | |
| } | |
| const updatedDelivery = await prisma.delivery.update({ | |
| where: { id }, | |
| data: { status: 'IN_TRANSIT' }, | |
| }); | |
| // Also update shipment status | |
| await prisma.shipment.update({ | |
| where: { id: delivery.shipmentId }, | |
| data: { status: 'IN_TRANSIT' }, | |
| }); | |
| res.status(200).json({ | |
| success: true, | |
| message: 'Delivery started', | |
| data: updatedDelivery, | |
| }); | |
| } catch (error) { | |
| console.error('Start delivery error:', error); | |
| res.status(500).json({ | |
| success: false, | |
| message: 'Failed to start delivery', | |
| }); | |
| } | |
| }; | |
| /** | |
| * POST /api/deliveries/:id/pickup - Cargo loaded | |
| */ | |
| const pickupCargo = async (req, res) => { | |
| try { | |
| const { id } = req.params; | |
| const delivery = await prisma.delivery.findUnique({ | |
| where: { id }, | |
| }); | |
| if (!delivery || delivery.driverId !== req.user.id) { | |
| return res.status(404).json({ | |
| success: false, | |
| message: 'Delivery not found', | |
| }); | |
| } | |
| const updatedDelivery = await prisma.delivery.update({ | |
| where: { id }, | |
| data: { | |
| status: 'CARGO_LOADED', | |
| pickupTime: new Date(), | |
| }, | |
| }); | |
| res.status(200).json({ | |
| success: true, | |
| message: 'Cargo marked as picked up', | |
| data: updatedDelivery, | |
| }); | |
| } catch (error) { | |
| console.error('Pickup cargo error:', error); | |
| res.status(500).json({ | |
| success: false, | |
| message: 'Failed to mark cargo as picked up', | |
| }); | |
| } | |
| }; | |
| /** | |
| * POST /api/deliveries/:id/complete - Delivery complete | |
| */ | |
| const completeDelivery = async (req, res) => { | |
| try { | |
| const { id } = req.params; | |
| const delivery = await prisma.delivery.findUnique({ | |
| where: { id }, | |
| include: { shipment: true }, | |
| }); | |
| if (!delivery || delivery.driverId !== req.user.id) { | |
| return res.status(404).json({ | |
| success: false, | |
| message: 'Delivery not found', | |
| }); | |
| } | |
| // Update delivery status | |
| const updatedDelivery = await prisma.delivery.update({ | |
| where: { id }, | |
| data: { | |
| status: 'COMPLETED', | |
| completedAt: new Date(), | |
| dropTime: new Date(), | |
| }, | |
| }); | |
| // Update shipment if exists | |
| if (delivery.shipmentId) { | |
| await prisma.shipment.update({ | |
| where: { id: delivery.shipmentId }, | |
| data: { status: 'COMPLETED' }, | |
| }); | |
| } | |
| // Create transaction record | |
| const transaction = await prisma.transaction.create({ | |
| data: { | |
| driverId: req.user.id, | |
| deliveryId: id, | |
| amount: delivery.totalEarnings || 0, | |
| type: 'BASE_DELIVERY', | |
| description: `Payment for delivery ${id}`, | |
| route: `${delivery.pickupLocation} → ${delivery.dropLocation}`, | |
| }, | |
| }); | |
| // Update driver's total earnings | |
| await prisma.user.update({ | |
| where: { id: req.user.id }, | |
| data: { | |
| totalEarnings: { increment: delivery.totalEarnings || 0 }, | |
| weeklyEarnings: { increment: delivery.totalEarnings || 0 }, | |
| deliveriesCount: { increment: 1 }, | |
| totalDistanceKm: { increment: delivery.distanceKm || 0 }, | |
| }, | |
| }); | |
| res.status(200).json({ | |
| success: true, | |
| message: 'Delivery completed successfully', | |
| data: { | |
| delivery: updatedDelivery, | |
| transaction, | |
| }, | |
| }); | |
| } catch (error) { | |
| console.error('Complete delivery error:', error); | |
| res.status(500).json({ | |
| success: false, | |
| message: 'Failed to complete delivery', | |
| }); | |
| } | |
| }; | |
| /** | |
| * POST /api/deliveries/:id/upload-photos - Upload photos (4 angles) | |
| */ | |
| const uploadPhotos = async (req, res) => { | |
| try { | |
| const { id } = req.params; | |
| const { photos } = req.body; // Expecting array of URLs | |
| if (!photos || !Array.isArray(photos)) { | |
| return res.status(400).json({ | |
| success: false, | |
| message: 'Photos are required as an array of URLs', | |
| }); | |
| } | |
| const delivery = await prisma.delivery.findUnique({ | |
| where: { id }, | |
| }); | |
| if (!delivery || delivery.driverId !== req.user.id) { | |
| return res.status(404).json({ | |
| success: false, | |
| message: 'Delivery not found', | |
| }); | |
| } | |
| // In a real app, we'd handle file uploads here. | |
| // For now, we update the relay node or delivery record if applicable. | |
| // Assuming delivery has a way to store photos or it's linked to a relay node. | |
| res.status(200).json({ | |
| success: true, | |
| message: 'Photos uploaded successfully (simulated)', | |
| count: photos.length, | |
| }); | |
| } catch (error) { | |
| console.error('Upload photos error:', error); | |
| res.status(500).json({ | |
| success: false, | |
| message: 'Failed to upload photos', | |
| }); | |
| } | |
| }; | |
| /** | |
| * POST /api/deliveries/create - Create new delivery from package form | |
| */ | |
| const createDelivery = async (req, res) => { | |
| try { | |
| const { | |
| pickupLocation, | |
| pickupLat, | |
| pickupLng, | |
| pickupTime, | |
| deliveryLocation, | |
| deliveryLat, | |
| deliveryLng, | |
| deliveryTime, | |
| cargoType, | |
| cargoWeight, | |
| cargoVolumeLtrs, | |
| cargoValue, | |
| specialInstructions, | |
| courierCompanyId, | |
| dispatcherId, | |
| distanceKm, | |
| postalCode, | |
| timeWindowStart, | |
| timeWindowEnd | |
| } = req.body; | |
| // Validate required fields | |
| if (!pickupLocation || !deliveryLocation || !cargoType || !cargoWeight || !cargoVolumeLtrs) { | |
| return res.status(400).json({ | |
| success: false, | |
| message: 'Missing required fields: pickupLocation, deliveryLocation, cargoType, cargoWeight, cargoVolumeLtrs' | |
| }); | |
| } | |
| // Validate coordinates | |
| if (!pickupLat || !pickupLng || !deliveryLat || !deliveryLng) { | |
| return res.status(400).json({ | |
| success: false, | |
| message: 'Missing required coordinates: pickupLat, pickupLng, deliveryLat, deliveryLng' | |
| }); | |
| } | |
| // Validate dispatcherId | |
| const finalDispatcherId = dispatcherId || (req.user ? req.user.id : null); | |
| if (!finalDispatcherId) { | |
| return res.status(400).json({ | |
| success: false, | |
| message: 'dispatcherId is required' | |
| }); | |
| } | |
| // Generate unique package ID | |
| const packageId = `PKG-${Date.now()}-${Math.random().toString(36).substr(2, 9).toUpperCase()}`; | |
| // Create delivery record | |
| const delivery = await prisma.delivery.create({ | |
| data: { | |
| packageId, | |
| pickupLocation, | |
| pickupLat: parseFloat(pickupLat), | |
| pickupLng: parseFloat(pickupLng), | |
| pickupTime: pickupTime ? new Date(pickupTime) : null, | |
| dropLocation: deliveryLocation, | |
| dropLat: parseFloat(deliveryLat), | |
| dropLng: parseFloat(deliveryLng), | |
| dropTime: deliveryTime ? new Date(deliveryTime) : null, | |
| cargoType, | |
| cargoWeight: parseFloat(cargoWeight), | |
| cargoVolumeLtrs: parseFloat(cargoVolumeLtrs), | |
| distanceKm: distanceKm ? parseFloat(distanceKm) : null, | |
| postalCode: postalCode || null, | |
| timeWindowStart: timeWindowStart ? new Date(timeWindowStart) : null, | |
| timeWindowEnd: timeWindowEnd ? new Date(timeWindowEnd) : null, | |
| // specialInstructions: specialInstructions || null, | |
| courierCompanyId: courierCompanyId || null, | |
| status: 'PENDING', | |
| dispatcherId: finalDispatcherId | |
| } | |
| }); | |
| res.status(201).json({ | |
| success: true, | |
| message: 'Delivery created successfully', | |
| data: delivery | |
| }); | |
| } catch (error) { | |
| console.error('Create delivery error:', error); | |
| res.status(500).json({ | |
| success: false, | |
| message: 'Failed to create delivery', | |
| error: error.message | |
| }); | |
| } | |
| }; | |
| /** | |
| * GET /api/deliveries/unassigned - Dispatcher's list of unassigned pending deliveries | |
| */ | |
| const getUnassignedDeliveries = async (req, res) => { | |
| try { | |
| const { courierCompanyId } = req.query; | |
| if (!courierCompanyId) { | |
| return res.status(400).json({ | |
| success: false, | |
| message: 'courierCompanyId is required', | |
| }); | |
| } | |
| const whereClause = { | |
| status: 'PENDING', | |
| driverId: null, | |
| truckId: null, | |
| optimizedRouteId: null, | |
| OR: [ | |
| { courierCompanyId: courierCompanyId }, | |
| { courierCompanyId: null } | |
| ] | |
| }; | |
| const [count, deliveries] = await Promise.all([ | |
| prisma.delivery.count({ where: whereClause }), | |
| prisma.delivery.findMany({ | |
| where: whereClause, | |
| include: { | |
| shipment: true, | |
| }, | |
| orderBy: { | |
| createdAt: 'desc', | |
| }, | |
| }), | |
| ]); | |
| res.status(200).json({ | |
| success: true, | |
| data: { | |
| count, | |
| deliveries, | |
| }, | |
| }); | |
| } catch (error) { | |
| console.error('Get unassigned deliveries error:', error); | |
| res.status(500).json({ | |
| success: false, | |
| message: 'Failed to fetch unassigned deliveries', | |
| error: error.message, | |
| }); | |
| } | |
| }; | |
| module.exports = { | |
| getAssignedDeliveries, | |
| acceptDelivery, | |
| rejectDelivery, | |
| startDelivery, | |
| pickupCargo, | |
| completeDelivery, | |
| uploadPhotos, | |
| createDelivery, | |
| getUnassignedDeliveries, | |
| }; |