fix: subtitle issue with sales transaction number.

This commit is contained in:
Ahmed Bouhuolia
2020-11-24 11:33:29 +02:00
parent 218d90c571
commit 9779591029
24 changed files with 218 additions and 76 deletions

View File

@@ -27,7 +27,12 @@ import Dragzone from 'components/Dragzone';
import withMediaActions from 'containers/Media/withMediaActions'; import withMediaActions from 'containers/Media/withMediaActions';
import useMedia from 'hooks/useMedia'; import useMedia from 'hooks/useMedia';
import { compose, repeatValue, orderingLinesIndexes } from 'utils'; import {
compose,
repeatValue,
orderingLinesIndexes,
defaultToTransform,
} from 'utils';
import withManualJournalsActions from './withManualJournalsActions'; import withManualJournalsActions from './withManualJournalsActions';
import withManualJournals from './withManualJournals'; import withManualJournals from './withManualJournals';
@@ -97,13 +102,18 @@ function MakeJournalEntriesForm({
: journalNextNumber; : journalNextNumber;
useEffect(() => { useEffect(() => {
const transactionNumber = manualJournal
? manualJournal.journal_number
: journalNumber;
if (manualJournal && manualJournal.id) { if (manualJournal && manualJournal.id) {
changePageTitle(formatMessage({ id: 'edit_journal' })); changePageTitle(formatMessage({ id: 'edit_journal' }));
changePageSubtitle(`No. ${manualJournal.journal_number}`);
} else { } else {
changePageSubtitle(`No. ${journalNumber}`);
changePageTitle(formatMessage({ id: 'new_journal' })); changePageTitle(formatMessage({ id: 'new_journal' }));
} }
changePageSubtitle(
defaultToTransform(transactionNumber, `No. ${transactionNumber}`, ''),
);
}, [ }, [
changePageTitle, changePageTitle,
changePageSubtitle, changePageSubtitle,
@@ -383,7 +393,9 @@ function MakeJournalEntriesForm({
useEffect(() => { useEffect(() => {
if (journalNumberChanged) { if (journalNumberChanged) {
setFieldValue('journal_number', journalNumber); setFieldValue('journal_number', journalNumber);
changePageSubtitle(`No. ${journalNumber}`); changePageSubtitle(
defaultToTransform(journalNumber, `No. ${journalNumber}`, ''),
);
setJournalNumberChanged(false); setJournalNumberChanged(false);
} }
}, [ }, [
@@ -440,7 +452,9 @@ function MakeJournalEntriesForm({
// Handle journal number field change. // Handle journal number field change.
const handleJournalNumberChanged = useCallback( const handleJournalNumberChanged = useCallback(
(journalNumber) => { (journalNumber) => {
changePageSubtitle(`No. ${journalNumber}`); changePageSubtitle(
defaultToTransform(journalNumber, `No. ${journalNumber}`, '')
);
}, },
[changePageSubtitle], [changePageSubtitle],
); );

View File

@@ -345,6 +345,7 @@ function AccountFormDialogContent({
onAccountSelected={onChangeSubaccount} onAccountSelected={onChangeSubaccount}
defaultSelectText={<T id={'select_parent_account'} />} defaultSelectText={<T id={'select_parent_account'} />}
selectedAccountId={values.parent_account_id} selectedAccountId={values.parent_account_id}
popoverFill={true}
/> />
</FormGroup> </FormGroup>
</If> </If>

View File

@@ -49,7 +49,7 @@ function PaymentMadeActionsBar({
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
const handleClickNewPaymentMade = useCallback(() => { const handleClickNewPaymentMade = useCallback(() => {
history.push('/payment-made/new'); history.push('/payment-mades/new');
}, [history]); }, [history]);
// const filterDropdown = FilterDropdown({ // const filterDropdown = FilterDropdown({

View File

@@ -13,6 +13,7 @@ const Schema = Yup.object().shape({
.required() .required()
.label(formatMessage({ id: 'payment_account_' })), .label(formatMessage({ id: 'payment_account_' })),
payment_number: Yup.string() payment_number: Yup.string()
.nullable()
.max(DATATYPES_LENGTH.STRING) .max(DATATYPES_LENGTH.STRING)
.label(formatMessage({ id: 'payment_no_' })), .label(formatMessage({ id: 'payment_no_' })),
reference: Yup.string().min(1).max(DATATYPES_LENGTH.STRING).nullable(), reference: Yup.string().min(1).max(DATATYPES_LENGTH.STRING).nullable(),

View File

@@ -107,6 +107,7 @@ function PaymentMadeFormHeader({
defaultSelectText={ <T id={'select_vender_account'} /> } defaultSelectText={ <T id={'select_vender_account'} /> }
onContactSelected={onChangeSelect('vendor_id')} onContactSelected={onChangeSelect('vendor_id')}
disabled={!isNewMode} disabled={!isNewMode}
popoverFill={true}
/> />
</FormGroup> </FormGroup>

View File

@@ -31,7 +31,12 @@ import Dragzone from 'components/Dragzone';
import useMedia from 'hooks/useMedia'; import useMedia from 'hooks/useMedia';
import { ERROR } from 'common/errors'; import { ERROR } from 'common/errors';
import { compose, repeatValue, orderingLinesIndexes } from 'utils'; import {
compose,
repeatValue,
defaultToTransform,
orderingLinesIndexes,
} from 'utils';
const MIN_LINES_NUMBER = 4; const MIN_LINES_NUMBER = 4;
@@ -98,16 +103,20 @@ const EstimateForm = ({
: estimateNextNumber; : estimateNextNumber;
useEffect(() => { useEffect(() => {
if (estimate && estimate.id) { const transNumber = !isNewMode ? estimate.estimate_number : estimateNumber;
if (isNewMode) {
changePageTitle(formatMessage({ id: 'edit_estimate' })); changePageTitle(formatMessage({ id: 'edit_estimate' }));
changePageSubtitle(`No. ${estimate.estimate_number}`);
} else { } else {
changePageSubtitle(`No. ${estimateNumber}`);
changePageTitle(formatMessage({ id: 'new_estimate' })); changePageTitle(formatMessage({ id: 'new_estimate' }));
} }
changePageSubtitle(
defaultToTransform(estimateNumber, `No. ${transNumber}`, ''),
);
}, [ }, [
estimate, estimate,
estimateNumber, estimateNumber,
isNewMode,
formatMessage, formatMessage,
changePageTitle, changePageTitle,
changePageSubtitle, changePageSubtitle,
@@ -211,18 +220,26 @@ const EstimateForm = ({
const handleEstimateNumberChange = useCallback( const handleEstimateNumberChange = useCallback(
(estimateNumber) => { (estimateNumber) => {
changePageSubtitle(`No. ${estimateNumber}`); changePageSubtitle(
defaultToTransform(estimateNumber, `No. ${estimateNumber}`, ''),
);
}, },
[changePageSubtitle], [changePageSubtitle],
); );
const handleSubmitClick = useCallback((event) => { const handleSubmitClick = useCallback(
(event) => {
setSubmitPayload({ redirect: true }); setSubmitPayload({ redirect: true });
}, [setSubmitPayload]); },
[setSubmitPayload],
);
const handleCancelClick = useCallback((event) => { const handleCancelClick = useCallback(
(event) => {
history.goBack(); history.goBack();
}, [history]); },
[history],
);
return ( return (
<div className={classNames(CLASSES.PAGE_FORM, CLASSES.PAGE_FORM_ESTIMATE)}> <div className={classNames(CLASSES.PAGE_FORM, CLASSES.PAGE_FORM_ESTIMATE)}>
@@ -239,7 +256,7 @@ const EstimateForm = ({
onEstimateNumberChanged={handleEstimateNumberChange} onEstimateNumberChanged={handleEstimateNumberChange}
/> />
<EstimateNumberWatcher estimateNumber={estimateNumber} /> <EstimateNumberWatcher estimateNumber={estimateNumber} />
<EditableItemsEntriesTable /> <EditableItemsEntriesTable filterSellableItems={true} />
<EstimateFormFooter /> <EstimateFormFooter />
<EstimateFloatingActions <EstimateFloatingActions
isSubmiting={isSubmitting} isSubmiting={isSubmitting}

View File

@@ -66,6 +66,7 @@ function EstimateFormHeader({
onContactSelected={(customer) => { onContactSelected={(customer) => {
form.setFieldValue('customer_id', customer.id); form.setFieldValue('customer_id', customer.id);
}} }}
popoverFill={true}
/> />
</FormGroup> </FormGroup>
)} )}

View File

@@ -30,7 +30,12 @@ import { AppToaster } from 'components';
import useMedia from 'hooks/useMedia'; import useMedia from 'hooks/useMedia';
import { ERROR } from 'common/errors'; 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'; import { useHistory } from 'react-router-dom';
const MIN_LINES_NUMBER = 4; const MIN_LINES_NUMBER = 4;
@@ -94,13 +99,16 @@ function InvoiceForm({
: invoiceNextNumber; : invoiceNextNumber;
useEffect(() => { useEffect(() => {
const transactionNumber = invoice ? invoice.invoice_no : invoiceNumber;
if (invoice && invoice.id) { if (invoice && invoice.id) {
changePageTitle(formatMessage({ id: 'edit_invoice' })); changePageTitle(formatMessage({ id: 'edit_invoice' }));
changePageSubtitle(`No. ${invoice.invoice_no}`);
} else { } else {
changePageSubtitle(`No. ${invoiceNumber}`);
changePageTitle(formatMessage({ id: 'new_invoice' })); changePageTitle(formatMessage({ id: 'new_invoice' }));
} }
changePageSubtitle(
defaultToTransform(transactionNumber, `No. ${transactionNumber}`, ''),
);
}, [ }, [
changePageTitle, changePageTitle,
changePageSubtitle, changePageSubtitle,
@@ -216,7 +224,9 @@ function InvoiceForm({
const handleInvoiceNumberChanged = useCallback( const handleInvoiceNumberChanged = useCallback(
(invoiceNumber) => { (invoiceNumber) => {
changePageSubtitle(`No. ${invoiceNumber}`); changePageSubtitle(
defaultToTransform(invoiceNumber, `No. ${invoiceNumber}`, ''),
);
}, },
[changePageSubtitle], [changePageSubtitle],
); );
@@ -236,7 +246,10 @@ function InvoiceForm({
onInvoiceNumberChanged={handleInvoiceNumberChanged} onInvoiceNumberChanged={handleInvoiceNumberChanged}
/> />
<InvoiceNumberChangeWatcher invoiceNumber={invoiceNumber} /> <InvoiceNumberChangeWatcher invoiceNumber={invoiceNumber} />
<EditableItemsEntriesTable defaultEntry={defaultInvoice} /> <EditableItemsEntriesTable
defaultEntry={defaultInvoice}
filterSellableItems={true}
/>
<InvoiceFormFooter /> <InvoiceFormFooter />
<InvoiceFloatingActions <InvoiceFloatingActions
isSubmitting={isSubmitting} isSubmitting={isSubmitting}

View File

@@ -66,6 +66,7 @@ function InvoiceFormHeader({
onContactSelected={(customer) => { onContactSelected={(customer) => {
form.setFieldValue('customer_id', customer.id); form.setFieldValue('customer_id', customer.id);
}} }}
popoverFill={true}
/> />
</FormGroup> </FormGroup>
)} )}

View File

@@ -49,7 +49,7 @@ function PaymentReceiveActionsBar({
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
const handleClickNewPaymentReceive = useCallback(() => { const handleClickNewPaymentReceive = useCallback(() => {
history.push('/payment-receive/new'); history.push('/payment-receives/new');
}, [history]); }, [history]);
// const filterDropdown = FilterDropdown({ // const filterDropdown = FilterDropdown({

View File

@@ -1,18 +1,11 @@
import React, { import React, { useMemo, useCallback, useEffect, useState } from 'react';
useMemo,
useCallback,
useEffect,
useState,
useRef,
} from 'react';
import * as Yup from 'yup';
import { useFormik } from 'formik'; import { useFormik } from 'formik';
import moment from 'moment'; import moment from 'moment';
import { FormattedMessage as T, useIntl } from 'react-intl'; import { FormattedMessage as T, useIntl } from 'react-intl';
import { pick, sumBy, omit } from 'lodash'; import { pick, sumBy, omit } from 'lodash';
import { Intent, Alert } from '@blueprintjs/core'; import { Intent, Alert } from '@blueprintjs/core';
import classNames from 'classnames'; import classNames from 'classnames';
import { useHistory } from 'react-router-dom';
import { CLASSES } from 'common/classes'; import { CLASSES } from 'common/classes';
import PaymentReceiveHeader from './PaymentReceiveFormHeader'; import PaymentReceiveHeader from './PaymentReceiveFormHeader';
@@ -32,7 +25,7 @@ import {
} from './PaymentReceiveForm.schema'; } from './PaymentReceiveForm.schema';
import { AppToaster } from 'components'; import { AppToaster } from 'components';
import { compose } from 'utils'; import { compose, defaultToTransform } from 'utils';
/** /**
* Payment Receive form. * Payment Receive form.
@@ -62,35 +55,45 @@ function PaymentReceiveForm({
changePageTitle, changePageTitle,
changePageSubtitle, changePageSubtitle,
}) { }) {
const history = useHistory();
const [amountChangeAlert, setAmountChangeAlert] = useState(false); const [amountChangeAlert, setAmountChangeAlert] = useState(false);
const [clearLinesAlert, setClearLinesAlert] = useState(false); const [clearLinesAlert, setClearLinesAlert] = useState(false);
const [fullAmount, setFullAmount] = useState(null); const [fullAmount, setFullAmount] = useState(null);
const [clearFormAlert, setClearFormAlert] = useState(false); const [clearFormAlert, setClearFormAlert] = useState(false);
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
const isNewMode = !paymentReceiveId;
const [localPaymentEntries, setLocalPaymentEntries] = useState( const [localPaymentEntries, setLocalPaymentEntries] = useState(
paymentReceiveEntries, paymentReceiveEntries,
); );
const isNewMode = !paymentReceiveId;
const paymentReceiveNumber = paymentReceiveNumberPrefix const paymentReceiveNumber = paymentReceiveNumberPrefix
? `${paymentReceiveNumberPrefix}-${paymentReceiveNextNumber}` ? `${paymentReceiveNumberPrefix}-${paymentReceiveNextNumber}`
: paymentReceiveNextNumber; : paymentReceiveNextNumber;
useEffect(() => { useEffect(() => {
const transactionNumber = !isNewMode
? paymentReceive.payment_receive_no
: paymentReceiveNumber;
if (paymentReceive && paymentReceiveId) { if (paymentReceive && paymentReceiveId) {
changePageTitle(formatMessage({ id: 'edit_payment_receive' })); changePageTitle(formatMessage({ id: 'edit_payment_receive' }));
changePageSubtitle(`No. ${paymentReceive.payment_receive_no}`); changePageSubtitle(`No. ${paymentReceive.payment_receive_no}`);
} else { } else {
changePageSubtitle(`No. ${paymentReceiveNumber}`);
changePageTitle(formatMessage({ id: 'payment_receive' })); changePageTitle(formatMessage({ id: 'payment_receive' }));
} }
changePageSubtitle(
defaultToTransform(transactionNumber, `No. ${transactionNumber}`, ''),
);
}, [ }, [
isNewMode,
changePageTitle, changePageTitle,
changePageSubtitle, changePageSubtitle,
paymentReceive, paymentReceive,
paymentReceiveId, paymentReceiveId,
formatMessage, formatMessage,
paymentReceiveNumber,
]); ]);
useEffect(() => { useEffect(() => {
@@ -167,8 +170,8 @@ function PaymentReceiveForm({
AppToaster.show({ AppToaster.show({
message: formatMessage({ message: formatMessage({
id: 'you_cannot_make_payment_with_zero_total_amount', id: 'you_cannot_make_payment_with_zero_total_amount',
intent: Intent.WARNING,
}), }),
intent: Intent.DANGER,
}); });
setSubmitting(false); setSubmitting(false);
return; return;
@@ -180,13 +183,14 @@ function PaymentReceiveForm({
AppToaster.show({ AppToaster.show({
message: formatMessage({ message: formatMessage({
id: paymentReceiveId id: paymentReceiveId
? 'the_payment_has_been_received_successfully_edited' ? 'the_payment_receive_transaction_has_been_edited'
: 'the_payment_has_been_received_successfully_created', : 'the_payment_receive_transaction_has_been_created',
}), }),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
setSubmitting(false); setSubmitting(false);
resetForm(); resetForm();
history.push('/payment-receives');
}; };
// Handle request response errors. // Handle request response errors.
const onError = (errors) => { const onError = (errors) => {
@@ -321,7 +325,13 @@ function PaymentReceiveForm({
useEffect(() => { useEffect(() => {
if (paymentReceiveNumberChanged) { if (paymentReceiveNumberChanged) {
setFieldValue('payment_receive_no', paymentReceiveNumber); setFieldValue('payment_receive_no', paymentReceiveNumber);
changePageSubtitle(`No. ${paymentReceiveNumber}`); changePageSubtitle(
defaultToTransform(
paymentReceiveNumber,
`No. ${paymentReceiveNumber}`,
'',
),
);
setPaymentReceiveNumberChanged(false); setPaymentReceiveNumberChanged(false);
} }
}, [ }, [
@@ -329,11 +339,14 @@ function PaymentReceiveForm({
paymentReceiveNumberChanged, paymentReceiveNumberChanged,
setFieldValue, setFieldValue,
changePageSubtitle, changePageSubtitle,
setPaymentReceiveNumberChanged,
]); ]);
const handlePaymentReceiveNumberChanged = useCallback( const handlePaymentReceiveNumberChanged = useCallback(
(payment_receive_no) => { (payment_receive_no) => {
changePageSubtitle(`No.${payment_receive_no}`); changePageSubtitle(
defaultToTransform(payment_receive_no, `No.${payment_receive_no}`, ''),
);
}, },
[changePageSubtitle], [changePageSubtitle],
); );

View File

@@ -14,6 +14,7 @@ const Schema = Yup.object().shape({
.label(formatMessage({ id: 'deposit_account_' })), .label(formatMessage({ id: 'deposit_account_' })),
full_amount: Yup.number().nullable(), full_amount: Yup.number().nullable(),
payment_receive_no: Yup.string() payment_receive_no: Yup.string()
.nullable()
.max(DATATYPES_LENGTH.STRING) .max(DATATYPES_LENGTH.STRING)
.label(formatMessage({ id: 'payment_receive_no_' })), .label(formatMessage({ id: 'payment_receive_no_' })),
reference_no: Yup.string().min(1).max(DATATYPES_LENGTH.STRING).nullable(), reference_no: Yup.string().min(1).max(DATATYPES_LENGTH.STRING).nullable(),

View File

@@ -114,6 +114,7 @@ function PaymentReceiveFormHeader({
selectedContactId={values.customer_id} selectedContactId={values.customer_id}
defaultSelectText={<T id={'select_customer_account'} />} defaultSelectText={<T id={'select_customer_account'} />}
onContactSelected={onChangeSelect('customer_id')} onContactSelected={onChangeSelect('customer_id')}
popoverFill={true}
/> />
</FormGroup> </FormGroup>

View File

@@ -21,7 +21,7 @@ export default function PaymentReceivesEmptyStatus() {
intent={Intent.PRIMARY} intent={Intent.PRIMARY}
large={true} large={true}
onClick={() => { onClick={() => {
history.push('/payment-receive/new'); history.push('/payment-receives/new');
}} }}
> >
New payment receive New payment receive

View File

@@ -32,7 +32,12 @@ import { AppToaster } from 'components';
import Dragzone from 'components/Dragzone'; import Dragzone from 'components/Dragzone';
import useMedia from 'hooks/useMedia'; import useMedia from 'hooks/useMedia';
import { compose, repeatValue, orderingLinesIndexes } from 'utils'; import {
compose,
repeatValue,
orderingLinesIndexes,
defaultToTransform,
} from 'utils';
const MIN_LINES_NUMBER = 4; const MIN_LINES_NUMBER = 4;
@@ -97,14 +102,20 @@ function ReceiptForm({
: receiptNextNumber; : receiptNextNumber;
useEffect(() => { useEffect(() => {
const transactionNumber = !isNewMode
? receipt.receipt_number
: receiptNumber;
if (receipt && receipt.id) { if (receipt && receipt.id) {
changePageTitle(formatMessage({ id: 'edit_receipt' })); changePageTitle(formatMessage({ id: 'edit_receipt' }));
changePageSubtitle(`No. ${receipt.receipt_number}`);
} else { } else {
changePageSubtitle(`No. ${receiptNumber}`);
changePageTitle(formatMessage({ id: 'new_receipt' })); changePageTitle(formatMessage({ id: 'new_receipt' }));
} }
changePageSubtitle(
defaultToTransform(transactionNumber, `No. ${transactionNumber}`, ''),
);
}, [ }, [
isNewMode,
changePageTitle, changePageTitle,
changePageSubtitle, changePageSubtitle,
receipt, receipt,
@@ -213,7 +224,9 @@ function ReceiptForm({
const handleReceiptNumberChanged = useCallback( const handleReceiptNumberChanged = useCallback(
(receiptNumber) => { (receiptNumber) => {
changePageSubtitle(`No. ${receiptNumber}`); changePageSubtitle(
defaultToTransform(receiptNumber, `No. ${receiptNumber}`, ''),
);
}, },
[changePageSubtitle], [changePageSubtitle],
); );
@@ -244,7 +257,7 @@ function ReceiptForm({
onReceiptNumberChanged={handleReceiptNumberChanged} onReceiptNumberChanged={handleReceiptNumberChanged}
/> />
<ReceiptNumberWatcher receiptNumber={receiptNumber} /> <ReceiptNumberWatcher receiptNumber={receiptNumber} />
<EditableItemsEntriesTable /> <EditableItemsEntriesTable filterSellableItems={true} />
<ReceiptFormFooter /> <ReceiptFormFooter />
<ReceiptFormFloatingActions <ReceiptFormFloatingActions
receiptId={receiptId} receiptId={receiptId}

View File

@@ -76,6 +76,7 @@ function ReceiptFormHeader({
onContactSelected={(contact) => { onContactSelected={(contact) => {
form.setFieldValue('customer_id', contact.id); form.setFieldValue('customer_id', contact.id);
}} }}
popoverFill={true}
/> />
</FormGroup> </FormGroup>
)} )}
@@ -103,6 +104,7 @@ function ReceiptFormHeader({
defaultSelectText={<T id={'select_deposit_account'} />} defaultSelectText={<T id={'select_deposit_account'} />}
selectedAccountId={value} selectedAccountId={value}
filterByTypes={['current_asset']} filterByTypes={['current_asset']}
popoverFill={true}
/> />
</FormGroup> </FormGroup>
)} )}

View File

@@ -91,7 +91,6 @@ export default {
count: 'Count', count: 'Count',
item_type: 'Item Type', item_type: 'Item Type',
item_name: 'Item Name', item_name: 'Item Name',
sku: 'SKU',
category: 'Category', category: 'Category',
account: 'Account', account: 'Account',
sales_information: 'Sales Information', sales_information: 'Sales Information',
@@ -689,12 +688,12 @@ export default {
payment_receive_no_: 'Payment receive no', payment_receive_no_: 'Payment receive no',
receive_amount: 'Receive Amount', receive_amount: 'Receive Amount',
receive_amount_: 'Receive amount', receive_amount_: 'Receive amount',
the_payment_has_been_received_successfully_created: the_payment_receive_transaction_has_been_created:
'The payment has been received successfully 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 receive has been successfully deleted.', 'The payment receive has been successfully deleted.',
the_payment_has_been_received_successfully_edited: the_payment_receive_transaction_has_been_edited:
'The payment has been received successfully 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?`, 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', select_invoice: 'Select Invoice',
payment_mades: 'Payment Mades', payment_mades: 'Payment Mades',
@@ -841,4 +840,6 @@ export default {
once_delete_these_vendors_you_will_not_able_restore_them: 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?", "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', 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',
}; };

View File

@@ -89,13 +89,17 @@ $sidebar-submenu-item-bg-color: #01287d;
margin-top: 3px; margin-top: 3px;
color: rgba(255, 255, 255, 0.25); color: rgba(255, 255, 255, 0.25);
} }
&-label{ &-labeler{
display: block; display: block;
color: $sidebar-menu-label-color; color: $sidebar-menu-label-color;
font-size: 12px; font-size: 12px;
padding: 6px 16px; padding: 6px 16px;
margin-top: 4px; margin-top: 4px;
} }
&:hover .bp3-button.menu-item__add-btn{
display: inline-block;
}
} }
.#{$ns}-submenu { .#{$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;
}
}
} }

View File

@@ -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"; import BaseController from "api/controllers/BaseController";
export default class ContactsController extends BaseController { export default class ContactsController extends BaseController {
@@ -48,7 +48,8 @@ export default class ContactsController extends BaseController {
*/ */
get contactNewDTOSchema(): ValidationChain[] { get contactNewDTOSchema(): ValidationChain[] {
return [ return [
check('balance').optional().isNumeric().toInt(), check('opening_balance').optional({ nullable: true }).isNumeric().toInt(),
body('opening_balance_at').if(body('opening_balance').exists()).exists(),
]; ];
} }

View File

@@ -90,9 +90,6 @@ export default class CustomersController extends ContactsController {
*/ */
get createCustomerDTOSchema() { get createCustomerDTOSchema() {
return [ return [
check('opening_balance').optional({ nullable: true }).isNumeric().toInt(),
check('opening_balance_at').optional({ nullable: true }).isISO8601(),
check('currency_code').optional().trim().escape(), check('currency_code').optional().trim().escape(),
]; ];
} }

View File

@@ -1,6 +1,7 @@
import { Request, Response, Router, NextFunction } from 'express'; import { Request, Response, Router, NextFunction } from 'express';
import { Service, Inject } from 'typedi'; 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 ContactsController from 'api/controllers/Contacts/Contacts';
import VendorsService from 'services/Contacts/VendorsService'; import VendorsService from 'services/Contacts/VendorsService';
import { ServiceError } from 'exceptions'; import { ServiceError } from 'exceptions';
@@ -72,7 +73,7 @@ export default class VendorsController extends ContactsController {
*/ */
get vendorDTOSchema(): ValidationChain[] { get vendorDTOSchema(): ValidationChain[] {
return [ return [
check('opening_balance').optional().isNumeric().toInt(), check('currency_code').optional().trim().escape(),
]; ];
} }
@@ -105,7 +106,11 @@ export default class VendorsController extends ContactsController {
try { try {
const vendor = await this.vendorsService.newVendor(tenantId, contactDTO); 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) { } catch (error) {
next(error); next(error);
} }
@@ -124,7 +129,11 @@ export default class VendorsController extends ContactsController {
try { try {
await this.vendorsService.editVendor(tenantId, contactId, contactDTO); 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) { } catch (error) {
next(error); next(error);
} }
@@ -142,7 +151,11 @@ export default class VendorsController extends ContactsController {
try { try {
await this.vendorsService.deleteVendor(tenantId, contactId) 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) { } catch (error) {
next(error); next(error);
} }
@@ -198,7 +211,11 @@ export default class VendorsController extends ContactsController {
}; };
try { 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({ return res.status(200).send({
vendors, vendors,
@@ -219,21 +236,27 @@ export default class VendorsController extends ContactsController {
*/ */
handlerServiceErrors(error, req: Request, res: Response, next: NextFunction) { handlerServiceErrors(error, req: Request, res: Response, next: NextFunction) {
if (error instanceof ServiceError) { 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') { if (error.errorType === 'contacts_not_found') {
return res.boom.badRequest(null, { 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') { if (error.errorType === 'some_vendors_have_bills') {
return res.boom.badRequest(null, { 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') { if (error.errorType === 'vendor_has_bills') {
return res.status(400).send({ return res.status(400).send({
errors: [{ type: 'VENDOR.HAS.BILLS', code: 200 }], errors: [{ type: 'VENDOR.HAS.BILLS', code: 400 }],
}); });
} }
} }
next(error);
} }
} }

View File

@@ -84,7 +84,7 @@ export default class PaymentReceivesController extends BaseController {
check('payment_date').exists(), check('payment_date').exists(),
check('reference_no').optional(), check('reference_no').optional(),
check('deposit_account_id').exists().isNumeric().toInt(), 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('statement').optional().trim().escape(),
check('entries').isArray({ min: 1 }), check('entries').isArray({ min: 1 }),

View File

@@ -1,5 +1,5 @@
import { Inject, Service } from 'typedi'; import { Inject, Service } from 'typedi';
import { omit, difference } from 'lodash'; import { omit, difference, defaultTo } from 'lodash';
import { import {
EventDispatcher, EventDispatcher,
EventDispatcherInterface, EventDispatcherInterface,
@@ -51,8 +51,7 @@ export default class CustomersService {
return { return {
...omit(customerDTO, ['customerType']), ...omit(customerDTO, ['customerType']),
contactType: customerDTO.customerType, contactType: customerDTO.customerType,
active: (typeof customerDTO.active === 'undefined') ? active: defaultTo(customerDTO.active, true),
true : customerDTO.active,
}; };
} }

View File

@@ -1,5 +1,5 @@
import { Inject, Service } from 'typedi'; import { Inject, Service } from 'typedi';
import { difference, rest } from 'lodash'; import { difference, defaultTo } from 'lodash';
import { import {
EventDispatcher, EventDispatcher,
EventDispatcherInterface, EventDispatcherInterface,
@@ -45,8 +45,7 @@ export default class VendorsService {
private vendorToContactDTO(vendorDTO: IVendorNewDTO|IVendorEditDTO) { private vendorToContactDTO(vendorDTO: IVendorNewDTO|IVendorEditDTO) {
return { return {
...vendorDTO, ...vendorDTO,
active: (typeof vendorDTO.active === 'undefined') ? active: defaultTo(vendorDTO.active, true),
true : vendorDTO.active,
}; };
} }
@@ -62,6 +61,7 @@ export default class VendorsService {
const contactDTO = this.vendorToContactDTO(vendorDTO); const contactDTO = this.vendorToContactDTO(vendorDTO);
const vendor = await this.contactService.newContact(tenantId, contactDTO, 'vendor'); const vendor = await this.contactService.newContact(tenantId, contactDTO, 'vendor');
// Triggers `onVendorCreated` event.
await this.eventDispatcher.dispatch(events.vendors.onCreated, { await this.eventDispatcher.dispatch(events.vendors.onCreated, {
tenantId, vendorId: vendor.id, vendor, tenantId, vendorId: vendor.id, vendor,
}); });