Files
bigcapital/packages/server/src/api/controllers/Warehouses/WarehouseTransfers.ts
2023-02-03 11:57:50 +02:00

408 lines
11 KiB
TypeScript

import { Service, Inject } from 'typedi';
import { Request, Response, Router, NextFunction } from 'express';
import { query, check, param } from 'express-validator';
import BaseController from '@/api/controllers/BaseController';
import { WarehouseTransferApplication } from '@/services/Warehouses/WarehousesTransfers/WarehouseTransferApplication';
import {
Features,
ICreateWarehouseTransferDTO,
IEditWarehouseTransferDTO,
} from '@/interfaces';
import { ServiceError } from '@/exceptions';
import { FeatureActivationGuard } from '@/api/middleware/FeatureActivationGuard';
@Service()
export class WarehousesTransfers extends BaseController {
@Inject()
private warehouseTransferApplication: WarehouseTransferApplication;
/**
*
*/
router() {
const router = Router();
router.post(
'/',
FeatureActivationGuard(Features.WAREHOUSES),
[
check('from_warehouse_id').exists().isInt().toInt(),
check('to_warehouse_id').exists().isInt().toInt(),
check('date').exists().isISO8601(),
check('transaction_number').optional(),
check('transfer_initiated').default(false).isBoolean().toBoolean(),
check('transfer_delivered').default(false).isBoolean().toBoolean(),
check('entries').exists().isArray({ min: 1 }),
check('entries.*.index').exists(),
check('entries.*.item_id').exists(),
check('entries.*.description').optional(),
check('entries.*.quantity').exists().isInt().toInt(),
check('entries.*.cost').optional().isDecimal().toFloat(),
],
this.validationResult,
this.asyncMiddleware(this.createWarehouseTransfer),
this.handlerServiceErrors
);
router.post(
'/:id',
FeatureActivationGuard(Features.WAREHOUSES),
[
param('id').exists().isInt().toInt(),
check('from_warehouse_id').exists().isInt().toInt(),
check('to_warehouse_id').exists().isInt().toInt(),
check('date').exists().isISO8601(),
check('transaction_number').optional(),
check('transfer_initiated').default(false).isBoolean().toBoolean(),
check('transfer_delivered').default(false).isBoolean().toBoolean(),
check('entries').exists().isArray({ min: 1 }),
check('entries.*.id').optional().isInt().toInt(),
check('entries.*.index').exists(),
check('entries.*.item_id').exists().isInt().toInt(),
check('entries.*.description').optional(),
check('entries.*.quantity').exists().isInt({ min: 1 }).toInt(),
check('entries.*.cost').optional().isDecimal().toFloat(),
],
this.validationResult,
this.asyncMiddleware(this.editWarehouseTransfer),
this.handlerServiceErrors
);
router.put(
'/:id/initiate',
FeatureActivationGuard(Features.WAREHOUSES),
[param('id').exists().isInt().toInt()],
this.asyncMiddleware(this.initiateTransfer),
this.handlerServiceErrors
);
router.put(
'/:id/transferred',
FeatureActivationGuard(Features.WAREHOUSES),
[param('id').exists().isInt().toInt()],
this.asyncMiddleware(this.deliverTransfer),
this.handlerServiceErrors
);
router.get(
'/',
FeatureActivationGuard(Features.WAREHOUSES),
[
query('view_slug').optional({ nullable: true }).isString().trim(),
query('stringified_filter_roles').optional().isJSON(),
query('column_sort_by').optional(),
query('sort_order').optional().isIn(['desc', 'asc']),
query('page').optional().isNumeric().toInt(),
query('page_size').optional().isNumeric().toInt(),
query('search_keyword').optional({ nullable: true }).isString().trim(),
],
this.validationResult,
this.asyncMiddleware(this.getWarehousesTransfers),
this.handlerServiceErrors
);
router.get(
'/:id',
[param('id').exists().isInt().toInt()],
this.validationResult,
this.asyncMiddleware(this.getWarehouseTransfer),
this.handlerServiceErrors
);
router.delete(
'/:id',
FeatureActivationGuard(Features.WAREHOUSES),
[param('id').exists().isInt().toInt()],
this.validationResult,
this.asyncMiddleware(this.deleteWarehouseTransfer),
this.handlerServiceErrors
);
return router;
}
/**
* Creates a new warehouse transfer transaction.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
* @returns {Response}
*/
private createWarehouseTransfer = async (
req: Request,
res: Response,
next: NextFunction
) => {
const { tenantId } = req;
const createWareouseTransfer: ICreateWarehouseTransferDTO =
this.matchedBodyData(req);
try {
const warehouse =
await this.warehouseTransferApplication.createWarehouseTransfer(
tenantId,
createWareouseTransfer
);
return res.status(200).send({
id: warehouse.id,
message:
'The warehouse transfer transaction has been created successfully.',
});
} catch (error) {
next(error);
}
};
/**
* Edits warehouse transfer transaction.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
* @returns {Response}
*/
private editWarehouseTransfer = async (
req: Request,
res: Response,
next: NextFunction
) => {
const { tenantId } = req;
const { id: warehouseTransferId } = req.params;
const editWarehouseTransferDTO: IEditWarehouseTransferDTO =
this.matchedBodyData(req);
try {
const warehouseTransfer =
await this.warehouseTransferApplication.editWarehouseTransfer(
tenantId,
warehouseTransferId,
editWarehouseTransferDTO
);
return res.status(200).send({
id: warehouseTransfer.id,
message:
'The warehouse transfer transaction has been edited successfully.',
});
} catch (error) {
next(error);
}
};
/**
* Deletes the given warehouse transfer transaction.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
* @returns {Response}
*/
private deleteWarehouseTransfer = async (
req: Request,
res: Response,
next: NextFunction
) => {
const { tenantId } = req;
const { id: warehouseTransferId } = req.params;
try {
await this.warehouseTransferApplication.deleteWarehouseTransfer(
tenantId,
warehouseTransferId
);
return res.status(200).send({
message:
'The warehouse transfer transaction has been deleted successfully.',
});
} catch (error) {
next(error);
}
};
/**
* Retrieves warehouse transfer transaction details.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
* @returns {Response}
*/
private getWarehouseTransfer = async (
req: Request,
res: Response,
next: NextFunction
) => {
const { tenantId } = req;
const { id: warehouseTransferId } = req.params;
try {
const warehouseTransfer =
await this.warehouseTransferApplication.getWarehouseTransfer(
tenantId,
warehouseTransferId
);
return res.status(200).send({ data: warehouseTransfer });
} catch (error) {
next(error);
}
};
/**
* Retrieves specific warehouse transfer transaction.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
* @returns {Response}
*/
private getWarehousesTransfers = async (
req: Request,
res: Response,
next: NextFunction
) => {
const { tenantId } = req;
const filterDTO = {
sortOrder: 'desc',
columnSortBy: 'created_at',
page: 1,
pageSize: 12,
...this.matchedQueryData(req),
};
try {
const { warehousesTransfers, pagination, filter } =
await this.warehouseTransferApplication.getWarehousesTransfers(
tenantId,
filterDTO
);
return res.status(200).send({
data: warehousesTransfers,
pagination,
filter,
});
} catch (error) {
next(error);
}
};
/**
* Initiates the warehouse transfer.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
* @returns {Response}
*/
private initiateTransfer = async (
req: Request,
res: Response,
next: NextFunction
) => {
const { tenantId } = req;
const { id: warehouseTransferId } = req.params;
try {
await this.warehouseTransferApplication.initiateWarehouseTransfer(
tenantId,
warehouseTransferId
);
return res.status(200).send({
id: warehouseTransferId,
message: 'The given warehouse transfer has been initialized.',
});
} catch (error) {
next(error);
}
};
/**
* marks the given warehouse transfer as transferred.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
* @returns {Response}
*/
private deliverTransfer = async (
req: Request,
res: Response,
next: NextFunction
) => {
const { tenantId } = req;
const { id: warehouseTransferId } = req.params;
try {
await this.warehouseTransferApplication.transferredWarehouseTransfer(
tenantId,
warehouseTransferId
);
return res.status(200).send({
id: warehouseTransferId,
message: 'The given warehouse transfer has been delivered.',
});
} catch (error) {
next(error);
}
};
/**
* Handles service errors.
* @param {Error} error
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
private handlerServiceErrors(
error: Error,
req: Request,
res: Response,
next: NextFunction
) {
if (error instanceof ServiceError) {
if (error.errorType === 'WAREHOUSES_TRANSFER_SHOULD_NOT_BE_SAME') {
return res.status(400).send({
errors: [
{ type: 'WAREHOUSES_TRANSFER_SHOULD_NOT_BE_SAME', code: 100 },
],
});
}
if (error.errorType === 'FROM_WAREHOUSE_NOT_FOUND') {
return res.status(400).send({
errors: [{ type: 'FROM_WAREHOUSE_NOT_FOUND', code: 200 }],
});
}
if (error.errorType === 'TO_WAREHOUSE_NOT_FOUND') {
return res.status(400).send({
errors: [{ type: 'TO_WAREHOUSE_NOT_FOUND', code: 300 }],
});
}
if (error.errorType === 'ITEMS_NOT_FOUND') {
return res.status(400).send({
errors: [{ type: 'ITEMS_NOT_FOUND', code: 400 }],
});
}
if (error.errorType === 'WAREHOUSE_TRANSFER_ITEMS_SHOULD_BE_INVENTORY') {
return res.status(400).send({
errors: [
{ type: 'WAREHOUSE_TRANSFER_ITEMS_SHOULD_BE_INVENTORY', code: 500 },
],
});
}
if (error.errorType === 'WAREHOUSE_TRANSFER_ALREADY_TRANSFERRED') {
return res.status(400).send({
errors: [
{ type: 'WAREHOUSE_TRANSFER_ALREADY_TRANSFERRED', code: 600 },
],
});
}
if (error.errorType === 'WAREHOUSE_TRANSFER_ALREADY_INITIATED') {
return res.status(400).send({
errors: [{ type: 'WAREHOUSE_TRANSFER_ALREADY_INITIATED', code: 700 }],
});
}
if (error.errorType === 'WAREHOUSE_TRANSFER_NOT_INITIATED') {
return res.status(400).send({
errors: [{ type: 'WAREHOUSE_TRANSFER_NOT_INITIATED', code: 800 }],
});
}
}
next(error);
}
}