feat(crm): add contracts, cost sheets, invoices modules and API clients

Made-with: Cursor
This commit is contained in:
Talal Sharabi
2026-03-11 16:40:25 +04:00
parent 8a20927044
commit 18c13cdf7c
12 changed files with 1483 additions and 10 deletions

View File

@@ -1,6 +1,9 @@
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';
@@ -171,5 +174,153 @@ router.post(
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;