Files
bigcapital/server/src/http/controllers/Contacts/Customers.ts
Ahmed Bouhuolia ad00f140d1 feat: licenses administration basic authentication.
feat: accounts slug.
feat: duplicate accounts_balance table and merge balance with accounts table.
feat: refactoring customers and vendors.
feat: system user soft deleting.
feat: preventing build tenant database without any subscription.
feat: remove 'password' property from 'req.user' object.
feat: refactoring JournalPoster class.
feat: delete duplicated directories and files.
2020-09-09 21:30:19 +02:00

196 lines
5.6 KiB
TypeScript

import { Request, Response, Router, NextFunction } from 'express';
import { Service, Inject } from 'typedi';
import { check } from 'express-validator';
import ContactsController from '@/http/controllers/Contacts/Contacts';
import CustomersService from '@/services/Contacts/CustomersService';
import { ServiceError } from '@/exceptions';
import { ICustomerNewDTO, ICustomerEditDTO } from '@/interfaces';
import asyncMiddleware from '@/http/middleware/asyncMiddleware';
@Service()
export default class CustomersController extends ContactsController {
@Inject()
customersService: CustomersService;
/**
* Express router.
*/
router() {
const router = Router();
router.post('/', [
...this.contactDTOSchema,
...this.contactNewDTOSchema,
...this.customerDTOSchema,
],
this.validationResult,
asyncMiddleware(this.newCustomer.bind(this))
);
router.post('/:id', [
...this.contactDTOSchema,
...this.contactEditDTOSchema,
...this.customerDTOSchema,
],
this.validationResult,
asyncMiddleware(this.editCustomer.bind(this))
);
router.delete('/:id', [
...this.specificContactSchema,
],
this.validationResult,
asyncMiddleware(this.deleteCustomer.bind(this))
);
router.delete('/', [
...this.bulkContactsSchema,
],
this.validationResult,
asyncMiddleware(this.deleteBulkCustomers.bind(this))
);
router.get('/:id', [
...this.specificContactSchema,
],
this.validationResult,
asyncMiddleware(this.getCustomer.bind(this))
);
return router;
}
/**
* Customer DTO schema.
*/
get customerDTOSchema() {
return [
check('customer_type').exists().trim().escape(),
check('opening_balance').optional().isNumeric().toInt(),
];
}
/**
* Creates a new customer.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
async newCustomer(req: Request, res: Response, next: NextFunction) {
const contactDTO: ICustomerNewDTO = this.matchedBodyData(req);
const { tenantId } = req;
try {
const contact = await this.customersService.newCustomer(tenantId, contactDTO);
return res.status(200).send({ id: contact.id });
} catch (error) {
next(error);
}
}
/**
* Edits the given customer details.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
async editCustomer(req: Request, res: Response, next: NextFunction) {
const contactDTO: ICustomerEditDTO = this.matchedBodyData(req);
const { tenantId } = req;
const { id: contactId } = req.params;
try {
await this.customersService.editCustomer(tenantId, contactId, contactDTO;)
return res.status(200).send({ id: contactId });
} catch (error) {
if (error instanceof ServiceError) {
if (error.errorType === 'contact_not_found') {
return res.boom.badRequest(null, {
errors: [{ type: 'CUSTOMER.NOT.FOUND', code: 100 }],
});
}
}
next(error);
}
}
/**
* Deletes the given customer from the storage.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
async deleteCustomer(req: Request, res: Response, next: NextFunction) {
const { tenantId } = req;
const { id: contactId } = req.params;
try {
await this.customersService.deleteCustomer(tenantId, contactId)
return res.status(200).send({ id: contactId });
} catch (error) {
if (error instanceof ServiceError) {
if (error.errorType === 'contact_not_found') {
return res.boom.badRequest(null, {
errors: [{ type: 'CUSTOMER.NOT.FOUND', code: 100 }],
});
}
if (error.errorType === 'customer_has_invoices') {
return res.boom.badRequest(null, {
errors: [{ type: 'CUSTOMER.HAS.SALES_INVOICES', code: 200 }],
});
}
}
next(error);
}
}
/**
* Retrieve details of the given customer id.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
async getCustomer(req: Request, res: Response, next: NextFunction) {
const { tenantId } = req;
const { id: contactId } = req.params;
try {
const contact = await this.customersService.getCustomer(tenantId, contactId)
return res.status(200).send({ contact });
} catch (error) {
if (error instanceof ServiceError) {
if (error.errorType === 'contact_not_found') {
return res.boom.badRequest(null, {
errors: [{ type: 'CONTACT.NOT.FOUND', code: 100 }],
});
}
}
next(error);
}
}
/**
* Deletes customers in bulk.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
async deleteBulkCustomers(req: Request, res: Response, next: NextFunction) {
const { ids: contactsIds } = req.query;
const { tenantId } = req;
try {
await this.customersService.deleteBulkCustomers(tenantId, contactsIds)
return res.status(200).send({ ids: contactsIds });
} catch (error) {
if (error instanceof ServiceError) {
if (error.errorType === 'contacts_not_found') {
return res.boom.badRequest(null, {
errors: [{ type: 'CUSTOMERS.NOT.FOUND', code: 100 }],
});
}
if (error.errorType === 'some_customers_have_invoices') {
return res.boom.badRequest(null, {
errors: [{ type: 'SOME.CUSTOMERS.HAVE.SALES_INVOICES', code: 200 }],
});
}
}
next(error);
}
}
}