diff --git a/client/src/containers/Accounting/MakeJournalEntriesForm.js b/client/src/containers/Accounting/MakeJournalEntriesForm.js
index fb8025875..0eded5f18 100644
--- a/client/src/containers/Accounting/MakeJournalEntriesForm.js
+++ b/client/src/containers/Accounting/MakeJournalEntriesForm.js
@@ -27,7 +27,12 @@ import Dragzone from 'components/Dragzone';
import withMediaActions from 'containers/Media/withMediaActions';
import useMedia from 'hooks/useMedia';
-import { compose, repeatValue, orderingLinesIndexes } from 'utils';
+import {
+ compose,
+ repeatValue,
+ orderingLinesIndexes,
+ defaultToTransform,
+} from 'utils';
import withManualJournalsActions from './withManualJournalsActions';
import withManualJournals from './withManualJournals';
@@ -97,13 +102,18 @@ function MakeJournalEntriesForm({
: journalNextNumber;
useEffect(() => {
+ const transactionNumber = manualJournal
+ ? manualJournal.journal_number
+ : journalNumber;
+
if (manualJournal && manualJournal.id) {
changePageTitle(formatMessage({ id: 'edit_journal' }));
- changePageSubtitle(`No. ${manualJournal.journal_number}`);
} else {
- changePageSubtitle(`No. ${journalNumber}`);
changePageTitle(formatMessage({ id: 'new_journal' }));
}
+ changePageSubtitle(
+ defaultToTransform(transactionNumber, `No. ${transactionNumber}`, ''),
+ );
}, [
changePageTitle,
changePageSubtitle,
@@ -383,7 +393,9 @@ function MakeJournalEntriesForm({
useEffect(() => {
if (journalNumberChanged) {
setFieldValue('journal_number', journalNumber);
- changePageSubtitle(`No. ${journalNumber}`);
+ changePageSubtitle(
+ defaultToTransform(journalNumber, `No. ${journalNumber}`, ''),
+ );
setJournalNumberChanged(false);
}
}, [
@@ -440,7 +452,9 @@ function MakeJournalEntriesForm({
// Handle journal number field change.
const handleJournalNumberChanged = useCallback(
(journalNumber) => {
- changePageSubtitle(`No. ${journalNumber}`);
+ changePageSubtitle(
+ defaultToTransform(journalNumber, `No. ${journalNumber}`, '')
+ );
},
[changePageSubtitle],
);
diff --git a/client/src/containers/Dialogs/AccountFormDialog/AccountFormDialogContent.js b/client/src/containers/Dialogs/AccountFormDialog/AccountFormDialogContent.js
index 5880c8f8f..a0ea4f5cc 100644
--- a/client/src/containers/Dialogs/AccountFormDialog/AccountFormDialogContent.js
+++ b/client/src/containers/Dialogs/AccountFormDialog/AccountFormDialogContent.js
@@ -345,6 +345,7 @@ function AccountFormDialogContent({
onAccountSelected={onChangeSubaccount}
defaultSelectText={}
selectedAccountId={values.parent_account_id}
+ popoverFill={true}
/>
diff --git a/client/src/containers/Purchases/PaymentMades/PaymentMadeActionsBar.js b/client/src/containers/Purchases/PaymentMades/PaymentMadeActionsBar.js
index c7afc012f..0ea2b5c74 100644
--- a/client/src/containers/Purchases/PaymentMades/PaymentMadeActionsBar.js
+++ b/client/src/containers/Purchases/PaymentMades/PaymentMadeActionsBar.js
@@ -49,7 +49,7 @@ function PaymentMadeActionsBar({
const { formatMessage } = useIntl();
const handleClickNewPaymentMade = useCallback(() => {
- history.push('/payment-made/new');
+ history.push('/payment-mades/new');
}, [history]);
// const filterDropdown = FilterDropdown({
diff --git a/client/src/containers/Purchases/PaymentMades/PaymentMadeForm.schema.js b/client/src/containers/Purchases/PaymentMades/PaymentMadeForm.schema.js
index d0d22b619..8f818d943 100644
--- a/client/src/containers/Purchases/PaymentMades/PaymentMadeForm.schema.js
+++ b/client/src/containers/Purchases/PaymentMades/PaymentMadeForm.schema.js
@@ -13,6 +13,7 @@ const Schema = Yup.object().shape({
.required()
.label(formatMessage({ id: 'payment_account_' })),
payment_number: Yup.string()
+ .nullable()
.max(DATATYPES_LENGTH.STRING)
.label(formatMessage({ id: 'payment_no_' })),
reference: Yup.string().min(1).max(DATATYPES_LENGTH.STRING).nullable(),
diff --git a/client/src/containers/Purchases/PaymentMades/PaymentMadeFormHeader.js b/client/src/containers/Purchases/PaymentMades/PaymentMadeFormHeader.js
index c7c2e26de..262106929 100644
--- a/client/src/containers/Purchases/PaymentMades/PaymentMadeFormHeader.js
+++ b/client/src/containers/Purchases/PaymentMades/PaymentMadeFormHeader.js
@@ -107,6 +107,7 @@ function PaymentMadeFormHeader({
defaultSelectText={ }
onContactSelected={onChangeSelect('vendor_id')}
disabled={!isNewMode}
+ popoverFill={true}
/>
diff --git a/client/src/containers/Sales/Estimate/EstimateForm.js b/client/src/containers/Sales/Estimate/EstimateForm.js
index 5beaaeb8c..71dd1e9be 100644
--- a/client/src/containers/Sales/Estimate/EstimateForm.js
+++ b/client/src/containers/Sales/Estimate/EstimateForm.js
@@ -31,7 +31,12 @@ import Dragzone from 'components/Dragzone';
import useMedia from 'hooks/useMedia';
import { ERROR } from 'common/errors';
-import { compose, repeatValue, orderingLinesIndexes } from 'utils';
+import {
+ compose,
+ repeatValue,
+ defaultToTransform,
+ orderingLinesIndexes,
+} from 'utils';
const MIN_LINES_NUMBER = 4;
@@ -98,16 +103,20 @@ const EstimateForm = ({
: estimateNextNumber;
useEffect(() => {
- if (estimate && estimate.id) {
+ const transNumber = !isNewMode ? estimate.estimate_number : estimateNumber;
+
+ if (isNewMode) {
changePageTitle(formatMessage({ id: 'edit_estimate' }));
- changePageSubtitle(`No. ${estimate.estimate_number}`);
} else {
- changePageSubtitle(`No. ${estimateNumber}`);
changePageTitle(formatMessage({ id: 'new_estimate' }));
}
+ changePageSubtitle(
+ defaultToTransform(estimateNumber, `No. ${transNumber}`, ''),
+ );
}, [
estimate,
estimateNumber,
+ isNewMode,
formatMessage,
changePageTitle,
changePageSubtitle,
@@ -211,18 +220,26 @@ const EstimateForm = ({
const handleEstimateNumberChange = useCallback(
(estimateNumber) => {
- changePageSubtitle(`No. ${estimateNumber}`);
+ changePageSubtitle(
+ defaultToTransform(estimateNumber, `No. ${estimateNumber}`, ''),
+ );
},
[changePageSubtitle],
);
- const handleSubmitClick = useCallback((event) => {
- setSubmitPayload({ redirect: true });
- }, [setSubmitPayload]);
+ const handleSubmitClick = useCallback(
+ (event) => {
+ setSubmitPayload({ redirect: true });
+ },
+ [setSubmitPayload],
+ );
- const handleCancelClick = useCallback((event) => {
- history.goBack();
- }, [history]);
+ const handleCancelClick = useCallback(
+ (event) => {
+ history.goBack();
+ },
+ [history],
+ );
return (
@@ -238,8 +255,8 @@ const EstimateForm = ({
-
-
+
+
{
form.setFieldValue('customer_id', customer.id);
}}
+ popoverFill={true}
/>
)}
diff --git a/client/src/containers/Sales/Invoice/InvoiceForm.js b/client/src/containers/Sales/Invoice/InvoiceForm.js
index dbafc74ac..dc5336b98 100644
--- a/client/src/containers/Sales/Invoice/InvoiceForm.js
+++ b/client/src/containers/Sales/Invoice/InvoiceForm.js
@@ -30,7 +30,12 @@ import { AppToaster } from 'components';
import useMedia from 'hooks/useMedia';
import { ERROR } from 'common/errors';
-import { compose, repeatValue, saveInvoke, orderingLinesIndexes } from 'utils';
+import {
+ compose,
+ repeatValue,
+ defaultToTransform,
+ orderingLinesIndexes,
+} from 'utils';
import { useHistory } from 'react-router-dom';
const MIN_LINES_NUMBER = 4;
@@ -94,13 +99,16 @@ function InvoiceForm({
: invoiceNextNumber;
useEffect(() => {
+ const transactionNumber = invoice ? invoice.invoice_no : invoiceNumber;
+
if (invoice && invoice.id) {
changePageTitle(formatMessage({ id: 'edit_invoice' }));
- changePageSubtitle(`No. ${invoice.invoice_no}`);
} else {
- changePageSubtitle(`No. ${invoiceNumber}`);
changePageTitle(formatMessage({ id: 'new_invoice' }));
}
+ changePageSubtitle(
+ defaultToTransform(transactionNumber, `No. ${transactionNumber}`, ''),
+ );
}, [
changePageTitle,
changePageSubtitle,
@@ -216,7 +224,9 @@ function InvoiceForm({
const handleInvoiceNumberChanged = useCallback(
(invoiceNumber) => {
- changePageSubtitle(`No. ${invoiceNumber}`);
+ changePageSubtitle(
+ defaultToTransform(invoiceNumber, `No. ${invoiceNumber}`, ''),
+ );
},
[changePageSubtitle],
);
@@ -236,7 +246,10 @@ function InvoiceForm({
onInvoiceNumberChanged={handleInvoiceNumberChanged}
/>
-
+
{
form.setFieldValue('customer_id', customer.id);
}}
+ popoverFill={true}
/>
)}
diff --git a/client/src/containers/Sales/PaymentReceive/PaymentReceiveActionsBar.js b/client/src/containers/Sales/PaymentReceive/PaymentReceiveActionsBar.js
index ca8b78412..33c45c3cb 100644
--- a/client/src/containers/Sales/PaymentReceive/PaymentReceiveActionsBar.js
+++ b/client/src/containers/Sales/PaymentReceive/PaymentReceiveActionsBar.js
@@ -49,7 +49,7 @@ function PaymentReceiveActionsBar({
const { formatMessage } = useIntl();
const handleClickNewPaymentReceive = useCallback(() => {
- history.push('/payment-receive/new');
+ history.push('/payment-receives/new');
}, [history]);
// const filterDropdown = FilterDropdown({
diff --git a/client/src/containers/Sales/PaymentReceive/PaymentReceiveForm.js b/client/src/containers/Sales/PaymentReceive/PaymentReceiveForm.js
index bd9e3e71f..a33136c25 100644
--- a/client/src/containers/Sales/PaymentReceive/PaymentReceiveForm.js
+++ b/client/src/containers/Sales/PaymentReceive/PaymentReceiveForm.js
@@ -1,18 +1,11 @@
-import React, {
- useMemo,
- useCallback,
- useEffect,
- useState,
- useRef,
-} from 'react';
-
-import * as Yup from 'yup';
+import React, { useMemo, useCallback, useEffect, useState } from 'react';
import { useFormik } from 'formik';
import moment from 'moment';
import { FormattedMessage as T, useIntl } from 'react-intl';
import { pick, sumBy, omit } from 'lodash';
import { Intent, Alert } from '@blueprintjs/core';
import classNames from 'classnames';
+import { useHistory } from 'react-router-dom';
import { CLASSES } from 'common/classes';
import PaymentReceiveHeader from './PaymentReceiveFormHeader';
@@ -32,7 +25,7 @@ import {
} from './PaymentReceiveForm.schema';
import { AppToaster } from 'components';
-import { compose } from 'utils';
+import { compose, defaultToTransform } from 'utils';
/**
* Payment Receive form.
@@ -62,35 +55,45 @@ function PaymentReceiveForm({
changePageTitle,
changePageSubtitle,
}) {
+ const history = useHistory();
+
const [amountChangeAlert, setAmountChangeAlert] = useState(false);
const [clearLinesAlert, setClearLinesAlert] = useState(false);
const [fullAmount, setFullAmount] = useState(null);
const [clearFormAlert, setClearFormAlert] = useState(false);
const { formatMessage } = useIntl();
- const isNewMode = !paymentReceiveId;
const [localPaymentEntries, setLocalPaymentEntries] = useState(
paymentReceiveEntries,
);
+ const isNewMode = !paymentReceiveId;
const paymentReceiveNumber = paymentReceiveNumberPrefix
? `${paymentReceiveNumberPrefix}-${paymentReceiveNextNumber}`
: paymentReceiveNextNumber;
useEffect(() => {
+ const transactionNumber = !isNewMode
+ ? paymentReceive.payment_receive_no
+ : paymentReceiveNumber;
+
if (paymentReceive && paymentReceiveId) {
changePageTitle(formatMessage({ id: 'edit_payment_receive' }));
changePageSubtitle(`No. ${paymentReceive.payment_receive_no}`);
} else {
- changePageSubtitle(`No. ${paymentReceiveNumber}`);
changePageTitle(formatMessage({ id: 'payment_receive' }));
}
+ changePageSubtitle(
+ defaultToTransform(transactionNumber, `No. ${transactionNumber}`, ''),
+ );
}, [
+ isNewMode,
changePageTitle,
changePageSubtitle,
paymentReceive,
paymentReceiveId,
formatMessage,
+ paymentReceiveNumber,
]);
useEffect(() => {
@@ -103,7 +106,7 @@ function PaymentReceiveForm({
const validationSchema = isNewMode
? CreatePaymentReceiveFormSchema
: EditPaymentReceiveFormSchema;
-
+
// Default payment receive entry.
const defaultPaymentReceiveEntry = {
id: null,
@@ -167,8 +170,8 @@ function PaymentReceiveForm({
AppToaster.show({
message: formatMessage({
id: 'you_cannot_make_payment_with_zero_total_amount',
- intent: Intent.WARNING,
}),
+ intent: Intent.DANGER,
});
setSubmitting(false);
return;
@@ -180,13 +183,14 @@ function PaymentReceiveForm({
AppToaster.show({
message: formatMessage({
id: paymentReceiveId
- ? 'the_payment_has_been_received_successfully_edited'
- : 'the_payment_has_been_received_successfully_created',
+ ? 'the_payment_receive_transaction_has_been_edited'
+ : 'the_payment_receive_transaction_has_been_created',
}),
intent: Intent.SUCCESS,
});
setSubmitting(false);
resetForm();
+ history.push('/payment-receives');
};
// Handle request response errors.
const onError = (errors) => {
@@ -321,7 +325,13 @@ function PaymentReceiveForm({
useEffect(() => {
if (paymentReceiveNumberChanged) {
setFieldValue('payment_receive_no', paymentReceiveNumber);
- changePageSubtitle(`No. ${paymentReceiveNumber}`);
+ changePageSubtitle(
+ defaultToTransform(
+ paymentReceiveNumber,
+ `No. ${paymentReceiveNumber}`,
+ '',
+ ),
+ );
setPaymentReceiveNumberChanged(false);
}
}, [
@@ -329,11 +339,14 @@ function PaymentReceiveForm({
paymentReceiveNumberChanged,
setFieldValue,
changePageSubtitle,
+ setPaymentReceiveNumberChanged,
]);
const handlePaymentReceiveNumberChanged = useCallback(
(payment_receive_no) => {
- changePageSubtitle(`No.${payment_receive_no}`);
+ changePageSubtitle(
+ defaultToTransform(payment_receive_no, `No.${payment_receive_no}`, ''),
+ );
},
[changePageSubtitle],
);
diff --git a/client/src/containers/Sales/PaymentReceive/PaymentReceiveForm.schema.js b/client/src/containers/Sales/PaymentReceive/PaymentReceiveForm.schema.js
index 39982e0f2..de9e40581 100644
--- a/client/src/containers/Sales/PaymentReceive/PaymentReceiveForm.schema.js
+++ b/client/src/containers/Sales/PaymentReceive/PaymentReceiveForm.schema.js
@@ -14,6 +14,7 @@ const Schema = Yup.object().shape({
.label(formatMessage({ id: 'deposit_account_' })),
full_amount: Yup.number().nullable(),
payment_receive_no: Yup.string()
+ .nullable()
.max(DATATYPES_LENGTH.STRING)
.label(formatMessage({ id: 'payment_receive_no_' })),
reference_no: Yup.string().min(1).max(DATATYPES_LENGTH.STRING).nullable(),
diff --git a/client/src/containers/Sales/PaymentReceive/PaymentReceiveFormHeader.js b/client/src/containers/Sales/PaymentReceive/PaymentReceiveFormHeader.js
index cd6d5ec7d..7144fa3df 100644
--- a/client/src/containers/Sales/PaymentReceive/PaymentReceiveFormHeader.js
+++ b/client/src/containers/Sales/PaymentReceive/PaymentReceiveFormHeader.js
@@ -114,6 +114,7 @@ function PaymentReceiveFormHeader({
selectedContactId={values.customer_id}
defaultSelectText={}
onContactSelected={onChangeSelect('customer_id')}
+ popoverFill={true}
/>
diff --git a/client/src/containers/Sales/PaymentReceive/PaymentReceivesEmptyStatus.js b/client/src/containers/Sales/PaymentReceive/PaymentReceivesEmptyStatus.js
index 1a6f0caaf..f307dc64a 100644
--- a/client/src/containers/Sales/PaymentReceive/PaymentReceivesEmptyStatus.js
+++ b/client/src/containers/Sales/PaymentReceive/PaymentReceivesEmptyStatus.js
@@ -21,7 +21,7 @@ export default function PaymentReceivesEmptyStatus() {
intent={Intent.PRIMARY}
large={true}
onClick={() => {
- history.push('/payment-receive/new');
+ history.push('/payment-receives/new');
}}
>
New payment receive
diff --git a/client/src/containers/Sales/Receipt/ReceiptForm.js b/client/src/containers/Sales/Receipt/ReceiptForm.js
index 23462955f..7b49c6bbe 100644
--- a/client/src/containers/Sales/Receipt/ReceiptForm.js
+++ b/client/src/containers/Sales/Receipt/ReceiptForm.js
@@ -32,7 +32,12 @@ import { AppToaster } from 'components';
import Dragzone from 'components/Dragzone';
import useMedia from 'hooks/useMedia';
-import { compose, repeatValue, orderingLinesIndexes } from 'utils';
+import {
+ compose,
+ repeatValue,
+ orderingLinesIndexes,
+ defaultToTransform,
+} from 'utils';
const MIN_LINES_NUMBER = 4;
@@ -97,14 +102,20 @@ function ReceiptForm({
: receiptNextNumber;
useEffect(() => {
+ const transactionNumber = !isNewMode
+ ? receipt.receipt_number
+ : receiptNumber;
+
if (receipt && receipt.id) {
changePageTitle(formatMessage({ id: 'edit_receipt' }));
- changePageSubtitle(`No. ${receipt.receipt_number}`);
} else {
- changePageSubtitle(`No. ${receiptNumber}`);
changePageTitle(formatMessage({ id: 'new_receipt' }));
}
+ changePageSubtitle(
+ defaultToTransform(transactionNumber, `No. ${transactionNumber}`, ''),
+ );
}, [
+ isNewMode,
changePageTitle,
changePageSubtitle,
receipt,
@@ -213,7 +224,9 @@ function ReceiptForm({
const handleReceiptNumberChanged = useCallback(
(receiptNumber) => {
- changePageSubtitle(`No. ${receiptNumber}`);
+ changePageSubtitle(
+ defaultToTransform(receiptNumber, `No. ${receiptNumber}`, ''),
+ );
},
[changePageSubtitle],
);
@@ -244,7 +257,7 @@ function ReceiptForm({
onReceiptNumberChanged={handleReceiptNumberChanged}
/>
-
+
{
form.setFieldValue('customer_id', contact.id);
}}
+ popoverFill={true}
/>
)}
@@ -103,6 +104,7 @@ function ReceiptFormHeader({
defaultSelectText={}
selectedAccountId={value}
filterByTypes={['current_asset']}
+ popoverFill={true}
/>
)}
diff --git a/client/src/lang/en/index.js b/client/src/lang/en/index.js
index 8076e4b5f..8cf64e6e2 100644
--- a/client/src/lang/en/index.js
+++ b/client/src/lang/en/index.js
@@ -91,7 +91,6 @@ export default {
count: 'Count',
item_type: 'Item Type',
item_name: 'Item Name',
- sku: 'SKU',
category: 'Category',
account: 'Account',
sales_information: 'Sales Information',
@@ -689,12 +688,12 @@ export default {
payment_receive_no_: 'Payment receive no',
receive_amount: 'Receive Amount',
receive_amount_: 'Receive amount',
- the_payment_has_been_received_successfully_created:
- 'The payment has been received successfully created.',
+ the_payment_receive_transaction_has_been_created:
+ 'The payment receive transaction has been created successfully.',
the_payment_receive_has_been_successfully_deleted:
'The payment receive has been successfully deleted.',
- the_payment_has_been_received_successfully_edited:
- 'The payment has been received successfully edited.',
+ the_payment_receive_transaction_has_been_edited:
+ 'The payment receive transaction has been edited successfully.',
once_delete_this_payment_receive_you_will_able_to_restore_it: `Once you delete this payment receive, you won\'t be able to restore it later. Are you sure you want to delete this payment receive?`,
select_invoice: 'Select Invoice',
payment_mades: 'Payment Mades',
@@ -841,4 +840,6 @@ export default {
once_delete_these_vendors_you_will_not_able_restore_them:
"Once you delete these vendors, you won't be able to retrieve them later. Are you sure you want to delete them?",
vendor_has_bills: 'Vendor has bills',
+ the_item_has_been_edited_successfully: 'The item has been edited successfully.',
+ you_cannot_make_payment_with_zero_total_amount: 'You cannot record payment transaction with zero total amount',
};
diff --git a/client/src/style/views/Sidebar.scss b/client/src/style/views/Sidebar.scss
index 01e730b9c..83c345042 100644
--- a/client/src/style/views/Sidebar.scss
+++ b/client/src/style/views/Sidebar.scss
@@ -89,13 +89,17 @@ $sidebar-submenu-item-bg-color: #01287d;
margin-top: 3px;
color: rgba(255, 255, 255, 0.25);
}
- &-label{
+ &-labeler{
display: block;
color: $sidebar-menu-label-color;
font-size: 12px;
padding: 6px 16px;
margin-top: 4px;
}
+
+ &:hover .bp3-button.menu-item__add-btn{
+ display: inline-block;
+ }
}
.#{$ns}-submenu {
@@ -188,4 +192,42 @@ $sidebar-submenu-item-bg-color: #01287d;
}
}
}
+
+ .bp3-button.menu-item__add-btn{
+ width: auto;
+
+ padding: 2px;
+ margin-right: 0px;
+ position: relative;
+ top: 1px;
+ border-radius: 3px;
+ display: none;
+ vertical-align: top;
+
+ &:not([class*="bp3-intent-"]):not(.bp3-minimal):not(:disabled){
+
+ .bp3-icon{
+ color: rgba(255, 255, 255, 0.4);
+ }
+ &,
+ &:hover{
+ min-height: auto;
+ min-width: auto;
+ outline: 0;
+ background-color: transparent;
+ }
+
+ &:hover{
+ background-color: rgba(255, 255, 255, 0.12);
+
+ .bp3-icon{
+ color: rgba(255, 255, 255, 0.6);
+ }
+ }
+ }
+ .bp3-icon{
+ margin: 0;
+ display: block;
+ }
+ }
}
diff --git a/server/src/api/controllers/Contacts/Contacts.ts b/server/src/api/controllers/Contacts/Contacts.ts
index 91a0c5f38..312938242 100644
--- a/server/src/api/controllers/Contacts/Contacts.ts
+++ b/server/src/api/controllers/Contacts/Contacts.ts
@@ -1,4 +1,4 @@
-import { check, param, query, ValidationChain } from 'express-validator';
+import { check, param, query, body, ValidationChain } from 'express-validator';
import BaseController from "api/controllers/BaseController";
export default class ContactsController extends BaseController {
@@ -48,7 +48,8 @@ export default class ContactsController extends BaseController {
*/
get contactNewDTOSchema(): ValidationChain[] {
return [
- check('balance').optional().isNumeric().toInt(),
+ check('opening_balance').optional({ nullable: true }).isNumeric().toInt(),
+ body('opening_balance_at').if(body('opening_balance').exists()).exists(),
];
}
diff --git a/server/src/api/controllers/Contacts/Customers.ts b/server/src/api/controllers/Contacts/Customers.ts
index 0b14944c0..433f74b51 100644
--- a/server/src/api/controllers/Contacts/Customers.ts
+++ b/server/src/api/controllers/Contacts/Customers.ts
@@ -90,9 +90,6 @@ export default class CustomersController extends ContactsController {
*/
get createCustomerDTOSchema() {
return [
- check('opening_balance').optional({ nullable: true }).isNumeric().toInt(),
- check('opening_balance_at').optional({ nullable: true }).isISO8601(),
-
check('currency_code').optional().trim().escape(),
];
}
diff --git a/server/src/api/controllers/Contacts/Vendors.ts b/server/src/api/controllers/Contacts/Vendors.ts
index 50e3e5b05..5a7041823 100644
--- a/server/src/api/controllers/Contacts/Vendors.ts
+++ b/server/src/api/controllers/Contacts/Vendors.ts
@@ -1,6 +1,7 @@
import { Request, Response, Router, NextFunction } from 'express';
import { Service, Inject } from 'typedi';
-import { check, query, ValidationChain } from 'express-validator';
+import { body, query, ValidationChain, check } from 'express-validator';
+
import ContactsController from 'api/controllers/Contacts/Contacts';
import VendorsService from 'services/Contacts/VendorsService';
import { ServiceError } from 'exceptions';
@@ -72,7 +73,7 @@ export default class VendorsController extends ContactsController {
*/
get vendorDTOSchema(): ValidationChain[] {
return [
- check('opening_balance').optional().isNumeric().toInt(),
+ check('currency_code').optional().trim().escape(),
];
}
@@ -105,7 +106,11 @@ export default class VendorsController extends ContactsController {
try {
const vendor = await this.vendorsService.newVendor(tenantId, contactDTO);
- return res.status(200).send({ id: vendor.id });
+
+ return res.status(200).send({
+ id: vendor.id,
+ message: 'The vendor has been created successfully.',
+ });
} catch (error) {
next(error);
}
@@ -124,7 +129,11 @@ export default class VendorsController extends ContactsController {
try {
await this.vendorsService.editVendor(tenantId, contactId, contactDTO);
- return res.status(200).send({ id: contactId });
+
+ return res.status(200).send({
+ id: contactId,
+ message: 'The vendor has been edited successfully.',
+ });
} catch (error) {
next(error);
}
@@ -142,7 +151,11 @@ export default class VendorsController extends ContactsController {
try {
await this.vendorsService.deleteVendor(tenantId, contactId)
- return res.status(200).send({ id: contactId });
+
+ return res.status(200).send({
+ id: contactId,
+ message: 'The vendor has been deleted successfully.',
+ });
} catch (error) {
next(error);
}
@@ -198,7 +211,11 @@ export default class VendorsController extends ContactsController {
};
try {
- const { vendors, pagination, filterMeta } = await this.vendorsService.getVendorsList(tenantId, vendorsFilter);
+ const {
+ vendors,
+ pagination,
+ filterMeta,
+ } = await this.vendorsService.getVendorsList(tenantId, vendorsFilter);
return res.status(200).send({
vendors,
@@ -219,21 +236,27 @@ export default class VendorsController extends ContactsController {
*/
handlerServiceErrors(error, req: Request, res: Response, next: NextFunction) {
if (error instanceof ServiceError) {
+ if (error.errorType === 'contact_not_found') {
+ return res.boom.badRequest(null, {
+ errors: [{ type: 'VENDOR.NOT.FOUND', code: 100 }],
+ });
+ }
if (error.errorType === 'contacts_not_found') {
return res.boom.badRequest(null, {
- errors: [{ type: 'VENDORS.NOT.FOUND', code: 100 }],
+ errors: [{ type: 'VENDORS.NOT.FOUND', code: 200 }],
});
}
if (error.errorType === 'some_vendors_have_bills') {
return res.boom.badRequest(null, {
- errors: [{ type: 'SOME.VENDORS.HAVE.BILLS', code: 200 }],
+ errors: [{ type: 'SOME.VENDORS.HAVE.BILLS', code: 300 }],
});
}
if (error.errorType === 'vendor_has_bills') {
return res.status(400).send({
- errors: [{ type: 'VENDOR.HAS.BILLS', code: 200 }],
+ errors: [{ type: 'VENDOR.HAS.BILLS', code: 400 }],
});
}
}
+ next(error);
}
}
\ No newline at end of file
diff --git a/server/src/api/controllers/Sales/PaymentReceives.ts b/server/src/api/controllers/Sales/PaymentReceives.ts
index 965515d9b..ea78563c5 100644
--- a/server/src/api/controllers/Sales/PaymentReceives.ts
+++ b/server/src/api/controllers/Sales/PaymentReceives.ts
@@ -84,7 +84,7 @@ export default class PaymentReceivesController extends BaseController {
check('payment_date').exists(),
check('reference_no').optional(),
check('deposit_account_id').exists().isNumeric().toInt(),
- check('payment_receive_no').exists().trim().escape(),
+ check('payment_receive_no').optional({ nullable: true }).trim().escape(),
check('statement').optional().trim().escape(),
check('entries').isArray({ min: 1 }),
diff --git a/server/src/services/Contacts/CustomersService.ts b/server/src/services/Contacts/CustomersService.ts
index e26faf14f..2f801d0e2 100644
--- a/server/src/services/Contacts/CustomersService.ts
+++ b/server/src/services/Contacts/CustomersService.ts
@@ -1,5 +1,5 @@
import { Inject, Service } from 'typedi';
-import { omit, difference } from 'lodash';
+import { omit, difference, defaultTo } from 'lodash';
import {
EventDispatcher,
EventDispatcherInterface,
@@ -51,8 +51,7 @@ export default class CustomersService {
return {
...omit(customerDTO, ['customerType']),
contactType: customerDTO.customerType,
- active: (typeof customerDTO.active === 'undefined') ?
- true : customerDTO.active,
+ active: defaultTo(customerDTO.active, true),
};
}
diff --git a/server/src/services/Contacts/VendorsService.ts b/server/src/services/Contacts/VendorsService.ts
index 8b5bb4862..a803aca8f 100644
--- a/server/src/services/Contacts/VendorsService.ts
+++ b/server/src/services/Contacts/VendorsService.ts
@@ -1,5 +1,5 @@
import { Inject, Service } from 'typedi';
-import { difference, rest } from 'lodash';
+import { difference, defaultTo } from 'lodash';
import {
EventDispatcher,
EventDispatcherInterface,
@@ -45,8 +45,7 @@ export default class VendorsService {
private vendorToContactDTO(vendorDTO: IVendorNewDTO|IVendorEditDTO) {
return {
...vendorDTO,
- active: (typeof vendorDTO.active === 'undefined') ?
- true : vendorDTO.active,
+ active: defaultTo(vendorDTO.active, true),
};
}
@@ -62,6 +61,7 @@ export default class VendorsService {
const contactDTO = this.vendorToContactDTO(vendorDTO);
const vendor = await this.contactService.newContact(tenantId, contactDTO, 'vendor');
+ // Triggers `onVendorCreated` event.
await this.eventDispatcher.dispatch(events.vendors.onCreated, {
tenantId, vendorId: vendor.id, vendor,
});