mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-20 14:50:32 +00:00
feat: customer form styling.
feat: customers list.
This commit is contained in:
@@ -12,8 +12,6 @@ import {
|
|||||||
Checkbox,
|
Checkbox,
|
||||||
Spinner,
|
Spinner,
|
||||||
ContextMenu,
|
ContextMenu,
|
||||||
Menu,
|
|
||||||
MenuItem,
|
|
||||||
} from '@blueprintjs/core';
|
} from '@blueprintjs/core';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import { FixedSizeList } from 'react-window';
|
import { FixedSizeList } from 'react-window';
|
||||||
|
|||||||
@@ -12,11 +12,7 @@ const CustomerBillingAddress = ({
|
|||||||
getFieldProps,
|
getFieldProps,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div className={'tab-panel--address'}>
|
||||||
className={
|
|
||||||
'customer-form__tabs-section customer-form__tabs-section--address'
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Row>
|
<Row>
|
||||||
<Col xs={6}>
|
<Col xs={6}>
|
||||||
<h4>
|
<h4>
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export default function CustomerFinancialPanel({
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={'customer-form__tabs-section customer-form__tabs-section--financial'}>
|
<div className={'tab-panel--financial'}>
|
||||||
<Row>
|
<Row>
|
||||||
<Col xs={6}>
|
<Col xs={6}>
|
||||||
<FormGroup
|
<FormGroup
|
||||||
|
|||||||
@@ -143,10 +143,46 @@ function CustomerForm({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
customer && customer.id
|
customer && customer.id
|
||||||
? changePageTitle(formatMessage({ id: 'edit_customer_details' }))
|
? changePageTitle(formatMessage({ id: 'edit_customer' }))
|
||||||
: changePageTitle(formatMessage({ id: 'new_customer' }));
|
: changePageTitle(formatMessage({ id: 'new_customer' }));
|
||||||
}, [changePageTitle, customer, formatMessage]);
|
}, [changePageTitle, customer, formatMessage]);
|
||||||
|
|
||||||
|
const handleFormSubmit = (values, { setSubmitting, resetForm, setErrors }) => {
|
||||||
|
const formValues = { ...values, status: payload.publish };
|
||||||
|
if (customer && customer.id) {
|
||||||
|
requestEditCustomer(customer.id, formValues)
|
||||||
|
.then((response) => {
|
||||||
|
AppToaster.show({
|
||||||
|
message: formatMessage({
|
||||||
|
id: 'the_item_customer_has_been_successfully_edited',
|
||||||
|
}),
|
||||||
|
intent: Intent.SUCCESS,
|
||||||
|
});
|
||||||
|
setSubmitting(false);
|
||||||
|
resetForm();
|
||||||
|
saveInvokeSubmit({ action: 'update', ...payload });
|
||||||
|
})
|
||||||
|
.catch((errors) => {
|
||||||
|
setSubmitting(false);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
requestSubmitCustomer(formValues)
|
||||||
|
.then((response) => {
|
||||||
|
AppToaster.show({
|
||||||
|
message: formatMessage({
|
||||||
|
id: 'the_customer_has_been_successfully_created',
|
||||||
|
}),
|
||||||
|
intent: Intent.SUCCESS,
|
||||||
|
});
|
||||||
|
setSubmitting(false);
|
||||||
|
saveInvokeSubmit({ action: 'new', ...payload });
|
||||||
|
})
|
||||||
|
.catch((errors) => {
|
||||||
|
setSubmitting(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const {
|
const {
|
||||||
setFieldValue,
|
setFieldValue,
|
||||||
getFieldProps,
|
getFieldProps,
|
||||||
@@ -160,42 +196,7 @@ function CustomerForm({
|
|||||||
initialValues: {
|
initialValues: {
|
||||||
...initialValues,
|
...initialValues,
|
||||||
},
|
},
|
||||||
onSubmit: (values, { setSubmitting, resetForm, setErrors }) => {
|
onSubmit: handleFormSubmit,
|
||||||
const formValues = { ...values, status: payload.publish };
|
|
||||||
if (customer && customer.id) {
|
|
||||||
requestEditCustomer(customer.id, formValues)
|
|
||||||
.then((response) => {
|
|
||||||
AppToaster.show({
|
|
||||||
message: formatMessage({
|
|
||||||
id: 'the_item_customer_has_been_successfully_edited',
|
|
||||||
}),
|
|
||||||
intent: Intent.SUCCESS,
|
|
||||||
});
|
|
||||||
setSubmitting(false);
|
|
||||||
resetForm();
|
|
||||||
saveInvokeSubmit({ action: 'update', ...payload });
|
|
||||||
})
|
|
||||||
.catch((errors) => {
|
|
||||||
setSubmitting(false);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
requestSubmitCustomer(formValues)
|
|
||||||
.then((response) => {
|
|
||||||
AppToaster.show({
|
|
||||||
message: formatMessage({
|
|
||||||
id: 'the_customer_has_been_successfully_created',
|
|
||||||
}),
|
|
||||||
intent: Intent.SUCCESS,
|
|
||||||
});
|
|
||||||
// history.push('/customers');
|
|
||||||
setSubmitting(false);
|
|
||||||
saveInvokeSubmit({ action: 'new', ...payload });
|
|
||||||
})
|
|
||||||
.catch((errors) => {
|
|
||||||
setSubmitting(false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -32,13 +32,14 @@ export default function CustomerFormPrimarySection({
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Handle salutation field select.
|
// Handle salutation field select.
|
||||||
const handleSalutationSelect = (salutation) => {
|
const handleSalutationSelect = useCallback((salutation) => {
|
||||||
setFieldValue('salutation', salutation.label);
|
setFieldValue('salutation', salutation.label);
|
||||||
};
|
}, [setFieldValue]);
|
||||||
|
|
||||||
// Handle display name field select.
|
// Handle display name field select.
|
||||||
const handleDisplayNameSelect = (displayName) => {
|
const handleDisplayNameSelect = useCallback((displayName) => {
|
||||||
setFieldValue('display_name', displayName.label);
|
setFieldValue('display_name', displayName.label);
|
||||||
};
|
}, [setFieldValue]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={'customer-form__primary-section-content'}>
|
<div className={'customer-form__primary-section-content'}>
|
||||||
@@ -116,6 +117,7 @@ export default function CustomerFormPrimarySection({
|
|||||||
firstName={values.first_name}
|
firstName={values.first_name}
|
||||||
lastName={values.last_name}
|
lastName={values.last_name}
|
||||||
company={values.company_name}
|
company={values.company_name}
|
||||||
|
salutation={values.salutation}
|
||||||
onItemSelect={handleDisplayNameSelect}
|
onItemSelect={handleDisplayNameSelect}
|
||||||
popoverProps={{ minimal: true }}
|
popoverProps={{ minimal: true }}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -7,28 +7,21 @@ import ErrorMessage from 'components/ErrorMessage';
|
|||||||
|
|
||||||
export default function CustomerNotePanel({ errors, touched, getFieldProps }) {
|
export default function CustomerNotePanel({ errors, touched, getFieldProps }) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div className={'tab-panel--note'}>
|
||||||
className={
|
<FormGroup
|
||||||
'customer-form__tabs-section customer-form__tabs-section--note'
|
label={<T id={'note'} />}
|
||||||
}
|
className={classNames('form-group--note', Classes.FILL)}
|
||||||
>
|
intent={errors.note && touched.note && Intent.DANGER}
|
||||||
<Row>
|
helperText={
|
||||||
<Col xs={6}>
|
<ErrorMessage name="payment_date" {...{ errors, touched }} />
|
||||||
<FormGroup
|
}
|
||||||
label={<T id={'note'} />}
|
>
|
||||||
className={classNames('form-group--select-list', Classes.FILL)}
|
<TextArea
|
||||||
intent={errors.note && touched.note && Intent.DANGER}
|
intent={errors.note && touched.note && Intent.DANGER}
|
||||||
helperText={
|
{...getFieldProps('note')}
|
||||||
<ErrorMessage name="payment_date" {...{ errors, touched }} />
|
/>
|
||||||
}
|
</FormGroup>
|
||||||
>
|
|
||||||
<TextArea
|
|
||||||
intent={errors.note && touched.note && Intent.DANGER}
|
|
||||||
{...getFieldProps('note')}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useEffect, useCallback, useMemo } from 'react';
|
import React, { useState, useCallback, useMemo } from 'react';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Popover,
|
Popover,
|
||||||
@@ -6,17 +6,23 @@ import {
|
|||||||
MenuItem,
|
MenuItem,
|
||||||
MenuDivider,
|
MenuDivider,
|
||||||
Position,
|
Position,
|
||||||
|
Intent,
|
||||||
} from '@blueprintjs/core';
|
} from '@blueprintjs/core';
|
||||||
|
|
||||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||||
import DataTable from 'components/DataTable';
|
import DataTable from 'components/DataTable';
|
||||||
import Icon from 'components/Icon';
|
import Icon from 'components/Icon';
|
||||||
|
import { Money } from 'components';
|
||||||
import { useUpdateEffect } from 'hooks';
|
import { useUpdateEffect } from 'hooks';
|
||||||
|
|
||||||
import LoadingIndicator from 'components/LoadingIndicator';
|
import LoadingIndicator from 'components/LoadingIndicator';
|
||||||
import withCustomers from './withCustomers';
|
import withCustomers from './withCustomers';
|
||||||
|
|
||||||
import { compose } from 'utils';
|
import { compose, firstLettersArgs, saveInvoke } from 'utils';
|
||||||
|
|
||||||
|
const AvatarCell = (row) => {
|
||||||
|
return <span className="avatar">{firstLettersArgs(row.display_name)}</span>;
|
||||||
|
};
|
||||||
|
|
||||||
const CustomerTable = ({
|
const CustomerTable = ({
|
||||||
loading,
|
loading,
|
||||||
@@ -32,7 +38,6 @@ const CustomerTable = ({
|
|||||||
onSelectedRowsChange,
|
onSelectedRowsChange,
|
||||||
}) => {
|
}) => {
|
||||||
const { formatMessage } = useIntl();
|
const { formatMessage } = useIntl();
|
||||||
|
|
||||||
const [initialMount, setInitialMount] = useState(false);
|
const [initialMount, setInitialMount] = useState(false);
|
||||||
|
|
||||||
useUpdateEffect(() => {
|
useUpdateEffect(() => {
|
||||||
@@ -41,36 +46,64 @@ const CustomerTable = ({
|
|||||||
}
|
}
|
||||||
}, [customersLoading, setInitialMount]);
|
}, [customersLoading, setInitialMount]);
|
||||||
|
|
||||||
const handleEditCustomer = useCallback(
|
// Customers actions list.
|
||||||
(customer) => () => {
|
const renderContextMenu = useMemo(
|
||||||
onEditCustomer && onEditCustomer(customer);
|
() => ({ customer, onEditCustomer, onDeleteCustomer }) => {
|
||||||
|
const handleEditCustomer = () => {
|
||||||
|
saveInvoke(onEditCustomer, customer);
|
||||||
|
};
|
||||||
|
const handleDeleteCustomer = () => {
|
||||||
|
saveInvoke(onDeleteCustomer, customer);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Menu>
|
||||||
|
<MenuItem
|
||||||
|
icon={<Icon icon="reader-18" />}
|
||||||
|
text={formatMessage({ id: 'view_details' })}
|
||||||
|
/>
|
||||||
|
<MenuDivider />
|
||||||
|
<MenuItem
|
||||||
|
icon={<Icon icon="pen-18" />}
|
||||||
|
text={formatMessage({ id: 'edit_customer' })}
|
||||||
|
onClick={handleEditCustomer}
|
||||||
|
/>
|
||||||
|
<MenuItem
|
||||||
|
icon={<Icon icon="trash-16" iconSize={16} />}
|
||||||
|
text={formatMessage({ id: 'delete_customer' })}
|
||||||
|
intent={Intent.DANGER}
|
||||||
|
onClick={handleDeleteCustomer}
|
||||||
|
/>
|
||||||
|
</Menu>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
[onEditCustomer],
|
[formatMessage],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleDeleteCustomer = useCallback(
|
// Renders actions table cell.
|
||||||
(customer) => () => {
|
const renderActionsCell = useMemo(() => ({ cell }) => (
|
||||||
onDeleteCustomer && onDeleteCustomer(customer);
|
<Popover
|
||||||
},
|
content={renderContextMenu({
|
||||||
[onDeleteCustomer],
|
customer: cell.row.original,
|
||||||
);
|
onEditCustomer,
|
||||||
const actionMenuList = useCallback((customer) => (
|
onDeleteCustomer,
|
||||||
<Menu>
|
})}
|
||||||
<MenuItem text={<T id={'view_details'} />} />
|
position={Position.RIGHT_BOTTOM}
|
||||||
<MenuDivider />
|
>
|
||||||
<MenuItem
|
<Button icon={<Icon icon="more-h-16" iconSize={16} />} />
|
||||||
text={<T id={'edit_customer'} />}
|
</Popover>
|
||||||
onClick={handleEditCustomer(customer)}
|
), [onDeleteCustomer, onEditCustomer, renderContextMenu]);
|
||||||
/>
|
|
||||||
<MenuItem
|
|
||||||
text={<T id={'delete_customer'} />}
|
|
||||||
onClick={handleDeleteCustomer(customer)}
|
|
||||||
/>
|
|
||||||
</Menu>
|
|
||||||
));
|
|
||||||
|
|
||||||
const columns = useMemo(
|
const columns = useMemo(
|
||||||
() => [
|
() => [
|
||||||
|
{
|
||||||
|
id: 'avatar',
|
||||||
|
Header: '',
|
||||||
|
accessor: AvatarCell,
|
||||||
|
className: 'avatar',
|
||||||
|
width: 50,
|
||||||
|
disableResizing: true,
|
||||||
|
disableSortBy: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'display_name',
|
id: 'display_name',
|
||||||
Header: formatMessage({ id: 'display_name' }),
|
Header: formatMessage({ id: 'display_name' }),
|
||||||
@@ -95,26 +128,20 @@ const CustomerTable = ({
|
|||||||
{
|
{
|
||||||
id: 'receivable_balance',
|
id: 'receivable_balance',
|
||||||
Header: formatMessage({ id: 'receivable_balance' }),
|
Header: formatMessage({ id: 'receivable_balance' }),
|
||||||
// accessor: '',
|
accessor: (r) => <Money amount={r.closing_balance} currency={'USD'} />,
|
||||||
className: 'receivable_balance',
|
className: 'receivable_balance',
|
||||||
width: 100,
|
width: 100,
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
id: 'actions',
|
id: 'actions',
|
||||||
Cell: ({ cell }) => (
|
Cell: renderActionsCell,
|
||||||
<Popover
|
|
||||||
content={actionMenuList(cell.row.original)}
|
|
||||||
position={Position.RIGHT_BOTTOM}
|
|
||||||
>
|
|
||||||
<Button icon={<Icon icon="more-h-16" iconSize={16} />} />
|
|
||||||
</Popover>
|
|
||||||
),
|
|
||||||
className: 'actions',
|
className: 'actions',
|
||||||
width: 50,
|
width: 70,
|
||||||
|
disableResizing: true,
|
||||||
|
disableSortBy: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[actionMenuList, formatMessage],
|
[formatMessage, renderActionsCell],
|
||||||
);
|
);
|
||||||
|
|
||||||
const selectionColumn = useMemo(
|
const selectionColumn = useMemo(
|
||||||
@@ -138,6 +165,13 @@ const CustomerTable = ({
|
|||||||
[onSelectedRowsChange],
|
[onSelectedRowsChange],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const rowContextMenu = (cell) =>
|
||||||
|
renderContextMenu({
|
||||||
|
customer: cell.row.original,
|
||||||
|
onEditCustomer,
|
||||||
|
onDeleteCustomer,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LoadingIndicator loading={loading} mount={false}>
|
<LoadingIndicator loading={loading} mount={false}>
|
||||||
<DataTable
|
<DataTable
|
||||||
@@ -146,11 +180,12 @@ const CustomerTable = ({
|
|||||||
data={customers}
|
data={customers}
|
||||||
selectionColumn={selectionColumn}
|
selectionColumn={selectionColumn}
|
||||||
onFetchData={handleFetchDate}
|
onFetchData={handleFetchDate}
|
||||||
expandable={true}
|
expandable={false}
|
||||||
treeGraph={true}
|
treeGraph={false}
|
||||||
onSelectedRowsChange={handleSelectedRowsChange}
|
onSelectedRowsChange={handleSelectedRowsChange}
|
||||||
loading={customersLoading && !initialMount}
|
loading={customersLoading && !initialMount}
|
||||||
spinnerProps={{ size: 30 }}
|
spinnerProps={{ size: 30 }}
|
||||||
|
rowContextMenu={rowContextMenu}
|
||||||
/>
|
/>
|
||||||
</LoadingIndicator>
|
</LoadingIndicator>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -135,11 +135,10 @@ function CustomersList({
|
|||||||
filter_roles: filterConditions || '',
|
filter_roles: filterConditions || '',
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[fetchCustomers],
|
[addCustomersTableQueries],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Handle Customers bulk delete button click.,
|
// Handle Customers bulk delete button click.,
|
||||||
|
|
||||||
const handleBulkDelete = useCallback(
|
const handleBulkDelete = useCallback(
|
||||||
(customersIds) => {
|
(customersIds) => {
|
||||||
setBulkDelete(customersIds);
|
setBulkDelete(customersIds);
|
||||||
@@ -184,7 +183,7 @@ function CustomersList({
|
|||||||
|
|
||||||
<DashboardPageContent>
|
<DashboardPageContent>
|
||||||
<CustomersTable
|
<CustomersTable
|
||||||
loadong={tableLoading}
|
loading={tableLoading}
|
||||||
onDeleteCustomer={handleDeleteCustomer}
|
onDeleteCustomer={handleDeleteCustomer}
|
||||||
onEditCustomer={handleEditCustomer}
|
onEditCustomer={handleEditCustomer}
|
||||||
onfetchData={handleFetchData}
|
onfetchData={handleFetchData}
|
||||||
|
|||||||
@@ -501,7 +501,6 @@ export default {
|
|||||||
billing_address: 'Billing Address',
|
billing_address: 'Billing Address',
|
||||||
shipping_address: 'Shipping Address',
|
shipping_address: 'Shipping Address',
|
||||||
customers_list: 'Customers List',
|
customers_list: 'Customers List',
|
||||||
edit_customer_details: 'Edit Customer Details',
|
|
||||||
receivable_balance: 'Receivable balance',
|
receivable_balance: 'Receivable balance',
|
||||||
the_customer_has_been_successfully_created:
|
the_customer_has_been_successfully_created:
|
||||||
'The customer has been successfully created.',
|
'The customer has been successfully created.',
|
||||||
@@ -804,4 +803,6 @@ export default {
|
|||||||
' Changing full amount will change all credits and payment were applied, Is this okay?',
|
' Changing full amount will change all credits and payment were applied, Is this okay?',
|
||||||
address_line_1: 'Address line 1',
|
address_line_1: 'Address line 1',
|
||||||
address_line_2: 'Address line 2',
|
address_line_2: 'Address line 2',
|
||||||
|
website: 'Website',
|
||||||
|
notes: 'Notes',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export const fetchCustomers = ({ query }) => {
|
|||||||
new Promise((resolve, reject) => {
|
new Promise((resolve, reject) => {
|
||||||
const pageQuery = getState().items.tableQuery;
|
const pageQuery = getState().items.tableQuery;
|
||||||
dispatch({
|
dispatch({
|
||||||
type: t.ITEMS_TABLE_LOADING,
|
type: t.CUSTOMERS_TABLE_LOADING,
|
||||||
payload: { loading: true },
|
payload: { loading: true },
|
||||||
});
|
});
|
||||||
ApiService.get(`customers`, { params: { ...pageQuery, ...query } })
|
ApiService.get(`customers`, { params: { ...pageQuery, ...query } })
|
||||||
|
|||||||
@@ -13,37 +13,36 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
#{$self}__header{
|
.bp3-form-group{
|
||||||
|
max-width: 500px;
|
||||||
|
|
||||||
.bp3-form-group{
|
&.bp3-inline{
|
||||||
max-width: 500px;
|
|
||||||
|
|
||||||
.bp3-label{
|
.bp3-label{
|
||||||
min-width: 150px;
|
min-width: 150px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bp3-form-content{
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
.bp3-form-content{
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.form-group--contact_name{
|
.form-group--contact_name{
|
||||||
max-width: 100%;
|
max-width: 600px;
|
||||||
|
|
||||||
.bp3-control-group > *{
|
.bp3-control-group > *{
|
||||||
flex-shrink: unset;
|
flex-shrink: unset;
|
||||||
|
|
||||||
&:not(:last-child) {
|
&:not(:last-child) {
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.input-group--salutation-list{
|
&.input-group--salutation-list{
|
||||||
width: 25%;
|
width: 25%;
|
||||||
}
|
}
|
||||||
&.input-group--first-name,
|
&.input-group--first-name,
|
||||||
&.input-group--last-name{
|
&.input-group--last-name{
|
||||||
width: 37%;
|
width: 37%;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,29 +75,52 @@
|
|||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
max-width: 1000px;
|
max-width: 1000px;
|
||||||
|
|
||||||
.bp3-form-group{
|
|
||||||
max-width: 440px;
|
|
||||||
|
|
||||||
.bp3-label{
|
|
||||||
min-width: 145px;
|
|
||||||
}
|
|
||||||
.bp3-form-content{
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea.bp3-input{
|
|
||||||
max-width: 100%;
|
|
||||||
width: 100%;
|
|
||||||
min-height: 50px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
h4{
|
h4{
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: #888;
|
color: #888;
|
||||||
margin-bottom: 1.2rem;
|
margin-bottom: 1.2rem;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
// Tab panels.
|
||||||
|
.tab-panel{
|
||||||
|
|
||||||
|
&--address{
|
||||||
|
.bp3-form-group{
|
||||||
|
max-width: 440px;
|
||||||
|
|
||||||
|
&.bp3-inline{
|
||||||
|
.bp3-label{
|
||||||
|
min-width: 145px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bp3-form-content{
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea.bp3-input{
|
||||||
|
max-width: 100%;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 50px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&--note{
|
||||||
|
.form-group--note{
|
||||||
|
.bp3-form-group{
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
|
textarea{
|
||||||
|
width: 100%;
|
||||||
|
min-height: 100px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropzone-container{
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.bp3-tabs{
|
.bp3-tabs{
|
||||||
@@ -136,115 +158,24 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dashboard__insider--customers-list{
|
||||||
|
|
||||||
.customer-form{
|
.bigcapital-datatable{
|
||||||
|
|
||||||
|
.avatar.td{
|
||||||
|
|
||||||
&__primary-section{
|
.avatar{
|
||||||
background-color: #fafafa;
|
height: 30px;
|
||||||
padding: 40px 22px 5px;
|
width: 30px;
|
||||||
margin: -20px -20px 26px;
|
display: inline-block;
|
||||||
|
background: #f3e2f6;
|
||||||
&-content{
|
border-radius: 50%;
|
||||||
width: 600px;
|
line-height: 30px;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #93639a;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&__after-primary-section{
|
|
||||||
&-content{
|
|
||||||
width: 600px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// .customer-form {
|
|
||||||
// padding: 25px;
|
|
||||||
// padding-bottom: 90px;
|
|
||||||
// width: 100%;
|
|
||||||
// margin-bottom: 30px;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// .form-group--customer-type {
|
|
||||||
// .bp3-label {
|
|
||||||
// position: relative;
|
|
||||||
// display: inline-block;
|
|
||||||
// margin: 0 50px 30px 0px;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // .form-group--contact-name {
|
|
||||||
// // .bp3-input-group .bp3-input {
|
|
||||||
// // position: relative;
|
|
||||||
// // // display: none;
|
|
||||||
// // width: 50%;
|
|
||||||
// // }
|
|
||||||
// // // .row {
|
|
||||||
// // // width: fit-content;
|
|
||||||
// // // }
|
|
||||||
|
|
||||||
// // // .#{$ns}-form-content{
|
|
||||||
// // // width: 350px;
|
|
||||||
// // // }
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// h1 {
|
|
||||||
// font-size: 14px;
|
|
||||||
// margin-bottom: 20px;
|
|
||||||
// }
|
|
||||||
// &__primary-section {
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
|
|
||||||
// &__tabs-section {
|
|
||||||
// position: relative;
|
|
||||||
// h4 {
|
|
||||||
// margin: 0;
|
|
||||||
// font-weight: 500;
|
|
||||||
// margin-bottom: 20px;
|
|
||||||
// font-size: 14px;
|
|
||||||
// color: #828282;
|
|
||||||
// }
|
|
||||||
// > div:first-of-type {
|
|
||||||
// padding-right: 40px !important;
|
|
||||||
// }
|
|
||||||
// > div ~ div {
|
|
||||||
// padding-left: 40px !important;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// .dropzone-container {
|
|
||||||
// align-self: end;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// .dropzone {
|
|
||||||
// width: 300px;
|
|
||||||
// height: 100px;
|
|
||||||
// margin-right: 20px;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// .form-group--contact-name {
|
|
||||||
// .bp3-form-group.bp3-inline label.bp3-label {
|
|
||||||
// line-height: 30px;
|
|
||||||
// display: inline-block;
|
|
||||||
// margin: 0 45px 0 0;
|
|
||||||
// width: 200px;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// .bp3-input-group .bp3-input {
|
|
||||||
// position: relative;
|
|
||||||
// // display: none;
|
|
||||||
// width: 100%;
|
|
||||||
// // margin-left: 30px;
|
|
||||||
// }
|
|
||||||
// // .row {
|
|
||||||
// // width: fit-content;
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// // .#{$ns}-form-content{
|
|
||||||
// // width: 350px;
|
|
||||||
// // }
|
|
||||||
// }
|
|
||||||
|
|||||||
@@ -17,17 +17,21 @@ export default class ContactsController extends BaseController {
|
|||||||
check('work_phone').optional().trim().escape(),
|
check('work_phone').optional().trim().escape(),
|
||||||
check('personal_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_city').optional().trim().escape(),
|
||||||
check('billing_address_country').optional().trim().escape(),
|
check('billing_address_country').optional().trim().escape(),
|
||||||
check('billing_address_email').optional().isEmail().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_phone').optional().trim().escape(),
|
||||||
check('billing_address_state').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_city').optional().trim().escape(),
|
||||||
check('shipping_address_country').optional().trim().escape(),
|
check('shipping_address_country').optional().trim().escape(),
|
||||||
check('shipping_address_email').optional().isEmail().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_phone').optional().trim().escape(),
|
||||||
check('shipping_address_state').optional().trim().escape(),
|
check('shipping_address_state').optional().trim().escape(),
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ export default class CustomersController extends ContactsController {
|
|||||||
...this.contactDTOSchema,
|
...this.contactDTOSchema,
|
||||||
...this.contactNewDTOSchema,
|
...this.contactNewDTOSchema,
|
||||||
...this.customerDTOSchema,
|
...this.customerDTOSchema,
|
||||||
|
...this.createCustomerDTOSchema,
|
||||||
],
|
],
|
||||||
this.validationResult,
|
this.validationResult,
|
||||||
asyncMiddleware(this.newCustomer.bind(this)),
|
asyncMiddleware(this.newCustomer.bind(this)),
|
||||||
@@ -77,10 +78,24 @@ export default class CustomersController extends ContactsController {
|
|||||||
get customerDTOSchema() {
|
get customerDTOSchema() {
|
||||||
return [
|
return [
|
||||||
check('customer_type').exists().trim().escape(),
|
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() {
|
get validateListQuerySchema() {
|
||||||
return [
|
return [
|
||||||
query('column_sort_by').optional().trim().escape(),
|
query('column_sort_by').optional().trim().escape(),
|
||||||
|
|||||||
@@ -7,7 +7,10 @@ exports.up = function(knex) {
|
|||||||
table.string('contact_type');
|
table.string('contact_type');
|
||||||
|
|
||||||
table.decimal('balance', 13, 3).defaultTo(0);
|
table.decimal('balance', 13, 3).defaultTo(0);
|
||||||
|
table.string('currency_code', 3);
|
||||||
|
|
||||||
table.decimal('opening_balance', 13, 3).defaultTo(0);
|
table.decimal('opening_balance', 13, 3).defaultTo(0);
|
||||||
|
table.date('opening_balance_at');
|
||||||
|
|
||||||
table.string('first_name').nullable();
|
table.string('first_name').nullable();
|
||||||
table.string('last_name').nullable();
|
table.string('last_name').nullable();
|
||||||
@@ -19,12 +22,12 @@ exports.up = function(knex) {
|
|||||||
table.string('work_phone').nullable();
|
table.string('work_phone').nullable();
|
||||||
table.string('personal_phone').nullable();
|
table.string('personal_phone').nullable();
|
||||||
|
|
||||||
table.string('billing_address_1').nullable();
|
table.string('billing_address1').nullable();
|
||||||
table.string('billing_address_2').nullable();
|
table.string('billing_address2').nullable();
|
||||||
table.string('billing_address_city').nullable();
|
table.string('billing_address_city').nullable();
|
||||||
table.string('billing_address_country').nullable();
|
table.string('billing_address_country').nullable();
|
||||||
table.string('billing_address_email').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_phone').nullable();
|
||||||
table.string('billing_address_state').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_city').nullable();
|
||||||
table.string('shipping_address_country').nullable();
|
table.string('shipping_address_country').nullable();
|
||||||
table.string('shipping_address_email').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_phone').nullable();
|
||||||
table.string('shipping_address_state').nullable();
|
table.string('shipping_address_state').nullable();
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,10 @@ export interface IContact extends IContactAddress{
|
|||||||
contactType: string,
|
contactType: string,
|
||||||
|
|
||||||
balance: number,
|
balance: number,
|
||||||
|
currencyCode: string,
|
||||||
|
|
||||||
openingBalance: number,
|
openingBalance: number,
|
||||||
|
openingBalanceAt: Date,
|
||||||
|
|
||||||
firstName: string,
|
firstName: string,
|
||||||
lastName: string,
|
lastName: string,
|
||||||
@@ -64,7 +67,10 @@ export interface IContact extends IContactAddress{
|
|||||||
export interface IContactNewDTO {
|
export interface IContactNewDTO {
|
||||||
contactType?: string,
|
contactType?: string,
|
||||||
|
|
||||||
|
currencyCode?: string,
|
||||||
|
|
||||||
openingBalance?: number,
|
openingBalance?: number,
|
||||||
|
openingBalanceAt?: string,
|
||||||
|
|
||||||
firstName?: string,
|
firstName?: string,
|
||||||
lastName?: string,
|
lastName?: string,
|
||||||
@@ -81,8 +87,6 @@ export interface IContactNewDTO {
|
|||||||
export interface IContactEditDTO {
|
export interface IContactEditDTO {
|
||||||
contactType?: string,
|
contactType?: string,
|
||||||
|
|
||||||
openingBalance?: number,
|
|
||||||
|
|
||||||
firstName?: string,
|
firstName?: string,
|
||||||
lastName?: string,
|
lastName?: string,
|
||||||
companyName?: string,
|
companyName?: string,
|
||||||
@@ -104,7 +108,10 @@ export interface ICustomer extends IContact {
|
|||||||
export interface ICustomerNewDTO extends IContactAddressDTO {
|
export interface ICustomerNewDTO extends IContactAddressDTO {
|
||||||
customerType: string,
|
customerType: string,
|
||||||
|
|
||||||
|
currencyCode: string,
|
||||||
|
|
||||||
openingBalance?: number,
|
openingBalance?: number,
|
||||||
|
openingBalanceAt?: string,
|
||||||
|
|
||||||
firstName?: string,
|
firstName?: string,
|
||||||
lastName?: string,
|
lastName?: string,
|
||||||
@@ -121,8 +128,6 @@ export interface ICustomerNewDTO extends IContactAddressDTO {
|
|||||||
export interface ICustomerEditDTO extends IContactAddressDTO {
|
export interface ICustomerEditDTO extends IContactAddressDTO {
|
||||||
customerType: string,
|
customerType: string,
|
||||||
|
|
||||||
openingBalance?: number,
|
|
||||||
|
|
||||||
firstName?: string,
|
firstName?: string,
|
||||||
lastName?: string,
|
lastName?: string,
|
||||||
companyName?: string,
|
companyName?: string,
|
||||||
@@ -142,7 +147,10 @@ export interface IVendor extends IContact {
|
|||||||
contactService: 'vendor',
|
contactService: 'vendor',
|
||||||
}
|
}
|
||||||
export interface IVendorNewDTO extends IContactAddressDTO {
|
export interface IVendorNewDTO extends IContactAddressDTO {
|
||||||
|
currencyCode: string,
|
||||||
|
|
||||||
openingBalance?: number,
|
openingBalance?: number,
|
||||||
|
openingBalanceAt?: string,
|
||||||
|
|
||||||
firstName?: string,
|
firstName?: string,
|
||||||
lastName?: string,
|
lastName?: string,
|
||||||
@@ -157,8 +165,6 @@ export interface IVendorNewDTO extends IContactAddressDTO {
|
|||||||
active?: boolean,
|
active?: boolean,
|
||||||
};
|
};
|
||||||
export interface IVendorEditDTO extends IContactAddressDTO {
|
export interface IVendorEditDTO extends IContactAddressDTO {
|
||||||
openingBalance?: number,
|
|
||||||
|
|
||||||
firstName?: string,
|
firstName?: string,
|
||||||
lastName?: string,
|
lastName?: string,
|
||||||
companyName?: string,
|
companyName?: string,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Inject, Service } from 'typedi';
|
import { Inject, Service } from 'typedi';
|
||||||
import { difference, upperFirst } from 'lodash';
|
import { difference, upperFirst, omit } from 'lodash';
|
||||||
import { ServiceError } from "exceptions";
|
import { ServiceError } from "exceptions";
|
||||||
import TenancyService from 'services/Tenancy/TenancyService';
|
import TenancyService from 'services/Tenancy/TenancyService';
|
||||||
import {
|
import {
|
||||||
@@ -38,17 +38,39 @@ export default class ContactsService {
|
|||||||
return contact;
|
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.
|
* Creates a new contact on the storage.
|
||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
* @param {TContactService} contactService
|
* @param {TContactService} contactService
|
||||||
* @param {IContactDTO} contactDTO
|
* @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 { contactRepository } = this.tenancy.repositories(tenantId);
|
||||||
|
const contactObj = this.transformContactObj(contactDTO);
|
||||||
|
|
||||||
this.logger.info('[contacts] trying to insert contact to the storage.', { tenantId, 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 });
|
this.logger.info('[contacts] contact inserted successfully.', { tenantId, contact });
|
||||||
return contact;
|
return contact;
|
||||||
@@ -63,10 +85,12 @@ export default class ContactsService {
|
|||||||
*/
|
*/
|
||||||
async editContact(tenantId: number, contactId: number, contactDTO: IContactEditDTO, contactService: TContactService) {
|
async editContact(tenantId: number, contactId: number, contactDTO: IContactEditDTO, contactService: TContactService) {
|
||||||
const { Contact } = this.tenancy.models(tenantId);
|
const { Contact } = this.tenancy.models(tenantId);
|
||||||
|
const contactObj = this.transformContactObj(contactDTO);
|
||||||
|
|
||||||
const contact = await this.getContactByIdOrThrowError(tenantId, contactId, contactService);
|
const contact = await this.getContactByIdOrThrowError(tenantId, contactId, contactService);
|
||||||
|
|
||||||
this.logger.info('[contacts] trying to edit the given contact details.', { tenantId, contactId, contactDTO });
|
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,
|
ICustomerEditDTO,
|
||||||
ICustomer,
|
ICustomer,
|
||||||
IPaginationMeta,
|
IPaginationMeta,
|
||||||
ICustomersFilter
|
ICustomersFilter,
|
||||||
|
IContactNewDTO,
|
||||||
|
IContactEditDTO
|
||||||
} from 'interfaces';
|
} from 'interfaces';
|
||||||
import { ServiceError } from 'exceptions';
|
import { ServiceError } from 'exceptions';
|
||||||
import TenancyService from 'services/Tenancy/TenancyService';
|
import TenancyService from 'services/Tenancy/TenancyService';
|
||||||
import DynamicListingService from 'services/DynamicListing/DynamicListService';
|
import DynamicListingService from 'services/DynamicListing/DynamicListService';
|
||||||
import events from 'subscribers/events';
|
import events from 'subscribers/events';
|
||||||
|
import moment from 'moment';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export default class CustomersService {
|
export default class CustomersService {
|
||||||
@@ -41,7 +44,7 @@ export default class CustomersService {
|
|||||||
* @param {ICustomerNewDTO|ICustomerEditDTO} customerDTO
|
* @param {ICustomerNewDTO|ICustomerEditDTO} customerDTO
|
||||||
* @returns {IContactDTO}
|
* @returns {IContactDTO}
|
||||||
*/
|
*/
|
||||||
private customerToContactDTO(customerDTO: ICustomerNewDTO | ICustomerEditDTO) {
|
private customerToContactDTO(customerDTO: ICustomerNewDTO|ICustomerEditDTO): IContactNewDTO|IContactEditDTO {
|
||||||
return {
|
return {
|
||||||
...omit(customerDTO, ['customerType']),
|
...omit(customerDTO, ['customerType']),
|
||||||
contactType: 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.
|
* Creates a new customer.
|
||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
@@ -62,8 +77,8 @@ export default class CustomersService {
|
|||||||
): Promise<ICustomer> {
|
): Promise<ICustomer> {
|
||||||
this.logger.info('[customer] trying to create a new customer.', { tenantId, customerDTO });
|
this.logger.info('[customer] trying to create a new customer.', { tenantId, customerDTO });
|
||||||
|
|
||||||
const contactDTO = this.customerToContactDTO(customerDTO)
|
const customerObj = this.transformNewCustomerDTO(customerDTO);
|
||||||
const customer = await this.contactService.newContact(tenantId, contactDTO, 'customer');
|
const customer = await this.contactService.newContact(tenantId, customerObj, 'customer');
|
||||||
|
|
||||||
this.logger.info('[customer] created successfully.', { tenantId, customerDTO });
|
this.logger.info('[customer] created successfully.', { tenantId, customerDTO });
|
||||||
await this.eventDispatcher.dispatch(events.customers.onCreated, {
|
await this.eventDispatcher.dispatch(events.customers.onCreated, {
|
||||||
|
|||||||
Reference in New Issue
Block a user