mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-16 21:00:31 +00:00
feat: customer form styling.
feat: customers list.
This commit is contained in:
@@ -17,17 +17,21 @@ export default class ContactsController extends BaseController {
|
||||
check('work_phone').optional().trim().escape(),
|
||||
check('personal_phone').optional().trim().escape(),
|
||||
|
||||
check('billing_address_1').optional().trim().escape(),
|
||||
check('billing_address_2').optional().trim().escape(),
|
||||
check('billing_address_city').optional().trim().escape(),
|
||||
check('billing_address_country').optional().trim().escape(),
|
||||
check('billing_address_email').optional().isEmail().trim().escape(),
|
||||
check('billing_address_zipcode').optional().trim().escape(),
|
||||
check('billing_address_postcode').optional().trim().escape(),
|
||||
check('billing_address_phone').optional().trim().escape(),
|
||||
check('billing_address_state').optional().trim().escape(),
|
||||
|
||||
check('shipping_address_1').optional().trim().escape(),
|
||||
check('shipping_address_2').optional().trim().escape(),
|
||||
check('shipping_address_city').optional().trim().escape(),
|
||||
check('shipping_address_country').optional().trim().escape(),
|
||||
check('shipping_address_email').optional().isEmail().trim().escape(),
|
||||
check('shipping_address_zip_code').optional().trim().escape(),
|
||||
check('shipping_address_postcode').optional().trim().escape(),
|
||||
check('shipping_address_phone').optional().trim().escape(),
|
||||
check('shipping_address_state').optional().trim().escape(),
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ export default class CustomersController extends ContactsController {
|
||||
...this.contactDTOSchema,
|
||||
...this.contactNewDTOSchema,
|
||||
...this.customerDTOSchema,
|
||||
...this.createCustomerDTOSchema,
|
||||
],
|
||||
this.validationResult,
|
||||
asyncMiddleware(this.newCustomer.bind(this)),
|
||||
@@ -77,10 +78,24 @@ export default class CustomersController extends ContactsController {
|
||||
get customerDTOSchema() {
|
||||
return [
|
||||
check('customer_type').exists().trim().escape(),
|
||||
check('opening_balance').optional().isNumeric().toInt(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create customer DTO schema.
|
||||
*/
|
||||
get createCustomerDTOSchema() {
|
||||
return [
|
||||
check('opening_balance').optional().isNumeric().toInt(),
|
||||
check('opening_balance_at').optional().isISO8601(),
|
||||
|
||||
check('currency_code').optional().trim().escape(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* List param query schema.
|
||||
*/
|
||||
get validateListQuerySchema() {
|
||||
return [
|
||||
query('column_sort_by').optional().trim().escape(),
|
||||
|
||||
@@ -7,7 +7,10 @@ exports.up = function(knex) {
|
||||
table.string('contact_type');
|
||||
|
||||
table.decimal('balance', 13, 3).defaultTo(0);
|
||||
table.string('currency_code', 3);
|
||||
|
||||
table.decimal('opening_balance', 13, 3).defaultTo(0);
|
||||
table.date('opening_balance_at');
|
||||
|
||||
table.string('first_name').nullable();
|
||||
table.string('last_name').nullable();
|
||||
@@ -19,12 +22,12 @@ exports.up = function(knex) {
|
||||
table.string('work_phone').nullable();
|
||||
table.string('personal_phone').nullable();
|
||||
|
||||
table.string('billing_address_1').nullable();
|
||||
table.string('billing_address_2').nullable();
|
||||
table.string('billing_address1').nullable();
|
||||
table.string('billing_address2').nullable();
|
||||
table.string('billing_address_city').nullable();
|
||||
table.string('billing_address_country').nullable();
|
||||
table.string('billing_address_email').nullable();
|
||||
table.string('billing_address_zipcode').nullable();
|
||||
table.string('billing_address_postcode').nullable();
|
||||
table.string('billing_address_phone').nullable();
|
||||
table.string('billing_address_state').nullable(),
|
||||
|
||||
@@ -33,7 +36,7 @@ exports.up = function(knex) {
|
||||
table.string('shipping_address_city').nullable();
|
||||
table.string('shipping_address_country').nullable();
|
||||
table.string('shipping_address_email').nullable();
|
||||
table.string('shipping_address_zipcode').nullable();
|
||||
table.string('shipping_address_postcode').nullable();
|
||||
table.string('shipping_address_phone').nullable();
|
||||
table.string('shipping_address_state').nullable();
|
||||
|
||||
|
||||
@@ -47,7 +47,10 @@ export interface IContact extends IContactAddress{
|
||||
contactType: string,
|
||||
|
||||
balance: number,
|
||||
currencyCode: string,
|
||||
|
||||
openingBalance: number,
|
||||
openingBalanceAt: Date,
|
||||
|
||||
firstName: string,
|
||||
lastName: string,
|
||||
@@ -64,7 +67,10 @@ export interface IContact extends IContactAddress{
|
||||
export interface IContactNewDTO {
|
||||
contactType?: string,
|
||||
|
||||
currencyCode?: string,
|
||||
|
||||
openingBalance?: number,
|
||||
openingBalanceAt?: string,
|
||||
|
||||
firstName?: string,
|
||||
lastName?: string,
|
||||
@@ -81,8 +87,6 @@ export interface IContactNewDTO {
|
||||
export interface IContactEditDTO {
|
||||
contactType?: string,
|
||||
|
||||
openingBalance?: number,
|
||||
|
||||
firstName?: string,
|
||||
lastName?: string,
|
||||
companyName?: string,
|
||||
@@ -104,7 +108,10 @@ export interface ICustomer extends IContact {
|
||||
export interface ICustomerNewDTO extends IContactAddressDTO {
|
||||
customerType: string,
|
||||
|
||||
currencyCode: string,
|
||||
|
||||
openingBalance?: number,
|
||||
openingBalanceAt?: string,
|
||||
|
||||
firstName?: string,
|
||||
lastName?: string,
|
||||
@@ -121,8 +128,6 @@ export interface ICustomerNewDTO extends IContactAddressDTO {
|
||||
export interface ICustomerEditDTO extends IContactAddressDTO {
|
||||
customerType: string,
|
||||
|
||||
openingBalance?: number,
|
||||
|
||||
firstName?: string,
|
||||
lastName?: string,
|
||||
companyName?: string,
|
||||
@@ -142,7 +147,10 @@ export interface IVendor extends IContact {
|
||||
contactService: 'vendor',
|
||||
}
|
||||
export interface IVendorNewDTO extends IContactAddressDTO {
|
||||
currencyCode: string,
|
||||
|
||||
openingBalance?: number,
|
||||
openingBalanceAt?: string,
|
||||
|
||||
firstName?: string,
|
||||
lastName?: string,
|
||||
@@ -157,8 +165,6 @@ export interface IVendorNewDTO extends IContactAddressDTO {
|
||||
active?: boolean,
|
||||
};
|
||||
export interface IVendorEditDTO extends IContactAddressDTO {
|
||||
openingBalance?: number,
|
||||
|
||||
firstName?: string,
|
||||
lastName?: string,
|
||||
companyName?: string,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Inject, Service } from 'typedi';
|
||||
import { difference, upperFirst } from 'lodash';
|
||||
import { difference, upperFirst, omit } from 'lodash';
|
||||
import { ServiceError } from "exceptions";
|
||||
import TenancyService from 'services/Tenancy/TenancyService';
|
||||
import {
|
||||
@@ -38,17 +38,39 @@ export default class ContactsService {
|
||||
return contact;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts contact DTO object to model object attributes to insert or update.
|
||||
* @param {IContactNewDTO | IContactEditDTO} contactDTO
|
||||
*/
|
||||
private transformContactObj(contactDTO: IContactNewDTO | IContactEditDTO) {
|
||||
return {
|
||||
...omit(contactDTO, [
|
||||
'billingAddress1', 'billingAddress2',
|
||||
'shippingAddress1', 'shippingAddress2',
|
||||
]),
|
||||
billing_address_1: contactDTO?.billingAddress1,
|
||||
billing_address_2: contactDTO?.billingAddress2,
|
||||
shipping_address_1: contactDTO?.shippingAddress1,
|
||||
shipping_address_2: contactDTO?.shippingAddress2,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new contact on the storage.
|
||||
* @param {number} tenantId
|
||||
* @param {TContactService} contactService
|
||||
* @param {IContactDTO} contactDTO
|
||||
*/
|
||||
async newContact(tenantId: number, contactDTO: IContactNewDTO, contactService: TContactService) {
|
||||
async newContact(
|
||||
tenantId: number,
|
||||
contactDTO: IContactNewDTO,
|
||||
contactService: TContactService,
|
||||
) {
|
||||
const { contactRepository } = this.tenancy.repositories(tenantId);
|
||||
const contactObj = this.transformContactObj(contactDTO);
|
||||
|
||||
this.logger.info('[contacts] trying to insert contact to the storage.', { tenantId, contactDTO });
|
||||
const contact = await contactRepository.insert({ contactService, ...contactDTO });
|
||||
const contact = await contactRepository.insert({ contactService, ...contactObj });
|
||||
|
||||
this.logger.info('[contacts] contact inserted successfully.', { tenantId, contact });
|
||||
return contact;
|
||||
@@ -63,10 +85,12 @@ export default class ContactsService {
|
||||
*/
|
||||
async editContact(tenantId: number, contactId: number, contactDTO: IContactEditDTO, contactService: TContactService) {
|
||||
const { Contact } = this.tenancy.models(tenantId);
|
||||
const contactObj = this.transformContactObj(contactDTO);
|
||||
|
||||
const contact = await this.getContactByIdOrThrowError(tenantId, contactId, contactService);
|
||||
|
||||
this.logger.info('[contacts] trying to edit the given contact details.', { tenantId, contactId, contactDTO });
|
||||
await Contact.query().findById(contactId).patch({ ...contactDTO })
|
||||
await Contact.query().findById(contactId).patch({ ...contactObj })
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,12 +12,15 @@ import {
|
||||
ICustomerEditDTO,
|
||||
ICustomer,
|
||||
IPaginationMeta,
|
||||
ICustomersFilter
|
||||
ICustomersFilter,
|
||||
IContactNewDTO,
|
||||
IContactEditDTO
|
||||
} from 'interfaces';
|
||||
import { ServiceError } from 'exceptions';
|
||||
import TenancyService from 'services/Tenancy/TenancyService';
|
||||
import DynamicListingService from 'services/DynamicListing/DynamicListService';
|
||||
import events from 'subscribers/events';
|
||||
import moment from 'moment';
|
||||
|
||||
@Service()
|
||||
export default class CustomersService {
|
||||
@@ -41,7 +44,7 @@ export default class CustomersService {
|
||||
* @param {ICustomerNewDTO|ICustomerEditDTO} customerDTO
|
||||
* @returns {IContactDTO}
|
||||
*/
|
||||
private customerToContactDTO(customerDTO: ICustomerNewDTO | ICustomerEditDTO) {
|
||||
private customerToContactDTO(customerDTO: ICustomerNewDTO|ICustomerEditDTO): IContactNewDTO|IContactEditDTO {
|
||||
return {
|
||||
...omit(customerDTO, ['customerType']),
|
||||
contactType: customerDTO.customerType,
|
||||
@@ -50,6 +53,18 @@ export default class CustomersService {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms new customer DTO to contact.
|
||||
* @param customerDTO
|
||||
*/
|
||||
private transformNewCustomerDTO(customerDTO: ICustomerNewDTO): IContactNewDTO {
|
||||
return {
|
||||
...this.customerToContactDTO(customerDTO),
|
||||
openingBalanceAt: customerDTO?.openingBalanceAt
|
||||
? moment(customerDTO.openingBalanceAt).toMySqlDateTime() : null,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new customer.
|
||||
* @param {number} tenantId
|
||||
@@ -62,8 +77,8 @@ export default class CustomersService {
|
||||
): Promise<ICustomer> {
|
||||
this.logger.info('[customer] trying to create a new customer.', { tenantId, customerDTO });
|
||||
|
||||
const contactDTO = this.customerToContactDTO(customerDTO)
|
||||
const customer = await this.contactService.newContact(tenantId, contactDTO, 'customer');
|
||||
const customerObj = this.transformNewCustomerDTO(customerDTO);
|
||||
const customer = await this.contactService.newContact(tenantId, customerObj, 'customer');
|
||||
|
||||
this.logger.info('[customer] created successfully.', { tenantId, customerDTO });
|
||||
await this.eventDispatcher.dispatch(events.customers.onCreated, {
|
||||
|
||||
Reference in New Issue
Block a user