import { Router } from 'express'; import { body, param } from 'express-validator'; import { pipelinesController, dealsController, quotesController } from './crm.controller'; import { costSheetsController } from './costSheets.controller'; import { contractsController } from './contracts.controller'; import { invoicesController } from './invoices.controller'; import { authenticate, authorize } from '../../shared/middleware/auth'; import { validate } from '../../shared/middleware/validation'; const router = Router(); // All routes require authentication router.use(authenticate); // ============= PIPELINES ============= // Get all pipelines router.get( '/pipelines', authorize('crm', 'deals', 'read'), pipelinesController.findAll ); // Get pipeline by ID router.get( '/pipelines/:id', authorize('crm', 'deals', 'read'), param('id').isUUID(), validate, pipelinesController.findById ); // ============= DEALS ============= // Get all deals router.get( '/deals', authorize('crm', 'deals', 'read'), dealsController.findAll ); // Get deal by ID router.get( '/deals/:id', authorize('crm', 'deals', 'read'), param('id').isUUID(), validate, dealsController.findById ); // Get deal history router.get( '/deals/:id/history', authorize('crm', 'deals', 'read'), param('id').isUUID(), validate, dealsController.getHistory ); // Create deal router.post( '/deals', authorize('crm', 'deals', 'create'), [ body('name').notEmpty().trim(), body('contactId').isUUID(), body('structure').isIn(['B2B', 'B2C', 'B2G', 'PARTNERSHIP']), body('pipelineId').isUUID(), body('stage').notEmpty(), body('estimatedValue').isNumeric(), validate, ], dealsController.create ); // Update deal router.put( '/deals/:id', authorize('crm', 'deals', 'update'), param('id').isUUID(), validate, dealsController.update ); // Update deal stage router.patch( '/deals/:id/stage', authorize('crm', 'deals', 'update'), [ param('id').isUUID(), body('stage').notEmpty(), validate, ], dealsController.updateStage ); // Mark deal as won router.post( '/deals/:id/win', authorize('crm', 'deals', 'update'), [ param('id').isUUID(), body('actualValue').isNumeric(), body('wonReason').notEmpty(), validate, ], dealsController.win ); // Mark deal as lost router.post( '/deals/:id/lose', authorize('crm', 'deals', 'update'), [ param('id').isUUID(), body('lostReason').notEmpty(), validate, ], dealsController.lose ); // ============= QUOTES ============= // Get quotes for a deal router.get( '/deals/:dealId/quotes', authorize('crm', 'quotes', 'read'), param('dealId').isUUID(), validate, quotesController.findByDeal ); // Get quote by ID router.get( '/quotes/:id', authorize('crm', 'quotes', 'read'), param('id').isUUID(), validate, quotesController.findById ); // Create quote router.post( '/quotes', authorize('crm', 'quotes', 'create'), [ body('dealId').isUUID(), body('items').isArray(), body('subtotal').isNumeric(), body('taxRate').isNumeric(), body('taxAmount').isNumeric(), body('total').isNumeric(), body('validUntil').isISO8601(), validate, ], quotesController.create ); // Approve quote router.post( '/quotes/:id/approve', authorize('crm', 'quotes', 'approve'), param('id').isUUID(), validate, quotesController.approve ); // Send quote router.post( '/quotes/:id/send', authorize('crm', 'quotes', 'update'), param('id').isUUID(), validate, quotesController.send ); // ============= COST SHEETS ============= router.get( '/deals/:dealId/cost-sheets', authorize('crm', 'deals', 'read'), param('dealId').isUUID(), validate, costSheetsController.findByDeal ); router.get( '/cost-sheets/:id', authorize('crm', 'deals', 'read'), param('id').isUUID(), validate, costSheetsController.findById ); router.post( '/cost-sheets', authorize('crm', 'deals', 'create'), [ body('dealId').isUUID(), body('items').isArray(), body('totalCost').isNumeric(), body('suggestedPrice').isNumeric(), body('profitMargin').isNumeric(), validate, ], costSheetsController.create ); router.post( '/cost-sheets/:id/approve', authorize('crm', 'deals', 'update'), param('id').isUUID(), validate, costSheetsController.approve ); router.post( '/cost-sheets/:id/reject', authorize('crm', 'deals', 'update'), param('id').isUUID(), validate, costSheetsController.reject ); // ============= CONTRACTS ============= router.get( '/deals/:dealId/contracts', authorize('crm', 'deals', 'read'), param('dealId').isUUID(), validate, contractsController.findByDeal ); router.get( '/contracts/:id', authorize('crm', 'deals', 'read'), param('id').isUUID(), validate, contractsController.findById ); router.post( '/contracts', authorize('crm', 'deals', 'create'), [ body('dealId').isUUID(), body('title').notEmpty().trim(), body('type').notEmpty().trim(), body('startDate').isISO8601(), body('value').isNumeric(), body('terms').notEmpty().trim(), validate, ], contractsController.create ); router.put( '/contracts/:id', authorize('crm', 'deals', 'update'), param('id').isUUID(), validate, contractsController.update ); router.post( '/contracts/:id/sign', authorize('crm', 'deals', 'update'), param('id').isUUID(), validate, contractsController.markSigned ); // ============= INVOICES ============= router.get( '/deals/:dealId/invoices', authorize('crm', 'deals', 'read'), param('dealId').isUUID(), validate, invoicesController.findByDeal ); router.get( '/invoices/:id', authorize('crm', 'deals', 'read'), param('id').isUUID(), validate, invoicesController.findById ); router.post( '/invoices', authorize('crm', 'deals', 'create'), [ body('items').isArray(), body('subtotal').isNumeric(), body('taxAmount').isNumeric(), body('total').isNumeric(), body('dueDate').isISO8601(), validate, ], invoicesController.create ); router.put( '/invoices/:id', authorize('crm', 'deals', 'update'), param('id').isUUID(), validate, invoicesController.update ); router.post( '/invoices/:id/record-payment', authorize('crm', 'deals', 'update'), [ param('id').isUUID(), body('paidAmount').isNumeric(), validate, ], invoicesController.recordPayment ); export default router;