Files
zerp/backend/src/modules/crm/crm.routes.ts
2026-03-11 16:40:25 +04:00

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;