This commit is contained in:
Ahmed Bouhuolia
2020-03-21 23:32:04 +02:00
parent ace43ed830
commit b5f94e9a8b
17 changed files with 780 additions and 188 deletions

View File

@@ -120,6 +120,10 @@ export default [
text: 'Trial Balance Sheet',
href: '/dashboard/accounting/trial-balance-sheet',
},
{
text: 'Journal',
href: '/dashboard/accounting/journal-sheet',
},
{
divider: true,
},

View File

@@ -0,0 +1,19 @@
import {connect} from 'react-redux';
import {
fetchJournalSheet
} from 'store/financialStatement/financialStatements.actions';
import {
getFinancialSheetIndexByQuery,
getFinancialSheet,
} from 'store/financialStatement/financialStatements.selectors';
export const mapStateToProps = (state, props) => ({
getJournalSheetIndex: (query) => getFinancialSheetIndexByQuery(state.financialStatements.journalSheets, query),
getJournalSheet: (index) => getFinancialSheet(state.financialStatements.journalSheets, index),
});
export const mapDispatchToProps = (dispatch) => ({
fetchJournalSheet: (query) => dispatch(fetchJournalSheet({ query })),
});
export default connect(mapStateToProps, mapDispatchToProps);

View File

@@ -78,16 +78,12 @@ function BalanceSheetTable({
}
},
}))),
], [balanceSheetColumns]);
], [balanceSheetColumns, balanceSheetQuery]);
const [data, setData] = useState([]);
useEffect(() => {
if (!balanceSheet) { return; }
setData([
{
name: 'Assets',
@@ -106,9 +102,6 @@ function BalanceSheetTable({
])
}, [])
// if (balanceSheets.length > 0) {
// setData(balanceSheets[0].balance_sheet);
// }
return (
<FinancialSheet
companyTitle={'Facebook, Incopration'}

View File

@@ -0,0 +1,72 @@
import React, {useState, useEffect, useMemo} from 'react';
import {compose} from 'utils';
import LoadingIndicator from 'components/LoadingIndicator';
import JournalConnect from 'connectors/Journal.connect';
import JournalHeader from 'containers/Dashboard/FinancialStatements/Journal/JournalHeader';
import useAsync from 'hooks/async';
import {useIntl} from 'react-intl';
import moment from 'moment';
import JournalTable from './JournalTable';
import DashboardConnect from 'connectors/Dashboard.connector';
function Journal({
fetchJournalSheet,
getJournalSheet,
getJournalSheetIndex,
changePageTitle,
}) {
const [filter, setFilter] = useState({
from_date: moment().startOf('year').format('YYYY-MM-DD'),
to_date: moment().endOf('year').format('YYYY-MM-DD'),
});
const [reload, setReload] = useState(false);
const fetchHook = useAsync(async () => {
await Promise.all([
fetchJournalSheet(filter),
]);
setReload(false);
});
useEffect(() => {
changePageTitle('Journal');
}, []);
useEffect(() => {
if (reload) {
fetchHook.execute();
}
}, [reload, fetchHook]);
const journalSheetIndex = useMemo(() => {
return getJournalSheetIndex(filter);
}, [filter, getJournalSheetIndex]);
const handleFilterSubmit = (filter) => {
setFilter({
...filter,
from_date: moment(filter.from_date).format('YYYY-MM-DD'),
to_date: moment(filter.to_date).format('YYYY-MM-DD'),
});
setReload(true);
};
return (
<div class="financial-statement">
<JournalHeader
pageFilter={filter}
onSubmitFilter={handleFilterSubmit} />
<div class="financial-statement__body">
<LoadingIndicator loading={fetchHook.pending}>
<JournalTable
journalIndex={journalSheetIndex} />
</LoadingIndicator>
</div>
</div>
)
}
export default compose(
JournalConnect,
DashboardConnect,
)(Journal);

View File

@@ -0,0 +1,120 @@
import React, {useState, useMemo, useEffect} from 'react';
import FinancialStatementHeader from 'containers/Dashboard/FinancialStatements/FinancialStatementHeader';
import {Row, Col} from 'react-grid-system';
import {
Button,
FormGroup,
Position,
HTMLSelect,
Intent,
} from '@blueprintjs/core';
import {DateInput} from '@blueprintjs/datetime';
import moment from 'moment';
import {
momentFormatter,
parseDateRangeQuery,
} from 'utils';
import {useIntl} from 'react-intl';
export default function JournalHeader({
pageFilter,
onSubmitFilter,
}) {
const intl = useIntl();
const [filter, setFilter] = useState({
...pageFilter,
from_date: moment(pageFilter.from_date).toDate(),
to_date: moment(pageFilter.to_date).toDate()
});
const setFilterByKey = (name, value) => {
setFilter({ ...filter, [name]: value });
};
const [reportDateRange, setReportDateRange] = useState('this_year');
const dateRangeOptions = [
{value: 'today', label: 'Today', },
{value: 'this_week', label: 'This Week'},
{value: 'this_month', label: 'This Month'},
{value: 'this_quarter', label: 'This Quarter'},
{value: 'this_year', label: 'This Year'},
{value: 'custom', label: 'Custom Range'},
];
const handleDateChange = (name) => (date) => {
setReportDateRange('custom');
setFilterByKey(name, date);
};
useEffect(() => {
if (reportDateRange === 'custom') { return; }
const dateRange = parseDateRangeQuery(reportDateRange);
if (dateRange) {
setFilter((filter) => ({ ...filter, ...dateRange }));
}
}, [reportDateRange]);
const handleSubmitClick = () => { onSubmitFilter(filter); };
return (
<FinancialStatementHeader>
<Row>
<Col sm={3}>
<FormGroup
label={intl.formatMessage({'id': 'report_date_range'})}
minimal={true}
fill={true}>
<HTMLSelect
fill={true}
options={dateRangeOptions}
value={reportDateRange}
onChange={(event) => setReportDateRange(event.target.value)} />
</FormGroup>
</Col>
<Col sm={3}>
<FormGroup
label={intl.formatMessage({'id': 'from_date'})}
minimal={true}
fill={true}>
<DateInput
{...momentFormatter('YYYY/MM/DD')}
value={filter.from_date}
onChange={handleDateChange('from_date')}
popoverProps={{ position: Position.BOTTOM }}
fill={true} />
</FormGroup>
</Col>
<Col sm={3}>
<FormGroup
label={intl.formatMessage({'id': 'to_date'})}
minimal={true}
fill={true}>
<DateInput
{...momentFormatter('YYYY/MM/DD')}
value={filter.to_date}
onChange={handleDateChange('to_date')}
popoverProps={{ position: Position.BOTTOM }}
fill={true} />
</FormGroup>
</Col>
</Row>
<Row>
<Col sm={3}>
<Button
intent={Intent.PRIMARY}
type="submit"
onClick={handleSubmitClick}>
{ 'Run Report' }
</Button>
</Col>
</Row>
</FinancialStatementHeader>
);
}

View File

@@ -0,0 +1,89 @@
import React, {useState, useEffect, useMemo} from 'react';
import FinancialSheet from 'components/FinancialSheet';
import DataTable from 'components/DataTable';
import {compose} from 'utils';
import moment from 'moment';
import JournalConnect from 'connectors/Journal.connect';
import {
getFinancialSheet,
} from 'store/financialStatement/financialStatements.selectors';
import {connect} from 'react-redux';
function JournalSheetTable({
journalIndex,
journalTableData,
}) {
const columns = useMemo(() => [
{
Header: 'Date',
accessor: r => moment(r.date).format('YYYY/MM/DD'),
className: 'date',
},
{
Header: 'Account Name',
accessor: 'account.name',
},
{
Header: 'Transaction Type',
accessor: 'transaction_type',
className: "transaction_type",
},
{
Header: 'Num.',
accessor: 'reference_id',
className: 'reference_id',
},
{
Header: 'Note',
accessor: 'note',
},
{
Header: 'Credit',
accessor: 'credit',
},
{
Header: 'Debit',
accessor: 'debit',
},
], []);
return (
<FinancialSheet
companyTitle={'Facebook, Incopration'}
sheetType={'Balance Sheet'}
date={[]}>
<DataTable
columns={columns}
data={journalTableData} />
</FinancialSheet>
);
}
const mapStateToProps = (state, props) => {
const journalTableData = [];
const journalSheet = getFinancialSheet(state.financialStatements.journalSheets, props.journalIndex);
if (journalSheet && journalSheet.journal) {
journalSheet.journal.forEach((journal) => {
journal.entries.forEach((entry, index) => {
journalTableData.push({ ...entry, index });
});
journalTableData.push({
credit: journal.credit,
debit: journal.debit,
total: true,
})
})
}
return {
journalSheet,
journalTableData,
}
}
export default compose(
connect(mapStateToProps),
JournalConnect,
)(JournalSheetTable);

View File

@@ -95,5 +95,12 @@ export default [
component: LazyLoader({
loader: () => import('containers/Dashboard/FinancialStatements/ProfitLossSheet/ProfitLossSheet')
}),
}
},
{
path: `${BASE_URL}/accounting/journal-sheet`,
name: 'dashboard.accounting.journal.sheet',
component: LazyLoader({
loader: () => import('containers/Dashboard/FinancialStatements/Journal/Journal')
}),
},
];

View File

@@ -3,7 +3,7 @@ import t from 'store/types';
export const fetchGeneralLedger = ({ query }) => {
return (dispatch) => new Promise((resolve, reject) => {
ApiService.get('/financial_statements/general_ledger').then((response) => {
ApiService.get('/financial_statements/general_ledger', { params: query }).then((response) => {
dispatch({
type: t.GENERAL_LEDGER_STATEMENT_SET,
data: response.data,
@@ -28,7 +28,7 @@ export const fetchBalanceSheet = ({ query }) => {
export const fetchTrialBalanceSheet = ({ query }) => {
return (dispatch) => new Promise((resolve, reject) => {
ApiService.get('/financial_statements/trial_balance_sheet').then((response) => {
ApiService.get('/financial_statements/trial_balance_sheet', { params: query }).then((response) => {
dispatch({
type: t.TRAIL_BALANCE_STATEMENT_SET,
data: response.data,
@@ -40,7 +40,7 @@ export const fetchTrialBalanceSheet = ({ query }) => {
export const fetchProfitLossSheet = ({ query }) => {
return (dispatch) => new Promise((resolve, reject) => {
ApiService.get('/financial_statements/profit_loss_sheet').then((response) => {
ApiService.get('/financial_statements/profit_loss_sheet', { params: query }).then((response) => {
dispatch({
type: t.PROFIT_LOSS_STATEMENT_SET,
data: response.data,
@@ -48,4 +48,17 @@ export const fetchProfitLossSheet = ({ query }) => {
resolve(response.data);
}).catch((error) => { reject(error); });
})
};
export const fetchJournalSheet = ({ query }) => {
return (dispatch) => new Promise((resolve, reject) => {
ApiService.get('/financial_statements/journal', { params: query }).then((response) => {
dispatch({
type: t.JOURNAL_SHEET_SET,
data: response.data,
query: response.data.query,
});
resolve(response.data);
}).catch(error => { reject(error); });
});
};

View File

@@ -1,12 +1,16 @@
import { createReducer } from '@reduxjs/toolkit';
import t from 'store/types';
import {getBalanceSheetIndexByQuery, getTrialBalanceSheetIndex} from './financialStatements.selectors';
import { actionComplete } from '@syncfusion/ej2-react-grids';
import {
getBalanceSheetIndexByQuery,
getTrialBalanceSheetIndex,
getFinancialSheetIndexByQuery,
} from './financialStatements.selectors';
const initialState = {
balanceSheets: [],
trialBalanceSheets: [],
generalLedger: [],
journalSheets: [],
};
export default createReducer(initialState, {
@@ -37,5 +41,20 @@ export default createReducer(initialState, {
} else {
state.trailBalanceSheet.push(trailBalanceSheet);
}
},
[t.JOURNAL_SHEET_SET]: (state, action) => {
const index = getFinancialSheetIndexByQuery(state.journalSheets, action.query);
console.log(index, 'INDEX');
const journal = {
query: action.data.query,
journal: action.data.journal,
};
if (index !== -1) {
state.journalSheets[index] = journal;
} else {
state.journalSheets.push(journal);
}
}
});

View File

@@ -1,6 +1,49 @@
import {getObjectDiff} from 'utils';
// Financial Statements selectors.
/**
* Retrieve financial statement sheet by the given query.
* @param {array} sheets
* @param {object} query
*/
export const getFinancialSheetIndexByQuery = (sheets, query) => {
return sheets.findIndex(balanceSheet => (
getObjectDiff(query, balanceSheet.query).length === 0
));
};
/**
* Retrieve financial statement sheet by the given sheet index.
* @param {array} sheets
* @param {number} index
*/
export const getFinancialSheet = (sheets, index) => {
return (typeof sheets[index] !== 'undefined') ? sheets[index] : null;
};
/**
* Retrieve financial statement columns by the given sheet index.
* @param {array} sheets
* @param {number} index
*/
export const getFinancialSheetColumns = (sheets, index) => {
const sheet = getFinancialSheet(sheets, index);
return (sheet && sheet.columns) ? sheet.columns : [];
};
/**
* Retrieve financial statement query by the given sheet index.
* @param {array} sheets
* @param {number} index
*/
export const getFinancialSheetsQuery = (sheets, index) => {
const sheet = getFinancialSheet(sheets, index);
return (sheet && sheet.query) ? sheet.columns : {};
};
// Balance Sheet.
export const getBalanceSheetByQuery = (balanceSheets, query) => {
return balanceSheets.find(balanceSheet => {

View File

@@ -4,4 +4,5 @@ export default {
GENERAL_LEDGER_STATEMENT_SET: 'GENERAL_LEDGER_STATEMENT_SET',
BALANCE_SHEET_STATEMENT_SET: 'BALANCE_SHEET_STATEMENT_SET',
TRAIL_BALANCE_STATEMENT_SET: 'TRAIL_BALANCE_STATEMENT_SET',
JOURNAL_SHEET_SET: 'JOURNAL_SHEET_SET',
}