diff --git a/src/docs/assets-routes.yaml b/src/docs/assets-routes.yaml index ce97f62..56c7abd 100644 --- a/src/docs/assets-routes.yaml +++ b/src/docs/assets-routes.yaml @@ -273,6 +273,87 @@ components: remarks: { type: string } paths: + /assets/options: + get: + tags: [Assets] + summary: All asset module dropdown options in one call + description: Returns contract_types, visit_types, policy_types, conditions, statuses, frequencies, etc. + responses: + '200': + description: Options fetched + content: { application/json: { schema: { $ref: '#/components/schemas/ApiResponse' } } } + /assets/contract-types: + get: + tags: [Assets] + summary: AMC contract type dropdown options + responses: + '200': + description: Contract types fetched + content: { application/json: { schema: { $ref: '#/components/schemas/ApiResponse' } } } + /assets/visit-types: + get: + tags: [Assets] + summary: Service visit type dropdown options + responses: + '200': + description: Visit types fetched + content: { application/json: { schema: { $ref: '#/components/schemas/ApiResponse' } } } + /assets/policy-types: + get: + tags: [Assets] + summary: Insurance policy type dropdown options + responses: + '200': + description: Policy types fetched + content: { application/json: { schema: { $ref: '#/components/schemas/ApiResponse' } } } + /assets/conditions: + get: + tags: [Assets] + summary: Asset condition dropdown options + responses: + '200': + description: Asset conditions fetched + content: { application/json: { schema: { $ref: '#/components/schemas/ApiResponse' } } } + /assets/statuses: + get: + tags: [Assets] + summary: Asset status dropdown options + responses: + '200': + description: Asset statuses fetched + content: { application/json: { schema: { $ref: '#/components/schemas/ApiResponse' } } } + /assets/payment-frequencies: + get: + tags: [Assets] + summary: AMC payment frequency dropdown options + responses: + '200': + description: Payment frequencies fetched + content: { application/json: { schema: { $ref: '#/components/schemas/ApiResponse' } } } + /assets/service-frequencies: + get: + tags: [Assets] + summary: AMC service frequency dropdown options + responses: + '200': + description: Service frequencies fetched + content: { application/json: { schema: { $ref: '#/components/schemas/ApiResponse' } } } + /assets/visit-statuses: + get: + tags: [Assets] + summary: Service visit status dropdown options + responses: + '200': + description: Visit statuses fetched + content: { application/json: { schema: { $ref: '#/components/schemas/ApiResponse' } } } + /assets/visit-conditions-after: + get: + tags: [Assets] + summary: Asset condition after visit dropdown options + responses: + '200': + description: Visit condition options fetched + content: { application/json: { schema: { $ref: '#/components/schemas/ApiResponse' } } } /assets/depreciation-methods: get: tags: [Assets] diff --git a/src/modules/assets/assets.constants.js b/src/modules/assets/assets.constants.js index 7f74984..f81edbb 100644 --- a/src/modules/assets/assets.constants.js +++ b/src/modules/assets/assets.constants.js @@ -1,36 +1,105 @@ -const ASSET_CONDITIONS = ['NEW', 'GOOD', 'FAIR', 'POOR']; -const ASSET_STATUSES = ['IN_USE', 'IDLE', 'UNDER_MAINTENANCE', 'DISPOSED', 'SCRAPPED']; -const DEPRECIATION_METHODS = ['SLM', 'WDV', 'OTHER']; +const toOptions = (entries) => + entries.map(([value, label]) => ({ value, label })); + +const ASSET_CONDITION_OPTIONS = toOptions([ + ['NEW', 'New'], + ['GOOD', 'Good'], + ['FAIR', 'Fair'], + ['POOR', 'Poor'], +]); + +const ASSET_STATUS_OPTIONS = toOptions([ + ['IN_USE', 'In Use'], + ['IDLE', 'Idle'], + ['UNDER_MAINTENANCE', 'Under Maintenance'], + ['DISPOSED', 'Disposed'], + ['SCRAPPED', 'Scrapped'], +]); + +const DEPRECIATION_METHOD_VALUES = ['SLM', 'WDV', 'OTHER']; + +const AMC_CONTRACT_TYPE_OPTIONS = toOptions([ + ['COMPREHENSIVE', 'Comprehensive'], + ['LABOUR_ONLY', 'Labour Only'], + ['PARTS_ONLY', 'Parts Only'], + ['PREVENTIVE_ONLY', 'Preventive Only'], +]); + +const PAYMENT_FREQUENCY_OPTIONS = toOptions([ + ['MONTHLY', 'Monthly'], + ['QUARTERLY', 'Quarterly'], + ['HALF_YEARLY', 'Half Yearly'], + ['ANNUAL', 'Annual'], +]); + +const SERVICE_FREQUENCY_OPTIONS = toOptions([ + ['MONTHLY', 'Monthly'], + ['QUARTERLY', 'Quarterly'], + ['HALF_YEARLY', 'Half Yearly'], + ['ANNUAL', 'Annual'], +]); + +const VISIT_TYPE_OPTIONS = toOptions([ + ['PREVENTIVE', 'Preventive'], + ['BREAKDOWN', 'Breakdown'], + ['INSPECTION', 'Inspection'], + ['INSTALLATION', 'Installation'], + ['CALIBRATION', 'Calibration'], + ['OTHER', 'Other'], +]); + +const VISIT_STATUS_OPTIONS = toOptions([ + ['SCHEDULED', 'Scheduled'], + ['IN_PROGRESS', 'In Progress'], + ['COMPLETED', 'Completed'], + ['CANCELLED', 'Cancelled'], + ['PENDING_PARTS', 'Pending Parts'], +]); + +const VISIT_CONDITION_AFTER_OPTIONS = toOptions([ + ['GOOD', 'Good'], + ['FAIR', 'Fair'], + ['POOR', 'Poor'], + ['NEEDS_REPLACEMENT', 'Needs Replacement'], +]); + +const INSURANCE_POLICY_TYPE_OPTIONS = toOptions([ + ['FIRE_AND_ALLIED', 'Fire and Allied'], + ['MACHINERY_BREAKDOWN', 'Machinery Breakdown'], + ['COMPREHENSIVE', 'Comprehensive'], + ['THIRD_PARTY', 'Third Party'], + ['VEHICLE', 'Vehicle'], + ['OTHER', 'Other'], +]); + +const ASSET_CONDITIONS = ASSET_CONDITION_OPTIONS.map((o) => o.value); +const ASSET_STATUSES = ASSET_STATUS_OPTIONS.map((o) => o.value); +const DEPRECIATION_METHODS = DEPRECIATION_METHOD_VALUES; const DISPOSAL_STATUSES = ['DISPOSED', 'SCRAPPED']; - -const AMC_CONTRACT_TYPES = ['COMPREHENSIVE', 'LABOUR_ONLY', 'PARTS_ONLY', 'PREVENTIVE_ONLY']; -const PAYMENT_FREQUENCIES = ['MONTHLY', 'QUARTERLY', 'HALF_YEARLY', 'ANNUAL']; -const SERVICE_FREQUENCIES = ['MONTHLY', 'QUARTERLY', 'HALF_YEARLY', 'ANNUAL']; - -const VISIT_TYPES = [ - 'PREVENTIVE', - 'BREAKDOWN', - 'INSPECTION', - 'INSTALLATION', - 'CALIBRATION', - 'OTHER', -]; -const VISIT_STATUSES = ['SCHEDULED', 'IN_PROGRESS', 'COMPLETED', 'CANCELLED', 'PENDING_PARTS']; -const VISIT_CONDITION_AFTER = ['GOOD', 'FAIR', 'POOR', 'NEEDS_REPLACEMENT']; - -const INSURANCE_POLICY_TYPES = [ - 'FIRE_AND_ALLIED', - 'MACHINERY_BREAKDOWN', - 'COMPREHENSIVE', - 'THIRD_PARTY', - 'VEHICLE', - 'OTHER', -]; +const AMC_CONTRACT_TYPES = AMC_CONTRACT_TYPE_OPTIONS.map((o) => o.value); +const PAYMENT_FREQUENCIES = PAYMENT_FREQUENCY_OPTIONS.map((o) => o.value); +const SERVICE_FREQUENCIES = SERVICE_FREQUENCY_OPTIONS.map((o) => o.value); +const VISIT_TYPES = VISIT_TYPE_OPTIONS.map((o) => o.value); +const VISIT_STATUSES = VISIT_STATUS_OPTIONS.map((o) => o.value); +const VISIT_CONDITION_AFTER = VISIT_CONDITION_AFTER_OPTIONS.map((o) => o.value); +const INSURANCE_POLICY_TYPES = INSURANCE_POLICY_TYPE_OPTIONS.map((o) => o.value); const ALERT_TYPES = ['AMC', 'INSURANCE', 'WARRANTY']; const ALERT_LEVELS = ['EXPIRED', 'CRITICAL', 'WARNING', 'INFO']; const SERVICE_ALERT_STATUSES = ['OVERDUE', 'DUE_THIS_WEEK', 'DUE_THIS_MONTH', 'UPCOMING']; +const getAssetDropdownOptions = () => ({ + contract_types: AMC_CONTRACT_TYPE_OPTIONS, + visit_types: VISIT_TYPE_OPTIONS, + policy_types: INSURANCE_POLICY_TYPE_OPTIONS, + asset_conditions: ASSET_CONDITION_OPTIONS, + asset_statuses: ASSET_STATUS_OPTIONS, + payment_frequencies: PAYMENT_FREQUENCY_OPTIONS, + service_frequencies: SERVICE_FREQUENCY_OPTIONS, + visit_statuses: VISIT_STATUS_OPTIONS, + visit_conditions_after: VISIT_CONDITION_AFTER_OPTIONS, +}); + module.exports = { ASSET_CONDITIONS, ASSET_STATUSES, @@ -46,4 +115,14 @@ module.exports = { ALERT_TYPES, ALERT_LEVELS, SERVICE_ALERT_STATUSES, + ASSET_CONDITION_OPTIONS, + ASSET_STATUS_OPTIONS, + AMC_CONTRACT_TYPE_OPTIONS, + PAYMENT_FREQUENCY_OPTIONS, + SERVICE_FREQUENCY_OPTIONS, + VISIT_TYPE_OPTIONS, + VISIT_STATUS_OPTIONS, + VISIT_CONDITION_AFTER_OPTIONS, + INSURANCE_POLICY_TYPE_OPTIONS, + getAssetDropdownOptions, }; diff --git a/src/modules/assets/assets.controller.js b/src/modules/assets/assets.controller.js index a82eeb3..e8b9880 100644 --- a/src/modules/assets/assets.controller.js +++ b/src/modules/assets/assets.controller.js @@ -177,6 +177,48 @@ const listDepreciationMethods = asyncHandler(async (_req, res) => { res.json(new ApiResponse(200, data, 'Depreciation methods fetched')); }); +const listContractTypes = asyncHandler(async (_req, res) => { + res.json(new ApiResponse(200, service.listContractTypes(), 'Contract types fetched')); +}); + +const listVisitTypes = asyncHandler(async (_req, res) => { + res.json(new ApiResponse(200, service.listVisitTypes(), 'Visit types fetched')); +}); + +const listPolicyTypes = asyncHandler(async (_req, res) => { + res.json(new ApiResponse(200, service.listPolicyTypes(), 'Policy types fetched')); +}); + +const listAssetConditions = asyncHandler(async (_req, res) => { + res.json(new ApiResponse(200, service.listAssetConditions(), 'Asset conditions fetched')); +}); + +const listAssetStatuses = asyncHandler(async (_req, res) => { + res.json(new ApiResponse(200, service.listAssetStatuses(), 'Asset statuses fetched')); +}); + +const listPaymentFrequencies = asyncHandler(async (_req, res) => { + res.json(new ApiResponse(200, service.listPaymentFrequencies(), 'Payment frequencies fetched')); +}); + +const listServiceFrequencies = asyncHandler(async (_req, res) => { + res.json(new ApiResponse(200, service.listServiceFrequencies(), 'Service frequencies fetched')); +}); + +const listVisitStatuses = asyncHandler(async (_req, res) => { + res.json(new ApiResponse(200, service.listVisitStatuses(), 'Visit statuses fetched')); +}); + +const listVisitConditionsAfter = asyncHandler(async (_req, res) => { + res.json( + new ApiResponse(200, service.listVisitConditionsAfter(), 'Visit condition options fetched') + ); +}); + +const listAssetOptions = asyncHandler(async (_req, res) => { + res.json(new ApiResponse(200, service.listAssetOptions(), 'Asset dropdown options fetched')); +}); + const calculateDepreciation = asyncHandler(async (req, res) => { const data = service.previewDepreciation(req.body); res.json(new ApiResponse(200, data, 'Depreciation calculated')); @@ -191,6 +233,16 @@ module.exports = { transfer, transferHistory, listDepreciationMethods, + listContractTypes, + listVisitTypes, + listPolicyTypes, + listAssetConditions, + listAssetStatuses, + listPaymentFrequencies, + listServiceFrequencies, + listVisitStatuses, + listVisitConditionsAfter, + listAssetOptions, calculateDepreciation, listAmc, createAmc, diff --git a/src/modules/assets/assets.routes.js b/src/modules/assets/assets.routes.js index 4e0d45a..1225be9 100644 --- a/src/modules/assets/assets.routes.js +++ b/src/modules/assets/assets.routes.js @@ -56,6 +56,21 @@ router.post( controller.calculateDepreciation ); +router.get('/options', authorize('ASSET', 'view'), controller.listAssetOptions); +router.get('/contract-types', authorize('ASSET', 'view'), controller.listContractTypes); +router.get('/visit-types', authorize('ASSET', 'view'), controller.listVisitTypes); +router.get('/policy-types', authorize('ASSET', 'view'), controller.listPolicyTypes); +router.get('/conditions', authorize('ASSET', 'view'), controller.listAssetConditions); +router.get('/statuses', authorize('ASSET', 'view'), controller.listAssetStatuses); +router.get('/payment-frequencies', authorize('ASSET', 'view'), controller.listPaymentFrequencies); +router.get('/service-frequencies', authorize('ASSET', 'view'), controller.listServiceFrequencies); +router.get('/visit-statuses', authorize('ASSET', 'view'), controller.listVisitStatuses); +router.get( + '/visit-conditions-after', + authorize('ASSET', 'view'), + controller.listVisitConditionsAfter +); + router.get('/:id/amc', authorize('ASSET', 'view'), controller.listAmc); router.post( '/:id/amc', diff --git a/src/modules/assets/assets.service.js b/src/modules/assets/assets.service.js index 1516684..29edd67 100644 --- a/src/modules/assets/assets.service.js +++ b/src/modules/assets/assets.service.js @@ -3,7 +3,7 @@ const ApiError = require('../../utils/ApiError'); const auditLog = require('../../utils/auditLog'); const { getPagination } = require('../../utils/pagination'); const { nextDocumentNumber } = require('../../utils/generateCode'); -const { DISPOSAL_STATUSES } = require('./assets.constants'); +const { DISPOSAL_STATUSES, getAssetDropdownOptions } = require('./assets.constants'); const { assertPlant, assertWarehouse } = require('../../utils/locations'); const repository = require('./assets.repository'); const { @@ -526,6 +526,17 @@ const getTransferHistory = async (id) => { const listDepreciationMethods = () => DEPRECIATION_METHOD_OPTIONS; +const listContractTypes = () => getAssetDropdownOptions().contract_types; +const listVisitTypes = () => getAssetDropdownOptions().visit_types; +const listPolicyTypes = () => getAssetDropdownOptions().policy_types; +const listAssetConditions = () => getAssetDropdownOptions().asset_conditions; +const listAssetStatuses = () => getAssetDropdownOptions().asset_statuses; +const listPaymentFrequencies = () => getAssetDropdownOptions().payment_frequencies; +const listServiceFrequencies = () => getAssetDropdownOptions().service_frequencies; +const listVisitStatuses = () => getAssetDropdownOptions().visit_statuses; +const listVisitConditionsAfter = () => getAssetDropdownOptions().visit_conditions_after; +const listAssetOptions = () => getAssetDropdownOptions(); + const previewDepreciation = (payload) => { if (payload.depreciation_method === 'OTHER' && (payload.depreciation_rate === undefined || payload.depreciation_rate === null)) { throw new ApiError(422, 'depreciation_rate is required when depreciation_method is OTHER'); @@ -542,5 +553,15 @@ module.exports = { transferAsset, getTransferHistory, listDepreciationMethods, + listContractTypes, + listVisitTypes, + listPolicyTypes, + listAssetConditions, + listAssetStatuses, + listPaymentFrequencies, + listServiceFrequencies, + listVisitStatuses, + listVisitConditionsAfter, + listAssetOptions, previewDepreciation, };