@@ -165,7 +141,7 @@ function ExpenseFormHeader({
}
>
}
selectedAccountId={values.payment_account_id}
diff --git a/client/src/containers/Expenses/ExpenseTable.js b/client/src/containers/Expenses/ExpenseTable.js
index 5427b1d58..213f45602 100644
--- a/client/src/containers/Expenses/ExpenseTable.js
+++ b/client/src/containers/Expenses/ExpenseTable.js
@@ -14,7 +14,6 @@ import {
} from 'components/DataTableCells';
import withAccounts from 'containers/Accounts/withAccounts';
-
const ExpenseCategoryHeaderCell = () => {
return (
<>
@@ -22,10 +21,10 @@ const ExpenseCategoryHeaderCell = () => {
>
);
-}
+};
- // Actions cell renderer.
- const ActionsCellRenderer = ({
+// Actions cell renderer.
+const ActionsCellRenderer = ({
row: { index },
column: { id },
cell: { value: initialValue },
@@ -101,16 +100,11 @@ function ExpenseTable({
const { formatMessage } = useIntl();
useEffect(() => {
- setRows([
- ...categories.map((e) => ({ ...e, rowType: 'editor' })),
- ]);
+ setRows([...categories.map((e) => ({ ...e, rowType: 'editor' }))]);
}, [categories]);
// Final table rows editor rows and total and final blank row.
- const tableRows = useMemo(
- () => [...rows, { rowType: 'total' }],
- [rows],
- );
+ const tableRows = useMemo(() => [...rows, { rowType: 'total' }], [rows]);
// Memorized data table columns.
const columns = useMemo(
@@ -133,6 +127,7 @@ function ExpenseTable({
disableSortBy: true,
disableResizing: true,
width: 250,
+ accountsDataProp: 'expenseAccounts',
},
{
Header: formatMessage({ id: 'amount_currency' }, { currency: 'USD' }),
@@ -187,6 +182,11 @@ function ExpenseTable({
// Handles click remove datatable row.
const handleRemoveRow = useCallback(
(rowIndex) => {
+ // Can't continue if there is just one row line or less.
+ if (rows.length <= 1) {
+ return;
+ }
+
const removeIndex = parseInt(rowIndex, 10);
const newRows = rows.filter((row, index) => index !== removeIndex);
@@ -220,6 +220,12 @@ function ExpenseTable({
[rows],
);
+ // Filter expense accounts.
+ const expenseAccounts = useMemo(
+ () => accountsList.filter((a) => a?.type?.root_type === 'expense'),
+ [accountsList],
+ );
+
return (
{
AppToaster.show({
message: formatMessage(
- { id: 'the_expenses_has_been_successfully_deleted' },
+ { id: 'the_expenses_have_been_successfully_deleted' },
{ count: selectedRowsCount },
),
intent: Intent.SUCCESS,
@@ -160,6 +160,7 @@ function ExpensesList({
requestPublishExpense(expense.id).then(() => {
AppToaster.show({
message: formatMessage({ id: 'the_expense_id_has_been_published' }),
+ intent: Intent.SUCCESS,
});
});
fetchExpenses.refetch();
diff --git a/client/src/containers/Expenses/withExpenseDetail.js b/client/src/containers/Expenses/withExpenseDetail.js
index 85d9fc769..639be0b49 100644
--- a/client/src/containers/Expenses/withExpenseDetail.js
+++ b/client/src/containers/Expenses/withExpenseDetail.js
@@ -5,7 +5,7 @@ export default () => {
const getExpenseById = getExpenseByIdFactory();
const mapStateToProps = (state, props) => ({
- expenseDetail: getExpenseById(state, props),
+ expense: getExpenseById(state, props),
});
return connect(mapStateToProps);
};
\ No newline at end of file
diff --git a/client/src/lang/en/index.js b/client/src/lang/en/index.js
index e18d6f72b..ec14c1435 100644
--- a/client/src/lang/en/index.js
+++ b/client/src/lang/en/index.js
@@ -436,11 +436,10 @@ export default {
'The expense #{number} has been successfully edited.',
the_expense_has_been_successfully_deleted:
'The expense has been successfully deleted',
- the_expenses_has_been_successfully_deleted:
- 'The expenses has been successfully deleted',
+ the_expenses_have_been_successfully_deleted:
+ 'The expenses #{number} have been successfully deleted',
once_delete_these_expenses_you_will_not_able_restore_them:
"Once you delete these expenses, you won't be able to retrieve them later. Are you sure you want to delete them?",
-
the_expense_id_has_been_published: 'The expense id has been published',
select_beneficiary_account: 'Select Beneficiary Account',
total_amount_equals_zero: 'Total amount equals zero',
@@ -529,4 +528,13 @@ export default {
logic_expression: 'logic expression',
assign_to_customer: 'Assign to Customer',
inactive: 'Inactive',
+ should_select_customers_with_entries_have_receivable_account: 'Should select customers with entries that have receivable account.',
+ should_select_vendors_with_entries_have_payable_account: 'Should select vendors with entries that have payable account.',
+ vendors_should_selected_with_payable_account_only: 'Vendors contacts should selected with payable account only.',
+ customers_should_selected_with_receivable_account_only: 'Customers contacts should selected with receivable account only.',
+ amount_cannot_be_zero_or_empty: 'Amount cannot be zero or empty.',
+ should_total_of_credit_and_debit_be_equal: 'Should total of credit and debit be equal.',
+ no_accounts: 'No Accounts',
+ the_accounts_have_been_successfully_inactivated: 'The accounts have been successfully inactivated.',
+ account_code_is_not_unique: 'Account code is not unqiue.'
};
diff --git a/client/src/services/yup.js b/client/src/services/yup.js
new file mode 100644
index 000000000..ec84ca0bd
--- /dev/null
+++ b/client/src/services/yup.js
@@ -0,0 +1,23 @@
+import * as Yup from 'yup';
+
+
+Yup.addMethod(Yup.string, 'digits', function () {
+ return this.test(
+ 'is-digits',
+ '${path} should be digits only.',
+ value => /^(0|[1-9]\d*)$/.test(value),
+ );
+});
+
+Yup.addMethod(Yup.number, 'decimalScale', function(scale) {
+ return this.test(
+ 'numeric-length',
+ '${path} should decimal length ',
+ (value) => {
+ const reg = new RegExp(/^(?:\d{1,13}|(?!.{15})\d+\.\d+)$/);
+ return reg.test(value);
+ },
+ );
+})
+
+export default Yup;
diff --git a/client/src/store/accounts/accounts.actions.js b/client/src/store/accounts/accounts.actions.js
index 87565f9b9..b4e470207 100644
--- a/client/src/store/accounts/accounts.actions.js
+++ b/client/src/store/accounts/accounts.actions.js
@@ -262,7 +262,9 @@ export const fetchAccount = ({ id }) => {
.then((response) => {
dispatch({
type: t.ACCOUNT_SET,
- account: response.data.account,
+ payload: {
+ account: response.data.account,
+ }
});
resolve(response);
})
diff --git a/client/src/store/accounts/accounts.reducer.js b/client/src/store/accounts/accounts.reducer.js
index 123cc43ac..e0e75d336 100644
--- a/client/src/store/accounts/accounts.reducer.js
+++ b/client/src/store/accounts/accounts.reducer.js
@@ -51,7 +51,11 @@ const accountsReducer = createReducer(initialState, {
},
[t.ACCOUNT_SET]: (state, action) => {
- state.accountsById[action.account.id] = action.account;
+ const { account } = action.payload;
+ state.items[account.id] = {
+ ...(state.items[account.id] || {}),
+ ...account,
+ };
},
[t.ACCOUNT_DELETE]: (state, action) => {
diff --git a/client/src/store/expenses/expenses.reducer.js b/client/src/store/expenses/expenses.reducer.js
index 51da45385..3df7c9ef1 100644
--- a/client/src/store/expenses/expenses.reducer.js
+++ b/client/src/store/expenses/expenses.reducer.js
@@ -8,7 +8,7 @@ const initialState = {
views: {},
loading: false,
tableQuery: {
- page_size: 4,
+ page_size: 12,
page: 1,
},
currentViewId: -1,
diff --git a/client/src/style/objects/form.scss b/client/src/style/objects/form.scss
index 87a70ea9e..65b5e8134 100644
--- a/client/src/style/objects/form.scss
+++ b/client/src/style/objects/form.scss
@@ -7,8 +7,7 @@ $form-check-input-indeterminate-bg-image: url("data:image/svg+xml,