mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-16 12:50:38 +00:00
Merge pull request #112 from bigcapitalhq/BIG-417-fcy-bcy-cashflow-accounts-transactions-api
Add FCY/BCY transactions to the account drawer.
This commit is contained in:
@@ -177,7 +177,7 @@ export default class ItemsController extends BaseController {
|
||||
/**
|
||||
* Validate list query schema.
|
||||
*/
|
||||
get validateListQuerySchema() {
|
||||
private get validateListQuerySchema() {
|
||||
return [
|
||||
query('column_sort_by').optional().trim().escape(),
|
||||
query('sort_order').optional().isIn(['desc', 'asc']),
|
||||
@@ -193,32 +193,20 @@ export default class ItemsController extends BaseController {
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate autocomplete list query schema.
|
||||
*/
|
||||
get autocompleteQuerySchema() {
|
||||
return [
|
||||
query('column_sort_by').optional().trim().escape(),
|
||||
query('sort_order').optional().isIn(['desc', 'asc']),
|
||||
|
||||
query('stringified_filter_roles').optional().isJSON(),
|
||||
query('limit').optional().isNumeric().toInt(),
|
||||
|
||||
query('keyword').optional().isString().trim().escape(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the given item details to the storage.
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
*/
|
||||
async newItem(req: Request, res: Response, next: NextFunction) {
|
||||
private async newItem(req: Request, res: Response, next: NextFunction) {
|
||||
const { tenantId } = req;
|
||||
const itemDTO: IItemDTO = this.matchedBodyData(req);
|
||||
|
||||
try {
|
||||
const storedItem = await this.itemsApplication.createItem(tenantId, itemDTO);
|
||||
const storedItem = await this.itemsApplication.createItem(
|
||||
tenantId,
|
||||
itemDTO
|
||||
);
|
||||
|
||||
return res.status(200).send({
|
||||
id: storedItem.id,
|
||||
@@ -234,7 +222,7 @@ export default class ItemsController extends BaseController {
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
*/
|
||||
async editItem(req: Request, res: Response, next: NextFunction) {
|
||||
private async editItem(req: Request, res: Response, next: NextFunction) {
|
||||
const { tenantId } = req;
|
||||
const itemId: number = req.params.id;
|
||||
const item: IItemDTO = this.matchedBodyData(req);
|
||||
@@ -257,7 +245,7 @@ export default class ItemsController extends BaseController {
|
||||
* @param {Response} res
|
||||
* @param {NextFunction} next
|
||||
*/
|
||||
async activateItem(req: Request, res: Response, next: NextFunction) {
|
||||
private async activateItem(req: Request, res: Response, next: NextFunction) {
|
||||
const { tenantId } = req;
|
||||
const itemId: number = req.params.id;
|
||||
|
||||
@@ -279,7 +267,11 @@ export default class ItemsController extends BaseController {
|
||||
* @param {Response} res
|
||||
* @param {NextFunction} next
|
||||
*/
|
||||
async inactivateItem(req: Request, res: Response, next: NextFunction) {
|
||||
private async inactivateItem(
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
) {
|
||||
const { tenantId } = req;
|
||||
const itemId: number = req.params.id;
|
||||
|
||||
@@ -300,7 +292,7 @@ export default class ItemsController extends BaseController {
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
*/
|
||||
async deleteItem(req: Request, res: Response, next: NextFunction) {
|
||||
private async deleteItem(req: Request, res: Response, next: NextFunction) {
|
||||
const itemId: number = req.params.id;
|
||||
const { tenantId } = req;
|
||||
|
||||
@@ -322,7 +314,7 @@ export default class ItemsController extends BaseController {
|
||||
* @param {Response} res
|
||||
* @return {Response}
|
||||
*/
|
||||
async getItem(req: Request, res: Response, next: NextFunction) {
|
||||
private async getItem(req: Request, res: Response, next: NextFunction) {
|
||||
const itemId: number = req.params.id;
|
||||
const { tenantId } = req;
|
||||
|
||||
@@ -342,7 +334,7 @@ export default class ItemsController extends BaseController {
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
*/
|
||||
async getItemsList(req: Request, res: Response, next: NextFunction) {
|
||||
private async getItemsList(req: Request, res: Response, next: NextFunction) {
|
||||
const { tenantId } = req;
|
||||
|
||||
const filter = {
|
||||
|
||||
@@ -42,6 +42,7 @@ export enum AccountNormal {
|
||||
|
||||
export interface IAccountsTransactionsFilter {
|
||||
accountId?: number;
|
||||
limit?: number;
|
||||
}
|
||||
|
||||
export interface IAccountTransaction {
|
||||
|
||||
@@ -106,7 +106,7 @@ export default class AccountTransactionTransformer extends Transformer {
|
||||
* @returns {string}
|
||||
*/
|
||||
protected formattedFcCredit(transaction: IAccountTransaction) {
|
||||
return this.formatMoney(this.fcDebit(transaction), {
|
||||
return this.formatMoney(this.fcCredit(transaction), {
|
||||
currencyCode: transaction.currencyCode,
|
||||
excerptZero: true,
|
||||
});
|
||||
@@ -117,7 +117,7 @@ export default class AccountTransactionTransformer extends Transformer {
|
||||
* @returns {string}
|
||||
*/
|
||||
protected formattedFcDebit(transaction: IAccountTransaction) {
|
||||
return this.formatMoney(this.fcCredit(transaction), {
|
||||
return this.formatMoney(this.fcDebit(transaction), {
|
||||
currencyCode: transaction.currencyCode,
|
||||
excerptZero: true,
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import React from 'react';
|
||||
import withBreadcrumbs from 'react-router-breadcrumbs-hoc';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { getDashboardRoutes } from '@/routes/dashboard';
|
||||
|
||||
import { If, Icon } from '@/components';
|
||||
import { FormattedMessage as T } from '@/components';
|
||||
import withDashboard from '@/containers/Dashboard/withDashboard';
|
||||
|
||||
@@ -4,23 +4,24 @@ import intl from 'react-intl-universal';
|
||||
import { Link } from 'react-router-dom';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { compose } from '@/utils';
|
||||
import { TableStyle } from '@/constants';
|
||||
import { Card, DataTable, If } from '@/components';
|
||||
import { AccountDrawerTableOptionsProvider } from './AccountDrawerTableOptionsProvider';
|
||||
import { AccountDrawerTableHeader } from './AccountDrawerTableHeader';
|
||||
|
||||
import { useAccountReadEntriesColumns } from './utils';
|
||||
import { useAppIntlContext } from '@/components/AppIntlProvider';
|
||||
import { useAccountDrawerContext } from './AccountDrawerProvider';
|
||||
|
||||
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
|
||||
import { compose } from '@/utils';
|
||||
|
||||
/**
|
||||
* account drawer table.
|
||||
*/
|
||||
function AccountDrawerTable({ closeDrawer }) {
|
||||
const { account, accounts, drawerName } = useAccountDrawerContext();
|
||||
|
||||
// Account read-only entries table columns.
|
||||
const columns = useAccountReadEntriesColumns();
|
||||
const { accounts, drawerName } = useAccountDrawerContext();
|
||||
|
||||
// Handle view more link click.
|
||||
const handleLinkClick = () => {
|
||||
@@ -31,27 +32,41 @@ function AccountDrawerTable({ closeDrawer }) {
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={accounts}
|
||||
payload={{ account }}
|
||||
styleName={TableStyle.Constrant}
|
||||
/>
|
||||
<AccountDrawerTableOptionsProvider>
|
||||
<AccountDrawerTableHeader />
|
||||
<AccountDrawerDataTable />
|
||||
|
||||
<If condition={accounts.length > 0}>
|
||||
<TableFooter>
|
||||
<Link
|
||||
to={`/financial-reports/general-ledger`}
|
||||
onClick={handleLinkClick}
|
||||
>
|
||||
{isRTL ? '→' : '←'} {intl.get('view_more_transactions')}
|
||||
</Link>
|
||||
</TableFooter>
|
||||
</If>
|
||||
<If condition={accounts.length > 0}>
|
||||
<TableFooter>
|
||||
<Link
|
||||
to={`/financial-reports/general-ledger`}
|
||||
onClick={handleLinkClick}
|
||||
>
|
||||
{isRTL ? '→' : '←'} {intl.get('view_more_transactions')}
|
||||
</Link>
|
||||
</TableFooter>
|
||||
</If>
|
||||
</AccountDrawerTableOptionsProvider>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
function AccountDrawerDataTable() {
|
||||
const { account, accounts } = useAccountDrawerContext();
|
||||
|
||||
// Account read-only entries table columns.
|
||||
const columns = useAccountReadEntriesColumns();
|
||||
|
||||
return (
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={accounts}
|
||||
payload={{ account }}
|
||||
styleName={TableStyle.Constrant}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(withDrawerActions)(AccountDrawerTable);
|
||||
|
||||
const TableFooter = styled.div`
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import React from 'react';
|
||||
import { Button, ButtonGroup } from '@blueprintjs/core';
|
||||
import styled from 'styled-components';
|
||||
import { useAccountDrawerTableOptionsContext } from './AccountDrawerTableOptionsProvider';
|
||||
|
||||
export function AccountDrawerTableHeader() {
|
||||
const {
|
||||
setBCYCurrencyType,
|
||||
setFYCCurrencyType,
|
||||
isBCYCurrencyType,
|
||||
isFCYCurrencyType,
|
||||
} = useAccountDrawerTableOptionsContext();
|
||||
|
||||
const handleBCYBtnClick = () => {
|
||||
setBCYCurrencyType();
|
||||
};
|
||||
const handleFCYBtnClick = () => {
|
||||
setFYCCurrencyType();
|
||||
};
|
||||
|
||||
return (
|
||||
<TableHeaderRoot>
|
||||
<ButtonGroup>
|
||||
<Button
|
||||
small
|
||||
outlined
|
||||
onClick={handleFCYBtnClick}
|
||||
active={isFCYCurrencyType}
|
||||
>
|
||||
FCY
|
||||
</Button>
|
||||
<Button
|
||||
small
|
||||
outlined
|
||||
onClick={handleBCYBtnClick}
|
||||
active={isBCYCurrencyType}
|
||||
>
|
||||
BCY
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</TableHeaderRoot>
|
||||
);
|
||||
}
|
||||
|
||||
const TableHeaderRoot = styled.div`
|
||||
margin-bottom: 1rem;
|
||||
`;
|
||||
@@ -0,0 +1,57 @@
|
||||
import React, { useState, useCallback } from 'react';
|
||||
|
||||
interface AccountDrawerTableOptionsContextValue {
|
||||
setFYCCurrencyType: () => void;
|
||||
setBCYCurrencyType: () => void;
|
||||
isFCYCurrencyType: boolean;
|
||||
isBCYCurrencyType: boolean;
|
||||
currencyType: ForeignCurrencyType;
|
||||
}
|
||||
|
||||
const AccountDrawerTableOptionsContext = React.createContext(
|
||||
{} as AccountDrawerTableOptionsContextValue,
|
||||
);
|
||||
|
||||
enum ForeignCurrencyTypes {
|
||||
FCY = 'FCY',
|
||||
BCY = 'BCY',
|
||||
}
|
||||
type ForeignCurrencyType = ForeignCurrencyTypes.FCY | ForeignCurrencyTypes.BCY;
|
||||
|
||||
function AccountDrawerTableOptionsProvider({
|
||||
initialCurrencyType = ForeignCurrencyTypes.FCY,
|
||||
...props
|
||||
}) {
|
||||
const [currencyType, setCurrentType] =
|
||||
useState<ForeignCurrencyType>(initialCurrencyType);
|
||||
|
||||
const setFYCCurrencyType = useCallback(
|
||||
() => setCurrentType(ForeignCurrencyTypes.FCY),
|
||||
[setCurrentType],
|
||||
);
|
||||
const setBCYCurrencyType = useCallback(
|
||||
() => setCurrentType(ForeignCurrencyTypes.BCY),
|
||||
[setCurrentType],
|
||||
);
|
||||
|
||||
// Provider.
|
||||
const provider = {
|
||||
setFYCCurrencyType,
|
||||
setBCYCurrencyType,
|
||||
isFCYCurrencyType: currencyType === ForeignCurrencyTypes.FCY,
|
||||
isBCYCurrencyType: currencyType === ForeignCurrencyTypes.BCY,
|
||||
currencyType,
|
||||
};
|
||||
|
||||
return (
|
||||
<AccountDrawerTableOptionsContext.Provider value={provider} {...props} />
|
||||
);
|
||||
}
|
||||
|
||||
const useAccountDrawerTableOptionsContext = () =>
|
||||
React.useContext(AccountDrawerTableOptionsContext);
|
||||
|
||||
export {
|
||||
AccountDrawerTableOptionsProvider,
|
||||
useAccountDrawerTableOptionsContext,
|
||||
};
|
||||
@@ -3,27 +3,15 @@ import intl from 'react-intl-universal';
|
||||
import React from 'react';
|
||||
|
||||
import { FormatDateCell } from '@/components';
|
||||
import { isBlank } from '@/utils';
|
||||
|
||||
/**
|
||||
* Debit/credit table cell.
|
||||
*/
|
||||
function DebitCreditTableCell({ value, payload: { account } }) {
|
||||
return !isBlank(value) && value !== 0 ? account.formatted_amount : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Running balance table cell.
|
||||
*/
|
||||
function RunningBalanceTableCell({ value, payload: { account } }) {
|
||||
return account.formatted_amount;
|
||||
}
|
||||
import { useAccountDrawerTableOptionsContext } from './AccountDrawerTableOptionsProvider';
|
||||
|
||||
/**
|
||||
* Retrieve entries columns of read-only account view.
|
||||
*/
|
||||
export const useAccountReadEntriesColumns = () =>
|
||||
React.useMemo(
|
||||
export const useAccountReadEntriesColumns = () => {
|
||||
const { isFCYCurrencyType } = useAccountDrawerTableOptionsContext();
|
||||
|
||||
return React.useMemo(
|
||||
() => [
|
||||
{
|
||||
Header: intl.get('transaction_date'),
|
||||
@@ -34,14 +22,15 @@ export const useAccountReadEntriesColumns = () =>
|
||||
},
|
||||
{
|
||||
Header: intl.get('transaction_type'),
|
||||
accessor: 'reference_type_formatted',
|
||||
accessor: 'transaction_type_formatted',
|
||||
width: 100,
|
||||
textOverview: true,
|
||||
},
|
||||
{
|
||||
Header: intl.get('credit'),
|
||||
accessor: 'credit',
|
||||
Cell: DebitCreditTableCell,
|
||||
accessor: isFCYCurrencyType
|
||||
? 'formatted_fc_credit'
|
||||
: 'formatted_credit',
|
||||
width: 80,
|
||||
className: 'credit',
|
||||
align: 'right',
|
||||
@@ -49,22 +38,13 @@ export const useAccountReadEntriesColumns = () =>
|
||||
},
|
||||
{
|
||||
Header: intl.get('debit'),
|
||||
accessor: 'debit',
|
||||
Cell: DebitCreditTableCell,
|
||||
accessor: isFCYCurrencyType ? 'formatted_fc_debit' : 'formatted_debit',
|
||||
width: 80,
|
||||
className: 'debit',
|
||||
align: 'right',
|
||||
textOverview: true,
|
||||
},
|
||||
{
|
||||
Header: intl.get('running_balance'),
|
||||
Cell: RunningBalanceTableCell,
|
||||
accessor: 'running_balance',
|
||||
width: 110,
|
||||
className: 'running_balance',
|
||||
align: 'right',
|
||||
textOverview: true,
|
||||
},
|
||||
],
|
||||
[],
|
||||
[isFCYCurrencyType],
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user