327 lines
6.3 KiB
TypeScript
327 lines
6.3 KiB
TypeScript
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;
|
|
|