mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-20 14:50:32 +00:00
Compare commits
6 Commits
style-fina
...
all-contri
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
44bd916ede | ||
|
|
fd5db4f055 | ||
|
|
e4a7f09dbc | ||
|
|
2c5537efad | ||
|
|
017908600e | ||
|
|
6307ca8935 |
@@ -60,6 +60,15 @@
|
|||||||
"contributions": [
|
"contributions": [
|
||||||
"bug"
|
"bug"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "kochie",
|
||||||
|
"name": "Robert Koch",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/10809884?v=4",
|
||||||
|
"profile": "https://me.kochie.io",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"contributorsPerLine": 7,
|
"contributorsPerLine": 7,
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
|||||||
<td align="center" valign="top" width="14.28%"><a href="https://scheibling.se"><img src="https://avatars.githubusercontent.com/u/24367830?v=4?s=100" width="100px;" alt="Lars Scheibling"/><br /><sub><b>Lars Scheibling</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/issues?q=author%3Ascheibling" title="Bug reports">🐛</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://scheibling.se"><img src="https://avatars.githubusercontent.com/u/24367830?v=4?s=100" width="100px;" alt="Lars Scheibling"/><br /><sub><b>Lars Scheibling</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/issues?q=author%3Ascheibling" title="Bug reports">🐛</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/suhaibaffan"><img src="https://avatars.githubusercontent.com/u/18115937?v=4?s=100" width="100px;" alt="Suhaib Affan"/><br /><sub><b>Suhaib Affan</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/commits?author=suhaibaffan" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/suhaibaffan"><img src="https://avatars.githubusercontent.com/u/18115937?v=4?s=100" width="100px;" alt="Suhaib Affan"/><br /><sub><b>Suhaib Affan</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/commits?author=suhaibaffan" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/KalliopiPliogka"><img src="https://avatars.githubusercontent.com/u/81677549?v=4?s=100" width="100px;" alt="Kalliopi Pliogka"/><br /><sub><b>Kalliopi Pliogka</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/issues?q=author%3AKalliopiPliogka" title="Bug reports">🐛</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/KalliopiPliogka"><img src="https://avatars.githubusercontent.com/u/81677549?v=4?s=100" width="100px;" alt="Kalliopi Pliogka"/><br /><sub><b>Kalliopi Pliogka</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/issues?q=author%3AKalliopiPliogka" title="Bug reports">🐛</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://me.kochie.io"><img src="https://avatars.githubusercontent.com/u/10809884?v=4?s=100" width="100px;" alt="Robert Koch"/><br /><sub><b>Robert Koch</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/commits?author=kochie" title="Code">💻</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
867
packages/server/package-lock.json
generated
867
packages/server/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -16,7 +16,7 @@ export default class TrialBalanceSheetController extends BaseFinancialReportCont
|
|||||||
/**
|
/**
|
||||||
* Router constructor.
|
* Router constructor.
|
||||||
*/
|
*/
|
||||||
router() {
|
public router() {
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
router.get(
|
router.get(
|
||||||
@@ -36,7 +36,7 @@ export default class TrialBalanceSheetController extends BaseFinancialReportCont
|
|||||||
* Validation schema.
|
* Validation schema.
|
||||||
* @return {ValidationChain[]}
|
* @return {ValidationChain[]}
|
||||||
*/
|
*/
|
||||||
get trialBalanceSheetValidationSchema(): ValidationChain[] {
|
private get trialBalanceSheetValidationSchema(): ValidationChain[] {
|
||||||
return [
|
return [
|
||||||
...this.sheetNumberFormatValidationSchema,
|
...this.sheetNumberFormatValidationSchema,
|
||||||
query('basis').optional(),
|
query('basis').optional(),
|
||||||
@@ -59,28 +59,37 @@ export default class TrialBalanceSheetController extends BaseFinancialReportCont
|
|||||||
/**
|
/**
|
||||||
* Retrieve the trial balance sheet.
|
* Retrieve the trial balance sheet.
|
||||||
*/
|
*/
|
||||||
public async trialBalanceSheet(
|
private async trialBalanceSheet(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
next: NextFunction
|
next: NextFunction
|
||||||
) {
|
) {
|
||||||
const { tenantId, settings } = req;
|
const { tenantId } = req;
|
||||||
let filter = this.matchedQueryData(req);
|
let filter = this.matchedQueryData(req);
|
||||||
|
|
||||||
filter = {
|
filter = {
|
||||||
...filter,
|
...filter,
|
||||||
accountsIds: castArray(filter.accountsIds),
|
accountsIds: castArray(filter.accountsIds),
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { data, query, meta } =
|
const accept = this.accepts(req);
|
||||||
await this.trialBalanceSheetService.trialBalanceSheet(tenantId, filter);
|
const acceptType = accept.types(['json', 'application/json+table']);
|
||||||
|
|
||||||
return res.status(200).send({
|
if (acceptType === 'application/json+table') {
|
||||||
data: this.transfromToResponse(data),
|
const { table, meta, query } =
|
||||||
query: this.transfromToResponse(query),
|
await this.trialBalanceSheetService.trialBalanceSheetTable(
|
||||||
meta: this.transfromToResponse(meta),
|
tenantId,
|
||||||
});
|
filter
|
||||||
|
);
|
||||||
|
return res.status(200).send({ table, meta, query });
|
||||||
|
} else {
|
||||||
|
const { data, query, meta } =
|
||||||
|
await this.trialBalanceSheetService.trialBalanceSheet(
|
||||||
|
tenantId,
|
||||||
|
filter
|
||||||
|
);
|
||||||
|
return res.status(200).send({ data, query, meta });
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,14 +31,14 @@ export default class OrganizationController extends BaseController {
|
|||||||
|
|
||||||
router.post(
|
router.post(
|
||||||
'/build',
|
'/build',
|
||||||
this.organizationValidationSchema,
|
this.buildOrganizationValidationSchema,
|
||||||
this.validationResult,
|
this.validationResult,
|
||||||
asyncMiddleware(this.build.bind(this)),
|
asyncMiddleware(this.build.bind(this)),
|
||||||
this.handleServiceErrors.bind(this)
|
this.handleServiceErrors.bind(this)
|
||||||
);
|
);
|
||||||
router.put(
|
router.put(
|
||||||
'/',
|
'/',
|
||||||
this.organizationValidationSchema,
|
this.updateOrganizationValidationSchema,
|
||||||
this.validationResult,
|
this.validationResult,
|
||||||
this.asyncMiddleware(this.updateOrganization.bind(this)),
|
this.asyncMiddleware(this.updateOrganization.bind(this)),
|
||||||
this.handleServiceErrors.bind(this)
|
this.handleServiceErrors.bind(this)
|
||||||
@@ -55,7 +55,7 @@ export default class OrganizationController extends BaseController {
|
|||||||
* Organization setup schema.
|
* Organization setup schema.
|
||||||
* @return {ValidationChain[]}
|
* @return {ValidationChain[]}
|
||||||
*/
|
*/
|
||||||
private get organizationValidationSchema(): ValidationChain[] {
|
private get commonOrganizationValidationSchema(): ValidationChain[] {
|
||||||
return [
|
return [
|
||||||
check('name').exists().trim(),
|
check('name').exists().trim(),
|
||||||
check('industry').optional({ nullable: true }).isString().trim().escape(),
|
check('industry').optional({ nullable: true }).isString().trim().escape(),
|
||||||
@@ -68,6 +68,29 @@ export default class OrganizationController extends BaseController {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build organization validation schema.
|
||||||
|
* @returns {ValidationChain[]}
|
||||||
|
*/
|
||||||
|
private get buildOrganizationValidationSchema(): ValidationChain[] {
|
||||||
|
return [...this.commonOrganizationValidationSchema];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update organization validation schema.
|
||||||
|
* @returns {ValidationChain[]}
|
||||||
|
*/
|
||||||
|
private get updateOrganizationValidationSchema(): ValidationChain[] {
|
||||||
|
return [
|
||||||
|
...this.commonOrganizationValidationSchema,
|
||||||
|
check('tax_number')
|
||||||
|
.optional({ nullable: true })
|
||||||
|
.isString()
|
||||||
|
.trim()
|
||||||
|
.escape(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds tenant database and migrate database schema.
|
* Builds tenant database and migrate database schema.
|
||||||
* @param {Request} req - Express request.
|
* @param {Request} req - Express request.
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ export interface ILedger {
|
|||||||
|
|
||||||
getClosingBalance(): number;
|
getClosingBalance(): number;
|
||||||
getForeignClosingBalance(): number;
|
getForeignClosingBalance(): number;
|
||||||
|
getClosingDebit(): number;
|
||||||
|
getClosingCredit(): number;
|
||||||
|
|
||||||
getContactsIds(): number[];
|
getContactsIds(): number[];
|
||||||
getAccountsIds(): number[];
|
getAccountsIds(): number[];
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ export interface IOrganizationUpdateDTO {
|
|||||||
timezone: string;
|
timezone: string;
|
||||||
fiscalYear: string;
|
fiscalYear: string;
|
||||||
industry: string;
|
industry: string;
|
||||||
|
taxNumber: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IOrganizationBuildEventPayload {
|
export interface IOrganizationBuildEventPayload {
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ export interface ITrialBalanceAccount extends ITrialBalanceTotal {
|
|||||||
id: number;
|
id: number;
|
||||||
parentAccountId: number;
|
parentAccountId: number;
|
||||||
name: string;
|
name: string;
|
||||||
|
formattedName: string;
|
||||||
code: string;
|
code: string;
|
||||||
accountNormal: string;
|
accountNormal: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { defaultTo, uniqBy } from 'lodash';
|
import { defaultTo, sumBy, uniqBy } from 'lodash';
|
||||||
import { IAccountTransaction, ILedger, ILedgerEntry } from '@/interfaces';
|
import { IAccountTransaction, ILedger, ILedgerEntry } from '@/interfaces';
|
||||||
|
|
||||||
export default class Ledger implements ILedger {
|
export default class Ledger implements ILedger {
|
||||||
@@ -49,6 +49,15 @@ export default class Ledger implements ILedger {
|
|||||||
return this.filter((entry) => entry.accountId === accountId);
|
return this.filter((entry) => entry.accountId === accountId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters entries by the given accounts ids then returns a new ledger.
|
||||||
|
* @param {number[]} accountsIds - Accounts ids.
|
||||||
|
* @returns {ILedger}
|
||||||
|
*/
|
||||||
|
public whereAccountsIds(accountsIds: number[]): ILedger {
|
||||||
|
return this.filter((entry) => accountsIds.indexOf(entry.accountId) !== -1);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filters entries that before or same the given date and returns a new ledger.
|
* Filters entries that before or same the given date and returns a new ledger.
|
||||||
* @param {Date|string} fromDate
|
* @param {Date|string} fromDate
|
||||||
@@ -130,6 +139,22 @@ export default class Ledger implements ILedger {
|
|||||||
return closingBalance;
|
return closingBalance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the closing credit of the entries.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
public getClosingCredit(): number {
|
||||||
|
return sumBy(this.entries, 'credit');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the closing debit of the entries.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
public getClosingDebit(): number {
|
||||||
|
return sumBy(this.entries, 'debit');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the closing balance of the entries.
|
* Retrieve the closing balance of the entries.
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
|
|||||||
@@ -10,13 +10,26 @@ import {
|
|||||||
} from '@/interfaces';
|
} from '@/interfaces';
|
||||||
import FinancialSheet from '../FinancialSheet';
|
import FinancialSheet from '../FinancialSheet';
|
||||||
import { allPassedConditionsPass, flatToNestedArray } from 'utils';
|
import { allPassedConditionsPass, flatToNestedArray } from 'utils';
|
||||||
|
import { TrialBalanceSheetRepository } from './TrialBalanceSheetRepository';
|
||||||
|
|
||||||
export default class TrialBalanceSheet extends FinancialSheet {
|
export default class TrialBalanceSheet extends FinancialSheet {
|
||||||
tenantId: number;
|
/**
|
||||||
query: ITrialBalanceSheetQuery;
|
* Trial balance sheet query.
|
||||||
accounts: IAccount & { type: IAccountType }[];
|
* @param {ITrialBalanceSheetQuery} query
|
||||||
journalFinancial: any;
|
*/
|
||||||
baseCurrency: string;
|
private query: ITrialBalanceSheetQuery;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trial balance sheet repository.
|
||||||
|
* @param {TrialBalanceSheetRepository}
|
||||||
|
*/
|
||||||
|
private repository: TrialBalanceSheetRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Organization base currency.
|
||||||
|
* @param {string}
|
||||||
|
*/
|
||||||
|
private baseCurrency: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor method.
|
* Constructor method.
|
||||||
@@ -28,20 +41,58 @@ export default class TrialBalanceSheet extends FinancialSheet {
|
|||||||
constructor(
|
constructor(
|
||||||
tenantId: number,
|
tenantId: number,
|
||||||
query: ITrialBalanceSheetQuery,
|
query: ITrialBalanceSheetQuery,
|
||||||
accounts: IAccount & { type: IAccountType }[],
|
repository: TrialBalanceSheetRepository,
|
||||||
journalFinancial: any,
|
|
||||||
baseCurrency: string
|
baseCurrency: string
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.tenantId = tenantId;
|
this.tenantId = tenantId;
|
||||||
this.query = query;
|
this.query = query;
|
||||||
this.accounts = accounts;
|
this.repository = repository;
|
||||||
this.journalFinancial = journalFinancial;
|
|
||||||
this.numberFormat = this.query.numberFormat;
|
this.numberFormat = this.query.numberFormat;
|
||||||
this.baseCurrency = baseCurrency;
|
this.baseCurrency = baseCurrency;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the closing credit of the given account.
|
||||||
|
* @param {number} accountId
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
public getClosingAccountCredit(accountId: number) {
|
||||||
|
const depsAccountsIds =
|
||||||
|
this.repository.accountsDepGraph.dependenciesOf(accountId);
|
||||||
|
|
||||||
|
return this.repository.totalAccountsLedger
|
||||||
|
.whereAccountsIds([accountId, ...depsAccountsIds])
|
||||||
|
.getClosingCredit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the closing debit of the given account.
|
||||||
|
* @param {number} accountId
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
public getClosingAccountDebit(accountId: number) {
|
||||||
|
const depsAccountsIds =
|
||||||
|
this.repository.accountsDepGraph.dependenciesOf(accountId);
|
||||||
|
|
||||||
|
return this.repository.totalAccountsLedger
|
||||||
|
.whereAccountsIds([accountId, ...depsAccountsIds])
|
||||||
|
.getClosingDebit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the closing total of the given account.
|
||||||
|
* @param {number} accountId
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
public getClosingAccountTotal(accountId: number) {
|
||||||
|
const credit = this.getClosingAccountCredit(accountId);
|
||||||
|
const debit = this.getClosingAccountDebit(accountId);
|
||||||
|
|
||||||
|
return debit - credit;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Account mapper.
|
* Account mapper.
|
||||||
* @param {IAccount} account
|
* @param {IAccount} account
|
||||||
@@ -50,23 +101,28 @@ export default class TrialBalanceSheet extends FinancialSheet {
|
|||||||
private accountTransformer = (
|
private accountTransformer = (
|
||||||
account: IAccount & { type: IAccountType }
|
account: IAccount & { type: IAccountType }
|
||||||
): ITrialBalanceAccount => {
|
): ITrialBalanceAccount => {
|
||||||
const trial = this.journalFinancial.getTrialBalanceWithDepands(account.id);
|
const debit = this.getClosingAccountDebit(account.id);
|
||||||
|
const credit = this.getClosingAccountCredit(account.id);
|
||||||
|
const balance = this.getClosingAccountTotal(account.id);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: account.id,
|
id: account.id,
|
||||||
parentAccountId: account.parentAccountId,
|
parentAccountId: account.parentAccountId,
|
||||||
name: account.name,
|
name: account.name,
|
||||||
|
formattedName: account.code
|
||||||
|
? `${account.name} - ${account.code}`
|
||||||
|
: `${account.name}`,
|
||||||
code: account.code,
|
code: account.code,
|
||||||
accountNormal: account.accountNormal,
|
accountNormal: account.accountNormal,
|
||||||
|
|
||||||
credit: trial.credit,
|
credit,
|
||||||
debit: trial.debit,
|
debit,
|
||||||
balance: trial.balance,
|
balance,
|
||||||
currencyCode: this.baseCurrency,
|
currencyCode: this.baseCurrency,
|
||||||
|
|
||||||
formattedCredit: this.formatNumber(trial.credit),
|
formattedCredit: this.formatNumber(credit),
|
||||||
formattedDebit: this.formatNumber(trial.debit),
|
formattedDebit: this.formatNumber(debit),
|
||||||
formattedBalance: this.formatNumber(trial.balance),
|
formattedBalance: this.formatNumber(balance),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -117,10 +173,7 @@ export default class TrialBalanceSheet extends FinancialSheet {
|
|||||||
private filterNoneTransactions = (
|
private filterNoneTransactions = (
|
||||||
accountNode: ITrialBalanceAccount
|
accountNode: ITrialBalanceAccount
|
||||||
): boolean => {
|
): boolean => {
|
||||||
const entries = this.journalFinancial.getAccountEntriesWithDepents(
|
return false === this.repository.totalAccountsLedger.isEmpty();
|
||||||
accountNode.id
|
|
||||||
);
|
|
||||||
return entries.length > 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -200,11 +253,11 @@ export default class TrialBalanceSheet extends FinancialSheet {
|
|||||||
*/
|
*/
|
||||||
public reportData(): ITrialBalanceSheetData {
|
public reportData(): ITrialBalanceSheetData {
|
||||||
// Don't return noting if the journal has no transactions.
|
// Don't return noting if the journal has no transactions.
|
||||||
if (this.journalFinancial.isEmpty()) {
|
if (this.repository.totalAccountsLedger.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// Retrieve accounts nodes.
|
// Retrieve accounts nodes.
|
||||||
const accounts = this.accountsSection(this.accounts);
|
const accounts = this.accountsSection(this.repository.accounts);
|
||||||
|
|
||||||
// Retrieve account node.
|
// Retrieve account node.
|
||||||
const total = this.tatalSection(accounts);
|
const total = this.tatalSection(accounts);
|
||||||
|
|||||||
@@ -0,0 +1,105 @@
|
|||||||
|
import { ITrialBalanceSheetQuery } from '@/interfaces';
|
||||||
|
import Ledger from '@/services/Accounting/Ledger';
|
||||||
|
import { Knex } from 'knex';
|
||||||
|
import { isEmpty } from 'lodash';
|
||||||
|
import { Service } from 'typedi';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class TrialBalanceSheetRepository {
|
||||||
|
private query: ITrialBalanceSheetQuery;
|
||||||
|
private models: any;
|
||||||
|
public accounts: any;
|
||||||
|
public accountsDepGraph;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Total closing accounts ledger.
|
||||||
|
* @param {Ledger}
|
||||||
|
*/
|
||||||
|
public totalAccountsLedger: Ledger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor method.
|
||||||
|
* @param {number} tenantId
|
||||||
|
* @param {IBalanceSheetQuery} query
|
||||||
|
*/
|
||||||
|
constructor(models: any, repos: any, query: ITrialBalanceSheetQuery) {
|
||||||
|
this.query = query;
|
||||||
|
this.repos = repos;
|
||||||
|
this.models = models;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Async initialize.
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
public asyncInitialize = async () => {
|
||||||
|
await this.initAccounts();
|
||||||
|
await this.initAccountsClosingTotalLedger();
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------------------
|
||||||
|
// # Accounts
|
||||||
|
// ----------------------------
|
||||||
|
/**
|
||||||
|
* Initialize accounts.
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
public initAccounts = async () => {
|
||||||
|
const accounts = await this.getAccounts();
|
||||||
|
const accountsDepGraph =
|
||||||
|
await this.repos.accountRepository.getDependencyGraph();
|
||||||
|
|
||||||
|
this.accountsDepGraph = accountsDepGraph;
|
||||||
|
this.accounts = accounts;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize all accounts closing total ledger.
|
||||||
|
* @return {Promise<void>}
|
||||||
|
*/
|
||||||
|
public initAccountsClosingTotalLedger = async (): Promise<void> => {
|
||||||
|
const totalByAccounts = await this.closingAccountsTotal(this.query.toDate);
|
||||||
|
|
||||||
|
this.totalAccountsLedger = Ledger.fromTransactions(totalByAccounts);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve accounts of the report.
|
||||||
|
* @return {Promise<IAccount[]>}
|
||||||
|
*/
|
||||||
|
private getAccounts = () => {
|
||||||
|
const { Account } = this.models;
|
||||||
|
|
||||||
|
return Account.query();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the opening balance transactions of the report.
|
||||||
|
* @param {Date|string} openingDate -
|
||||||
|
*/
|
||||||
|
public closingAccountsTotal = async (openingDate: Date | string) => {
|
||||||
|
const { AccountTransaction } = this.models;
|
||||||
|
|
||||||
|
return AccountTransaction.query().onBuild((query) => {
|
||||||
|
query.sum('credit as credit');
|
||||||
|
query.sum('debit as debit');
|
||||||
|
query.groupBy('accountId');
|
||||||
|
query.select(['accountId']);
|
||||||
|
|
||||||
|
query.modify('filterDateRange', null, openingDate);
|
||||||
|
query.withGraphFetched('account');
|
||||||
|
|
||||||
|
this.commonFilterBranchesQuery(query);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common branches filter query.
|
||||||
|
* @param {Knex.QueryBuilder} query
|
||||||
|
*/
|
||||||
|
private commonFilterBranchesQuery = (query: Knex.QueryBuilder) => {
|
||||||
|
if (!isEmpty(this.query.branchesIds)) {
|
||||||
|
query.modify('filterByBranches', this.query.branchesIds);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -2,12 +2,18 @@ import { Service, Inject } from 'typedi';
|
|||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import TenancyService from '@/services/Tenancy/TenancyService';
|
import TenancyService from '@/services/Tenancy/TenancyService';
|
||||||
import Journal from '@/services/Accounting/JournalPoster';
|
import Journal from '@/services/Accounting/JournalPoster';
|
||||||
import { ITrialBalanceSheetMeta, ITrialBalanceSheetQuery, ITrialBalanceStatement } from '@/interfaces';
|
import {
|
||||||
|
ITrialBalanceSheetMeta,
|
||||||
|
ITrialBalanceSheetQuery,
|
||||||
|
ITrialBalanceStatement,
|
||||||
|
} from '@/interfaces';
|
||||||
import TrialBalanceSheet from './TrialBalanceSheet';
|
import TrialBalanceSheet from './TrialBalanceSheet';
|
||||||
import FinancialSheet from '../FinancialSheet';
|
import FinancialSheet from '../FinancialSheet';
|
||||||
import InventoryService from '@/services/Inventory/Inventory';
|
import InventoryService from '@/services/Inventory/Inventory';
|
||||||
import { parseBoolean } from 'utils';
|
import { parseBoolean } from 'utils';
|
||||||
import { Tenant } from '@/system/models';
|
import { Tenant } from '@/system/models';
|
||||||
|
import { TrialBalanceSheetRepository } from './TrialBalanceSheetRepository';
|
||||||
|
import { TrialBalanceSheetTable } from './TrialBalanceSheetTable';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export default class TrialBalanceSheetService extends FinancialSheet {
|
export default class TrialBalanceSheetService extends FinancialSheet {
|
||||||
@@ -51,9 +57,8 @@ export default class TrialBalanceSheetService extends FinancialSheet {
|
|||||||
reportMetadata(tenantId: number): ITrialBalanceSheetMeta {
|
reportMetadata(tenantId: number): ITrialBalanceSheetMeta {
|
||||||
const settings = this.tenancy.settings(tenantId);
|
const settings = this.tenancy.settings(tenantId);
|
||||||
|
|
||||||
const isCostComputeRunning = this.inventoryService.isItemsCostComputeRunning(
|
const isCostComputeRunning =
|
||||||
tenantId
|
this.inventoryService.isItemsCostComputeRunning(tenantId);
|
||||||
);
|
|
||||||
const organizationName = settings.get({
|
const organizationName = settings.get({
|
||||||
group: 'organization',
|
group: 'organization',
|
||||||
key: 'name',
|
key: 'name',
|
||||||
@@ -72,10 +77,8 @@ export default class TrialBalanceSheetService extends FinancialSheet {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve trial balance sheet statement.
|
* Retrieve trial balance sheet statement.
|
||||||
* -------------
|
|
||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
* @param {IBalanceSheetQuery} query
|
* @param {IBalanceSheetQuery} query
|
||||||
*
|
|
||||||
* @return {IBalanceSheetStatement}
|
* @return {IBalanceSheetStatement}
|
||||||
*/
|
*/
|
||||||
public async trialBalanceSheet(
|
public async trialBalanceSheet(
|
||||||
@@ -86,43 +89,27 @@ export default class TrialBalanceSheetService extends FinancialSheet {
|
|||||||
...this.defaultQuery,
|
...this.defaultQuery,
|
||||||
...query,
|
...query,
|
||||||
};
|
};
|
||||||
const {
|
|
||||||
accountRepository,
|
|
||||||
transactionsRepository,
|
|
||||||
} = this.tenancy.repositories(tenantId);
|
|
||||||
|
|
||||||
const tenant = await Tenant.query()
|
const tenant = await Tenant.query()
|
||||||
.findById(tenantId)
|
.findById(tenantId)
|
||||||
.withGraphFetched('metadata');
|
.withGraphFetched('metadata');
|
||||||
|
|
||||||
this.logger.info('[trial_balance_sheet] trying to calcualte the report.', {
|
const models = this.tenancy.models(tenantId);
|
||||||
tenantId,
|
const repos = this.tenancy.repositories(tenantId);
|
||||||
filter,
|
|
||||||
});
|
|
||||||
// Retrieve all accounts on the storage.
|
|
||||||
const accounts = await accountRepository.all();
|
|
||||||
const accountsGraph = await accountRepository.getDependencyGraph();
|
|
||||||
|
|
||||||
// Retrieve all journal transactions based on the given query.
|
const trialBalanceSheetRepos = new TrialBalanceSheetRepository(
|
||||||
const transactions = await transactionsRepository.journal({
|
models,
|
||||||
fromDate: query.fromDate,
|
repos,
|
||||||
toDate: query.toDate,
|
filter
|
||||||
sumationCreditDebit: true,
|
|
||||||
branchesIds: query.branchesIds
|
|
||||||
});
|
|
||||||
// Transform transactions array to journal collection.
|
|
||||||
const transactionsJournal = Journal.fromTransactions(
|
|
||||||
transactions,
|
|
||||||
tenantId,
|
|
||||||
accountsGraph
|
|
||||||
);
|
);
|
||||||
|
await trialBalanceSheetRepos.asyncInitialize();
|
||||||
|
|
||||||
// Trial balance report instance.
|
// Trial balance report instance.
|
||||||
const trialBalanceInstance = new TrialBalanceSheet(
|
const trialBalanceInstance = new TrialBalanceSheet(
|
||||||
tenantId,
|
tenantId,
|
||||||
filter,
|
filter,
|
||||||
accounts,
|
trialBalanceSheetRepos,
|
||||||
transactionsJournal,
|
tenant.metadata.baseCurrency
|
||||||
tenant.metadata.baseCurrency,
|
|
||||||
);
|
);
|
||||||
// Trial balance sheet data.
|
// Trial balance sheet data.
|
||||||
const trialBalanceSheetData = trialBalanceInstance.reportData();
|
const trialBalanceSheetData = trialBalanceInstance.reportData();
|
||||||
@@ -133,4 +120,27 @@ export default class TrialBalanceSheetService extends FinancialSheet {
|
|||||||
meta: this.reportMetadata(tenantId),
|
meta: this.reportMetadata(tenantId),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the trial balance sheet table.
|
||||||
|
* @param {number} tenantId
|
||||||
|
* @param {ITrialBalanceSheetQuery} query
|
||||||
|
* @returns {Promise<any>}
|
||||||
|
*/
|
||||||
|
public async trialBalanceSheetTable(
|
||||||
|
tenantId: number,
|
||||||
|
query: ITrialBalanceSheetQuery
|
||||||
|
) {
|
||||||
|
const trialBalance = await this.trialBalanceSheet(tenantId, query);
|
||||||
|
const table = new TrialBalanceSheetTable(trialBalance.data, query, {});
|
||||||
|
|
||||||
|
return {
|
||||||
|
table: {
|
||||||
|
columns: table.tableColumns(),
|
||||||
|
rows: table.tableRows(),
|
||||||
|
},
|
||||||
|
meta: trialBalance.meta,
|
||||||
|
query: trialBalance.query,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,146 @@
|
|||||||
|
import * as R from 'ramda';
|
||||||
|
import FinancialSheet from '../FinancialSheet';
|
||||||
|
import { FinancialTable } from '../FinancialTable';
|
||||||
|
import {
|
||||||
|
IBalanceSheetStatementData,
|
||||||
|
ITableColumn,
|
||||||
|
ITableColumnAccessor,
|
||||||
|
ITableRow,
|
||||||
|
ITrialBalanceAccount,
|
||||||
|
ITrialBalanceSheetData,
|
||||||
|
ITrialBalanceSheetQuery,
|
||||||
|
ITrialBalanceTotal,
|
||||||
|
} from '@/interfaces';
|
||||||
|
import { tableRowMapper } from '@/utils';
|
||||||
|
import { IROW_TYPE } from '../BalanceSheet/constants';
|
||||||
|
import { FinancialSheetStructure } from '../FinancialSheetStructure';
|
||||||
|
|
||||||
|
export class TrialBalanceSheetTable extends R.compose(
|
||||||
|
FinancialTable,
|
||||||
|
FinancialSheetStructure
|
||||||
|
)(FinancialSheet) {
|
||||||
|
/**
|
||||||
|
* @param {ITrialBalanceSheetData}
|
||||||
|
*/
|
||||||
|
public data: ITrialBalanceSheetData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Balance sheet query.
|
||||||
|
* @param {ITrialBalanceSheetQuery}
|
||||||
|
*/
|
||||||
|
public query: ITrialBalanceSheetQuery;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor method.
|
||||||
|
* @param {IBalanceSheetStatementData} reportData -
|
||||||
|
* @param {ITrialBalanceSheetQuery} query -
|
||||||
|
*/
|
||||||
|
constructor(
|
||||||
|
data: ITrialBalanceSheetData,
|
||||||
|
query: ITrialBalanceSheetQuery,
|
||||||
|
i18n: any
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.data = data;
|
||||||
|
this.query = query;
|
||||||
|
this.i18n = i18n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the common columns for all report nodes.
|
||||||
|
* @param {ITableColumnAccessor[]}
|
||||||
|
*/
|
||||||
|
private commonColumnsAccessors = (): ITableColumnAccessor[] => {
|
||||||
|
return [
|
||||||
|
{ key: 'account', accessor: 'formattedName' },
|
||||||
|
{ key: 'debit', accessor: 'formattedDebit' },
|
||||||
|
{ key: 'credit', accessor: 'formattedCredit' },
|
||||||
|
{ key: 'total', accessor: 'formattedBalance' },
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps the account node to table row.
|
||||||
|
* @param {ITrialBalanceAccount} node -
|
||||||
|
* @returns {ITableRow}
|
||||||
|
*/
|
||||||
|
private accountNodeTableRowsMapper = (
|
||||||
|
node: ITrialBalanceAccount
|
||||||
|
): ITableRow => {
|
||||||
|
const columns = this.commonColumnsAccessors();
|
||||||
|
const meta = {
|
||||||
|
rowTypes: [IROW_TYPE.ACCOUNT],
|
||||||
|
id: node.id,
|
||||||
|
};
|
||||||
|
return tableRowMapper(node, columns, meta);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps the total node to table row.
|
||||||
|
* @param {ITrialBalanceTotal} node -
|
||||||
|
* @returns {ITableRow}
|
||||||
|
*/
|
||||||
|
private totalNodeTableRowsMapper = (node: ITrialBalanceTotal): ITableRow => {
|
||||||
|
const columns = this.commonColumnsAccessors();
|
||||||
|
const meta = {
|
||||||
|
rowTypes: [IROW_TYPE.TOTAL],
|
||||||
|
id: node.id,
|
||||||
|
};
|
||||||
|
return tableRowMapper(node, columns, meta);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mappes the given report sections to table rows.
|
||||||
|
* @param {IBalanceSheetDataNode[]} nodes -
|
||||||
|
* @return {ITableRow}
|
||||||
|
*/
|
||||||
|
private accountsToTableRowsMap = (
|
||||||
|
nodes: ITrialBalanceAccount[]
|
||||||
|
): ITableRow[] => {
|
||||||
|
return this.mapNodesDeep(nodes, this.accountNodeTableRowsMapper);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the accounts table rows of the given report data.
|
||||||
|
* @returns {ITableRow[]}
|
||||||
|
*/
|
||||||
|
private accountsTableRows = (): ITableRow[] => {
|
||||||
|
return this.accountsToTableRowsMap(this.data.accounts);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps the given total node to table row.
|
||||||
|
* @returns {ITableRow}
|
||||||
|
*/
|
||||||
|
private totalTableRow = (): ITableRow => {
|
||||||
|
return this.totalNodeTableRowsMapper(this.data.total);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the table rows.
|
||||||
|
* @returns {ITableRow[]}
|
||||||
|
*/
|
||||||
|
public tableRows = (): ITableRow[] => {
|
||||||
|
return R.compose(
|
||||||
|
R.append(this.totalTableRow()),
|
||||||
|
R.concat(this.accountsTableRows())
|
||||||
|
)([]);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrrieves the table columns.
|
||||||
|
* @returns {ITableColumn[]}
|
||||||
|
*/
|
||||||
|
public tableColumns = (): ITableColumn[] => {
|
||||||
|
return R.compose(
|
||||||
|
this.tableColumnsCellIndexing,
|
||||||
|
R.concat([
|
||||||
|
{ key: 'account_name', label: 'Account' },
|
||||||
|
{ key: 'debit', label: 'Debit' },
|
||||||
|
{ key: 'credit', label: 'Credit' },
|
||||||
|
{ key: 'total', label: 'Total' },
|
||||||
|
])
|
||||||
|
)([]);
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
export enum IROW_TYPE {
|
||||||
|
ACCOUNT = 'ACCOUNT',
|
||||||
|
TOTAL = 'TOTAL',
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
exports.up = function (knex) {
|
||||||
|
return knex.schema.table('tenants_metadata', (table) => {
|
||||||
|
table.string('tax_number')
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.down = function (knex) {
|
||||||
|
return knex.schema.table('tenants_metadata', (table) => {
|
||||||
|
table.dropColumn('tax_number');
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -62,6 +62,7 @@ const BalanceSheetDataTable = styled(ReportDataTable)`
|
|||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
padding-top: 0.32rem;
|
padding-top: 0.32rem;
|
||||||
padding-bottom: 0.32rem;
|
padding-bottom: 0.32rem;
|
||||||
|
color: #252A31;
|
||||||
}
|
}
|
||||||
&.is-expanded {
|
&.is-expanded {
|
||||||
.td:not(.name) .cell-inner {
|
.td:not(.name) .cell-inner {
|
||||||
@@ -72,6 +73,7 @@ const BalanceSheetDataTable = styled(ReportDataTable)`
|
|||||||
.td {
|
.td {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
border-top: 1px solid #bbb;
|
border-top: 1px solid #bbb;
|
||||||
|
color: #000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,9 +60,8 @@ const CashflowStatementDataTable = styled(DataTable)`
|
|||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
padding-top: 0.32rem;
|
padding-top: 0.32rem;
|
||||||
padding-bottom: 0.32rem;
|
padding-bottom: 0.32rem;
|
||||||
|
color: #252a31;
|
||||||
}
|
}
|
||||||
|
|
||||||
// &.row-type--AGGREGATE,
|
|
||||||
&.row_type--ACCOUNTS {
|
&.row_type--ACCOUNTS {
|
||||||
border-top: 1px solid #bbb;
|
border-top: 1px solid #bbb;
|
||||||
}
|
}
|
||||||
@@ -72,6 +71,9 @@ const CashflowStatementDataTable = styled(DataTable)`
|
|||||||
&.row_type--TOTAL {
|
&.row_type--TOTAL {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
|
||||||
|
.td {
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
&:not(:first-child) .td {
|
&:not(:first-child) .td {
|
||||||
border-top: 1px solid #bbb;
|
border-top: 1px solid #bbb;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ const ProfitLossDataTable = styled(ReportDataTable)`
|
|||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
padding-top: 0.32rem;
|
padding-top: 0.32rem;
|
||||||
padding-bottom: 0.32rem;
|
padding-bottom: 0.32rem;
|
||||||
|
color: #252A31;
|
||||||
}
|
}
|
||||||
&.is-expanded {
|
&.is-expanded {
|
||||||
.td:not(.name) .cell-inner {
|
.td:not(.name) .cell-inner {
|
||||||
@@ -71,6 +72,7 @@ const ProfitLossDataTable = styled(ReportDataTable)`
|
|||||||
.td {
|
.td {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
border-top: 1px solid #bbb;
|
border-top: 1px solid #bbb;
|
||||||
|
color: #000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&:last-of-type .td {
|
&:last-of-type .td {
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import {
|
|||||||
} from './components';
|
} from './components';
|
||||||
|
|
||||||
import withTrialBalanceActions from './withTrialBalanceActions';
|
import withTrialBalanceActions from './withTrialBalanceActions';
|
||||||
|
|
||||||
import { compose } from '@/utils';
|
import { compose } from '@/utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -8,8 +8,7 @@ import { tableRowTypesToClassnames } from '@/utils';
|
|||||||
import { ReportDataTable, FinancialSheet } from '@/components';
|
import { ReportDataTable, FinancialSheet } from '@/components';
|
||||||
|
|
||||||
import { useTrialBalanceSheetContext } from './TrialBalanceProvider';
|
import { useTrialBalanceSheetContext } from './TrialBalanceProvider';
|
||||||
import { useTrialBalanceTableColumns } from './components';
|
import { useTrialBalanceSheetTableColumns } from './hooks';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trial Balance sheet data table.
|
* Trial Balance sheet data table.
|
||||||
@@ -17,12 +16,12 @@ import { useTrialBalanceTableColumns } from './components';
|
|||||||
export default function TrialBalanceSheetTable({ companyName }) {
|
export default function TrialBalanceSheetTable({ companyName }) {
|
||||||
// Trial balance sheet context.
|
// Trial balance sheet context.
|
||||||
const {
|
const {
|
||||||
trialBalanceSheet: { tableRows, query },
|
trialBalanceSheet: { table, query },
|
||||||
isLoading,
|
isLoading,
|
||||||
} = useTrialBalanceSheetContext();
|
} = useTrialBalanceSheetContext();
|
||||||
|
|
||||||
// Trial balance sheet table columns.
|
// Trial balance sheet table columns.
|
||||||
const columns = useTrialBalanceTableColumns();
|
const columns = useTrialBalanceSheetTableColumns();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FinancialSheet
|
<FinancialSheet
|
||||||
@@ -36,7 +35,7 @@ export default function TrialBalanceSheetTable({ companyName }) {
|
|||||||
>
|
>
|
||||||
<TrialBalanceDataTable
|
<TrialBalanceDataTable
|
||||||
columns={columns}
|
columns={columns}
|
||||||
data={tableRows}
|
data={table.rows}
|
||||||
expandable={true}
|
expandable={true}
|
||||||
expandToggleColumn={1}
|
expandToggleColumn={1}
|
||||||
expandColumnSpace={1}
|
expandColumnSpace={1}
|
||||||
@@ -59,7 +58,7 @@ const TrialBalanceDataTable = styled(ReportDataTable)`
|
|||||||
.balance.td {
|
.balance.td {
|
||||||
border-top-color: #000;
|
border-top-color: #000;
|
||||||
}
|
}
|
||||||
.tr.row_type--total .td {
|
.tr.row_type--TOTAL .td {
|
||||||
border-top: 1px solid #bbb;
|
border-top: 1px solid #bbb;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
border-bottom: 3px double #000;
|
border-bottom: 3px double #000;
|
||||||
|
|||||||
@@ -1,88 +1,10 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import React from 'react';
|
|
||||||
import intl from 'react-intl-universal';
|
|
||||||
import { Button } from '@blueprintjs/core';
|
import { Button } from '@blueprintjs/core';
|
||||||
|
|
||||||
import { Align } from '@/constants';
|
|
||||||
import { getColumnWidth } from '@/utils';
|
|
||||||
import { CellTextSpan } from '@/components/Datatable/Cells';
|
|
||||||
import { If, Icon, FormattedMessage as T } from '@/components';
|
import { If, Icon, FormattedMessage as T } from '@/components';
|
||||||
import { useTrialBalanceSheetContext } from './TrialBalanceProvider';
|
import { useTrialBalanceSheetContext } from './TrialBalanceProvider';
|
||||||
import { FinancialComputeAlert } from '../FinancialReportPage';
|
import { FinancialComputeAlert } from '../FinancialReportPage';
|
||||||
import FinancialLoadingBar from '../FinancialLoadingBar';
|
import FinancialLoadingBar from '../FinancialLoadingBar';
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the credit column.
|
|
||||||
*/
|
|
||||||
const getCreditColumn = (data) => {
|
|
||||||
const width = getColumnWidth(data, `credit`, { minWidth: 140 });
|
|
||||||
|
|
||||||
return {
|
|
||||||
Header: intl.get('credit'),
|
|
||||||
Cell: CellTextSpan,
|
|
||||||
accessor: 'formatted_credit',
|
|
||||||
className: 'credit',
|
|
||||||
width,
|
|
||||||
textOverview: true,
|
|
||||||
align: Align.Right,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the debit column.
|
|
||||||
*/
|
|
||||||
const getDebitColumn = (data) => {
|
|
||||||
return {
|
|
||||||
Header: intl.get('debit'),
|
|
||||||
Cell: CellTextSpan,
|
|
||||||
accessor: 'formatted_debit',
|
|
||||||
width: getColumnWidth(data, `debit`, { minWidth: 140 }),
|
|
||||||
textOverview: true,
|
|
||||||
align: Align.Right,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the balance column.
|
|
||||||
*/
|
|
||||||
const getBalanceColumn = (data) => {
|
|
||||||
return {
|
|
||||||
Header: intl.get('balance'),
|
|
||||||
Cell: CellTextSpan,
|
|
||||||
accessor: 'formatted_balance',
|
|
||||||
className: 'balance',
|
|
||||||
width: getColumnWidth(data, `balance`, { minWidth: 140 }),
|
|
||||||
textOverview: true,
|
|
||||||
align: Align.Right,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve trial balance sheet table columns.
|
|
||||||
*/
|
|
||||||
export const useTrialBalanceTableColumns = () => {
|
|
||||||
// Trial balance sheet context.
|
|
||||||
const {
|
|
||||||
trialBalanceSheet: { tableRows },
|
|
||||||
} = useTrialBalanceSheetContext();
|
|
||||||
|
|
||||||
return React.useMemo(
|
|
||||||
() => [
|
|
||||||
{
|
|
||||||
Header: intl.get('account_name'),
|
|
||||||
accessor: (row) => (row.code ? `${row.name} - ${row.code}` : row.name),
|
|
||||||
className: 'name',
|
|
||||||
width: 350,
|
|
||||||
textOverview: true,
|
|
||||||
},
|
|
||||||
getCreditColumn(tableRows),
|
|
||||||
getDebitColumn(tableRows),
|
|
||||||
getBalanceColumn(tableRows),
|
|
||||||
],
|
|
||||||
[tableRows],
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trial balance sheet progress loading bar.
|
* Trial balance sheet progress loading bar.
|
||||||
*/
|
*/
|
||||||
@@ -101,7 +23,7 @@ export function TrialBalanceSheetLoadingBar() {
|
|||||||
*/
|
*/
|
||||||
export function TrialBalanceSheetAlerts() {
|
export function TrialBalanceSheetAlerts() {
|
||||||
const {
|
const {
|
||||||
trialBalanceSheet: { meta },
|
trialBalanceSheet,
|
||||||
isLoading,
|
isLoading,
|
||||||
refetchSheet,
|
refetchSheet,
|
||||||
} = useTrialBalanceSheetContext();
|
} = useTrialBalanceSheetContext();
|
||||||
@@ -115,7 +37,7 @@ export function TrialBalanceSheetAlerts() {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// Can't continue if the cost compute job is not running.
|
// Can't continue if the cost compute job is not running.
|
||||||
if (!meta.is_cost_compute_running) {
|
if (!trialBalanceSheet?.meta.is_cost_compute_running) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
import * as R from 'ramda';
|
||||||
|
import { Align } from '@/constants';
|
||||||
|
import { getColumnWidth } from '@/utils';
|
||||||
|
|
||||||
|
const ACCOUNT_NAME_COLUMN_WIDTH = 320;
|
||||||
|
const AMOUNT_COLUMNS_MIN_WIDTH = 120;
|
||||||
|
const AMOUNT_COLUMNS_MAGIC_SPACING = 10;
|
||||||
|
|
||||||
|
const getTableCellValueAccessor = (index: number) => `cells[${index}].value`;
|
||||||
|
|
||||||
|
const accountNameAccessor = R.curry((data, column) => {
|
||||||
|
const accessor = getTableCellValueAccessor(column.cell_index);
|
||||||
|
|
||||||
|
return {
|
||||||
|
Header: column.label,
|
||||||
|
id: column.key,
|
||||||
|
accessor,
|
||||||
|
className: column.key,
|
||||||
|
width: ACCOUNT_NAME_COLUMN_WIDTH,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const amountAccessor = R.curry((data, column) => {
|
||||||
|
const accessor = getTableCellValueAccessor(column.cell_index);
|
||||||
|
|
||||||
|
return {
|
||||||
|
Header: column.label,
|
||||||
|
id: column.key,
|
||||||
|
accessor,
|
||||||
|
className: column.key,
|
||||||
|
width: getColumnWidth(data, accessor, {
|
||||||
|
magicSpacing: AMOUNT_COLUMNS_MAGIC_SPACING,
|
||||||
|
minWidth: AMOUNT_COLUMNS_MIN_WIDTH,
|
||||||
|
}),
|
||||||
|
align: Align.Right,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const dynamicColumnMapper = R.curry((data, column) => {
|
||||||
|
const accountNameColumn = accountNameAccessor(data);
|
||||||
|
const creditColumn = amountAccessor(data);
|
||||||
|
const debitColumn = amountAccessor(data);
|
||||||
|
const totalColumn = amountAccessor(data);
|
||||||
|
|
||||||
|
return R.compose(
|
||||||
|
R.when(R.pathEq(['key'], 'account_name'), accountNameColumn),
|
||||||
|
R.when(R.pathEq(['key'], 'credit'), creditColumn),
|
||||||
|
R.when(R.pathEq(['key'], 'debit'), debitColumn),
|
||||||
|
R.when(R.pathEq(['key'], 'total'), totalColumn),
|
||||||
|
)(column);
|
||||||
|
});
|
||||||
|
|
||||||
|
export const trialBalancesheetDynamicColumns = (columns, data) => {
|
||||||
|
return R.map(dynamicColumnMapper(data), columns);
|
||||||
|
};
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
import React from 'react';
|
||||||
|
import { useTrialBalanceSheetContext } from './TrialBalanceProvider';
|
||||||
|
import { trialBalancesheetDynamicColumns } from './dynamicColumns';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the trial balance sheet columns.
|
||||||
|
*/
|
||||||
|
export const useTrialBalanceSheetTableColumns = () => {
|
||||||
|
const {
|
||||||
|
trialBalanceSheet: { table },
|
||||||
|
} = useTrialBalanceSheetContext();
|
||||||
|
|
||||||
|
return React.useMemo(
|
||||||
|
() => trialBalancesheetDynamicColumns(table.columns, table.rows),
|
||||||
|
[table],
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -6,6 +6,9 @@ const Schema = Yup.object().shape({
|
|||||||
name: Yup.string()
|
name: Yup.string()
|
||||||
.required()
|
.required()
|
||||||
.label(intl.get('organization_name_')),
|
.label(intl.get('organization_name_')),
|
||||||
|
tax_number: Yup.string()
|
||||||
|
.nullable()
|
||||||
|
.label(intl.get('organization_tax_number_')),
|
||||||
industry: Yup.string()
|
industry: Yup.string()
|
||||||
.nullable()
|
.nullable()
|
||||||
.label(intl.get('organization_industry_')),
|
.label(intl.get('organization_industry_')),
|
||||||
|
|||||||
@@ -59,6 +59,17 @@ export default function PreferencesGeneralForm({ isSubmitting }) {
|
|||||||
<FInputGroup medium={'true'} name={'name'} fastField={true} />
|
<FInputGroup medium={'true'} name={'name'} fastField={true} />
|
||||||
</FFormGroup>
|
</FFormGroup>
|
||||||
|
|
||||||
|
{/* ---------- Organization Tax Number ---------- */}
|
||||||
|
<FFormGroup
|
||||||
|
name={'tax_number'}
|
||||||
|
label={<T id={'organization_tax_number'} />}
|
||||||
|
inline={true}
|
||||||
|
helperText={<T id={'shown_on_sales_forms_and_purchase_orders'} />}
|
||||||
|
fastField={true}
|
||||||
|
>
|
||||||
|
<FInputGroup medium={'true'} name={'tax_number'} fastField={true} />
|
||||||
|
</FFormGroup>
|
||||||
|
|
||||||
{/* ---------- Industry ---------- */}
|
{/* ---------- Industry ---------- */}
|
||||||
<FFormGroup
|
<FFormGroup
|
||||||
name={'industry'}
|
name={'industry'}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ const defaultValues = {
|
|||||||
fiscal_year: '',
|
fiscal_year: '',
|
||||||
date_format: '',
|
date_format: '',
|
||||||
timezone: '',
|
timezone: '',
|
||||||
|
tax_number: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -43,17 +43,12 @@ export function useTrialBalanceSheet(query, props) {
|
|||||||
method: 'get',
|
method: 'get',
|
||||||
url: '/financial_statements/trial_balance_sheet',
|
url: '/financial_statements/trial_balance_sheet',
|
||||||
params: query,
|
params: query,
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json+table',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
select: (res) => ({
|
select: (res) => res.data,
|
||||||
tableRows: trialBalanceSheetReducer(res.data.data),
|
|
||||||
...res.data,
|
|
||||||
}),
|
|
||||||
defaultData: {
|
|
||||||
tableRows: [],
|
|
||||||
data: [],
|
|
||||||
query: {},
|
|
||||||
},
|
|
||||||
...props,
|
...props,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
"success": "Success",
|
"success": "Success",
|
||||||
"register_a_new_organization": "Register a New Organization.",
|
"register_a_new_organization": "Register a New Organization.",
|
||||||
"organization_name": "Organization Name",
|
"organization_name": "Organization Name",
|
||||||
|
"organization_tax_number": "Organization Tax Number",
|
||||||
"email": "Email",
|
"email": "Email",
|
||||||
"email_address": "Email Address",
|
"email_address": "Email Address",
|
||||||
"register": "Register",
|
"register": "Register",
|
||||||
@@ -339,6 +340,7 @@
|
|||||||
"item_type_": "Item type",
|
"item_type_": "Item type",
|
||||||
"item_name_": "Item name",
|
"item_name_": "Item name",
|
||||||
"organization_industry_": "Organization industry",
|
"organization_industry_": "Organization industry",
|
||||||
|
"organization_tax_number_": "Organization tax number",
|
||||||
"base_currency_": "Base currency",
|
"base_currency_": "Base currency",
|
||||||
"date_format_": "Date format",
|
"date_format_": "Date format",
|
||||||
"category_name_": "Category name",
|
"category_name_": "Category name",
|
||||||
@@ -1804,6 +1806,7 @@
|
|||||||
"balance_sheet.total_change": "Total Change",
|
"balance_sheet.total_change": "Total Change",
|
||||||
"balance_sheet.change": "% Change",
|
"balance_sheet.change": "% Change",
|
||||||
"balance_sheet.previous_period": "Previous Period (PP)",
|
"balance_sheet.previous_period": "Previous Period (PP)",
|
||||||
|
"balance_sheet.net_income": "Net Income",
|
||||||
"profit_loss_sheet.comparisons": "Comparisons",
|
"profit_loss_sheet.comparisons": "Comparisons",
|
||||||
"profit_loss_sheet.dimensions": "Dimensions",
|
"profit_loss_sheet.dimensions": "Dimensions",
|
||||||
"profit_loss_sheet.previous_year": "Previous Year",
|
"profit_loss_sheet.previous_year": "Previous Year",
|
||||||
|
|||||||
Reference in New Issue
Block a user