mirror of
https://github.com/frappe/books.git
synced 2024-12-23 03:19:01 +00:00
Reports
- Common FinancialStatementsView - Add BalanceSheet - Add Fiscal Year in Accounting Settings
This commit is contained in:
parent
3da7b7169a
commit
180825243f
@ -21,6 +21,8 @@ module.exports = {
|
|||||||
frappe.desk.menu.addItem('Contact', "#list/Contact");
|
frappe.desk.menu.addItem('Contact', "#list/Contact");
|
||||||
frappe.desk.menu.addItem('Settings', () => frappe.desk.showFormModal('SystemSettings'));
|
frappe.desk.menu.addItem('Settings', () => frappe.desk.showFormModal('SystemSettings'));
|
||||||
frappe.desk.menu.addItem('General Ledger', '#report/general-ledger');
|
frappe.desk.menu.addItem('General Ledger', '#report/general-ledger');
|
||||||
|
frappe.desk.menu.addItem('Profit And Loss', '#report/profit-and-loss');
|
||||||
|
frappe.desk.menu.addItem('Balance Sheet', '#report/balance-sheet');
|
||||||
|
|
||||||
frappe.router.default = '#tree/Account';
|
frappe.router.default = '#tree/Account';
|
||||||
|
|
||||||
|
@ -63,7 +63,9 @@ async function saveSetupWizardValues(values) {
|
|||||||
name,
|
name,
|
||||||
email,
|
email,
|
||||||
abbreviation,
|
abbreviation,
|
||||||
bankName
|
bankName,
|
||||||
|
fiscalYearStart,
|
||||||
|
fiscalYearEnd
|
||||||
} = values;
|
} = values;
|
||||||
|
|
||||||
const doc = await frappe.getDoc('AccountingSettings');
|
const doc = await frappe.getDoc('AccountingSettings');
|
||||||
@ -73,6 +75,8 @@ async function saveSetupWizardValues(values) {
|
|||||||
await doc.set('fullname', name);
|
await doc.set('fullname', name);
|
||||||
await doc.set('email', email);
|
await doc.set('email', email);
|
||||||
await doc.set('bankName', bankName);
|
await doc.set('bankName', bankName);
|
||||||
|
await doc.set('fiscalYearStart', fiscalYearStart);
|
||||||
|
await doc.set('fiscalYearEnd', fiscalYearEnd);
|
||||||
|
|
||||||
await doc.update();
|
await doc.update();
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,21 @@ module.exports = {
|
|||||||
"label": "Bank Name",
|
"label": "Bank Name",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"required": 1
|
"required": 1
|
||||||
}
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"fieldname": "fiscalYearStart",
|
||||||
|
"label": "Fiscal Year Start Date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"required": 1
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"fieldname": "fiscalYearEnd",
|
||||||
|
"label": "Fiscal Year End Date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"required": 1
|
||||||
|
},
|
||||||
|
|
||||||
]
|
]
|
||||||
}
|
}
|
@ -21,6 +21,7 @@
|
|||||||
"postinstall": "electron-builder install-app-deps"
|
"postinstall": "electron-builder install-app-deps"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"frappe-datatable": "../datatable",
|
||||||
"frappejs": "../frappejs"
|
"frappejs": "../frappejs"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
53
reports/BalanceSheet/BalanceSheet.js
Normal file
53
reports/BalanceSheet/BalanceSheet.js
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
const frappe = require('frappejs');
|
||||||
|
const { unique } = require('frappejs/utils');
|
||||||
|
const { getData } = require('../FinancialStatements/FinancialStatements');
|
||||||
|
|
||||||
|
class BalanceSheet {
|
||||||
|
async run({ fromDate, toDate, periodicity }) {
|
||||||
|
|
||||||
|
let asset = await getData({
|
||||||
|
rootType: 'Asset',
|
||||||
|
balanceMustBe: 'Debit',
|
||||||
|
fromDate,
|
||||||
|
toDate,
|
||||||
|
periodicity,
|
||||||
|
accumulateValues: true
|
||||||
|
});
|
||||||
|
|
||||||
|
let liability = await getData({
|
||||||
|
rootType: 'Liability',
|
||||||
|
balanceMustBe: 'Credit',
|
||||||
|
fromDate,
|
||||||
|
toDate,
|
||||||
|
periodicity,
|
||||||
|
accumulateValues: true
|
||||||
|
});
|
||||||
|
|
||||||
|
let equity = await getData({
|
||||||
|
rootType: 'Equity',
|
||||||
|
balanceMustBe: 'Credit',
|
||||||
|
fromDate,
|
||||||
|
toDate,
|
||||||
|
periodicity,
|
||||||
|
accumulateValues: true
|
||||||
|
});
|
||||||
|
|
||||||
|
const rows = [
|
||||||
|
...asset.accounts, asset.totalRow, [],
|
||||||
|
...liability.accounts, liability.totalRow, [],
|
||||||
|
...equity.accounts, equity.totalRow, []
|
||||||
|
];
|
||||||
|
|
||||||
|
const columns = unique([
|
||||||
|
...asset.periodList,
|
||||||
|
...liability.periodList,
|
||||||
|
...equity.periodList
|
||||||
|
]);
|
||||||
|
|
||||||
|
return { rows, columns };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function execute(params) {
|
||||||
|
return new BalanceSheet().run(params);
|
||||||
|
}
|
16
reports/BalanceSheet/BalanceSheetView.js
Normal file
16
reports/BalanceSheet/BalanceSheetView.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
const frappe = require('frappejs');
|
||||||
|
const FinancialStatementsView = require('../FinancialStatements/FinancialStatementsView');
|
||||||
|
|
||||||
|
module.exports = class BalanceSheetView extends FinancialStatementsView {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
title: frappe._('Balance Sheet'),
|
||||||
|
method: 'balance-sheet',
|
||||||
|
filterFields: [
|
||||||
|
{fieldtype: 'Date', label: 'To Date', required: 1},
|
||||||
|
{fieldtype: 'Select', options: ['Monthly', 'Quarterly', 'Half Yearly', 'Yearly'],
|
||||||
|
label: 'Periodicity', fieldname: 'periodicity', default: 'Monthly'}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
214
reports/FinancialStatements/FinancialStatements.js
Normal file
214
reports/FinancialStatements/FinancialStatements.js
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
const frappe = require('frappejs');
|
||||||
|
const { DateTime } = require('luxon');
|
||||||
|
const { unique } = require('frappejs/utils');
|
||||||
|
|
||||||
|
async function getData({
|
||||||
|
rootType,
|
||||||
|
balanceMustBe = 'Debit',
|
||||||
|
fromDate,
|
||||||
|
toDate,
|
||||||
|
periodicity = 'Monthly',
|
||||||
|
accumulateValues = false
|
||||||
|
}) {
|
||||||
|
|
||||||
|
let accounts = await getAccounts(rootType);
|
||||||
|
let fiscalYear = await getFiscalYear();
|
||||||
|
let ledgerEntries = await getLedgerEntries(fromDate, toDate, accounts);
|
||||||
|
let periodList = getPeriodList(fromDate, toDate, periodicity, fiscalYear);
|
||||||
|
|
||||||
|
for (let account of accounts) {
|
||||||
|
const entries = ledgerEntries.filter(entry => entry.account === account.name);
|
||||||
|
|
||||||
|
for (let entry of entries) {
|
||||||
|
let periodKey = getPeriodKey(entry.date, periodicity);
|
||||||
|
|
||||||
|
if (!account[periodKey]) {
|
||||||
|
account[periodKey] = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const multiplier = balanceMustBe === 'Debit' ? 1 : -1;
|
||||||
|
const value = (entry.debit - entry.credit) * multiplier
|
||||||
|
account[periodKey] += value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accumulateValues) {
|
||||||
|
periodList.forEach((periodKey, i) => {
|
||||||
|
if (i === 0) return;
|
||||||
|
const previousPeriodKey = periodList[i - 1];
|
||||||
|
|
||||||
|
for (let account of accounts) {
|
||||||
|
if (!account[periodKey]) {
|
||||||
|
account[periodKey] = 0.0;
|
||||||
|
}
|
||||||
|
account[periodKey] += account[previousPeriodKey] || 0.0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate totalRow
|
||||||
|
let totalRow = {
|
||||||
|
account: `Total ${rootType} (${balanceMustBe})`
|
||||||
|
};
|
||||||
|
|
||||||
|
periodList.forEach((periodKey) => {
|
||||||
|
if (!totalRow[periodKey]) {
|
||||||
|
totalRow[periodKey] = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let account of accounts) {
|
||||||
|
totalRow[periodKey] += account[periodKey] || 0.0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { accounts, totalRow, periodList };
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPeriodList(fromDate, toDate, periodicity, fiscalYear) {
|
||||||
|
if (!fromDate) {
|
||||||
|
fromDate = fiscalYear.start;
|
||||||
|
}
|
||||||
|
|
||||||
|
let monthsToAdd = {
|
||||||
|
'Monthly': 1,
|
||||||
|
'Quarterly': 3,
|
||||||
|
'Half Yearly': 6,
|
||||||
|
'Yearly': 12
|
||||||
|
}[periodicity];
|
||||||
|
|
||||||
|
let startDate = DateTime.fromISO(fromDate).startOf('month');
|
||||||
|
let endDate = DateTime.fromISO(toDate).endOf('month');
|
||||||
|
let curDate = startDate;
|
||||||
|
let out = [];
|
||||||
|
|
||||||
|
while (curDate <= endDate) {
|
||||||
|
out.push(getPeriodKey(curDate, periodicity));
|
||||||
|
curDate = curDate.plus({ months: monthsToAdd });
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPeriodKey(date, periodicity) {
|
||||||
|
let key;
|
||||||
|
let dateObj = DateTime.fromISO(date);
|
||||||
|
let year = dateObj.year;
|
||||||
|
let quarter = dateObj.quarter;
|
||||||
|
let month = dateObj.month;
|
||||||
|
|
||||||
|
let getKey = {
|
||||||
|
'Monthly': () => `${dateObj.monthShort} ${year}`,
|
||||||
|
'Quarterly': () => {
|
||||||
|
return {
|
||||||
|
1: `Jan ${year} - Mar ${year}`,
|
||||||
|
2: `Apr ${year} - Jun ${year}`,
|
||||||
|
3: `Jun ${year} - Sep ${year}`,
|
||||||
|
4: `Oct ${year} - Dec ${year}`
|
||||||
|
}[quarter]
|
||||||
|
},
|
||||||
|
'Half Yearly': () => {
|
||||||
|
return {
|
||||||
|
1: `Apr ${year} - Sep ${year}`,
|
||||||
|
2: `Oct ${year} - Mar ${year}`
|
||||||
|
}[[2, 3].includes(quarter) ? 1 : 2]
|
||||||
|
},
|
||||||
|
'Yearly': () => {
|
||||||
|
if (month > 3) {
|
||||||
|
return `${year} - ${year + 1}`
|
||||||
|
}
|
||||||
|
return `${year - 1} - ${year}`
|
||||||
|
}
|
||||||
|
}[periodicity];
|
||||||
|
|
||||||
|
return getKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setIndentLevel(accounts, parentAccount, level) {
|
||||||
|
if (!parentAccount) {
|
||||||
|
// root
|
||||||
|
parentAccount = null;
|
||||||
|
level = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
accounts.forEach(account => {
|
||||||
|
if (account.parentAccount === parentAccount && account.indent === undefined) {
|
||||||
|
account.indent = level;
|
||||||
|
setIndentLevel(accounts, account.name, level + 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return accounts;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sortAccounts(accounts) {
|
||||||
|
let out = [];
|
||||||
|
let pushed = {};
|
||||||
|
|
||||||
|
pushToOut(null);
|
||||||
|
|
||||||
|
function pushToOut(parentAccount) {
|
||||||
|
accounts.forEach(account => {
|
||||||
|
if (account.parentAccount === parentAccount && !pushed[account.name]) {
|
||||||
|
out.push(account);
|
||||||
|
pushed[account.name] = 1;
|
||||||
|
|
||||||
|
pushToOut(account.name);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getLedgerEntries(fromDate, toDate, accounts) {
|
||||||
|
const dateFilter = () => {
|
||||||
|
const before = ['<=', toDate];
|
||||||
|
const after = ['>=', fromDate];
|
||||||
|
if (fromDate) {
|
||||||
|
return [...after, ...before];
|
||||||
|
}
|
||||||
|
return before;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ledgerEntries = await frappe.db.getAll({
|
||||||
|
doctype: 'AccountingLedgerEntry',
|
||||||
|
fields: ['account', 'debit', 'credit', 'date'],
|
||||||
|
filters: {
|
||||||
|
account: ['in', accounts.map(d => d.name)],
|
||||||
|
date: dateFilter()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return ledgerEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getAccounts(rootType) {
|
||||||
|
let accounts = await frappe.db.getAll({
|
||||||
|
doctype: 'Account',
|
||||||
|
fields: ['name', 'parentAccount'],
|
||||||
|
filters: {
|
||||||
|
rootType
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
accounts = setIndentLevel(accounts);
|
||||||
|
accounts = sortAccounts(accounts);
|
||||||
|
|
||||||
|
accounts.forEach(account => {
|
||||||
|
account.account = account.name;
|
||||||
|
});
|
||||||
|
|
||||||
|
return accounts;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getFiscalYear() {
|
||||||
|
let { fiscalYearStart, fiscalYearEnd } = await frappe.getSingle('AccountingSettings');
|
||||||
|
return {
|
||||||
|
start: fiscalYearStart,
|
||||||
|
end: fiscalYearEnd
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getData
|
||||||
|
}
|
41
reports/FinancialStatements/FinancialStatementsView.js
Normal file
41
reports/FinancialStatements/FinancialStatementsView.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
const ReportPage = require('frappejs/client/desk/reportpage');
|
||||||
|
const frappe = require('frappejs');
|
||||||
|
const { unique } = require('frappejs/utils');
|
||||||
|
|
||||||
|
module.exports = class FinancialStatementsView extends ReportPage {
|
||||||
|
constructor(opts) {
|
||||||
|
super({
|
||||||
|
title: opts.title,
|
||||||
|
filterFields: opts.filterFields
|
||||||
|
});
|
||||||
|
|
||||||
|
this.method = opts.method;
|
||||||
|
this.datatableOptions = {
|
||||||
|
treeView: true,
|
||||||
|
layout: 'fixed'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getRowsForDataTable(data) {
|
||||||
|
return data.rows || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
getColumns(data) {
|
||||||
|
const columns = [
|
||||||
|
{ label: 'Account', fieldtype: 'Data', fieldname: 'account', width: 340 }
|
||||||
|
];
|
||||||
|
|
||||||
|
if (data && data.columns) {
|
||||||
|
const currencyColumns = data.columns;
|
||||||
|
const columnDefs = currencyColumns.map(name => ({
|
||||||
|
label: name,
|
||||||
|
fieldname: name,
|
||||||
|
fieldtype: 'Currency'
|
||||||
|
}));
|
||||||
|
|
||||||
|
columns.push(...columnDefs);
|
||||||
|
}
|
||||||
|
|
||||||
|
return columns;
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
const frappe = require('frappejs');
|
const frappe = require('frappejs');
|
||||||
const { getData } = require('../financialStatements');
|
const { unique } = require('frappejs/utils');
|
||||||
|
const { getData } = require('../FinancialStatements/FinancialStatements');
|
||||||
|
|
||||||
class ProfitAndLoss {
|
class ProfitAndLoss {
|
||||||
async run({ fromDate, toDate, periodicity }) {
|
async run({ fromDate, toDate, periodicity }) {
|
||||||
@ -20,7 +21,24 @@ class ProfitAndLoss {
|
|||||||
periodicity
|
periodicity
|
||||||
});
|
});
|
||||||
|
|
||||||
return { income, expense };
|
const rows = [
|
||||||
|
...income.accounts, income.totalRow, [],
|
||||||
|
...expense.accounts, expense.totalRow, []
|
||||||
|
];
|
||||||
|
|
||||||
|
const columns = unique([...income.periodList, ...expense.periodList])
|
||||||
|
|
||||||
|
let profitRow = {
|
||||||
|
account: 'Total Profit'
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let column of columns) {
|
||||||
|
profitRow[column] = (income.totalRow[column] || 0.0) - (expense.totalRow[column] || 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
rows.push(profitRow);
|
||||||
|
|
||||||
|
return { rows, columns };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,93 +1,17 @@
|
|||||||
const ReportPage = require('frappejs/client/desk/reportpage');
|
|
||||||
const frappe = require('frappejs');
|
const frappe = require('frappejs');
|
||||||
const { unique } = require('frappejs/utils');
|
const FinancialStatementsView = require('../FinancialStatements/FinancialStatementsView');
|
||||||
|
|
||||||
module.exports = class ProfitAndLossView extends ReportPage {
|
module.exports = class ProfitAndLossView extends FinancialStatementsView {
|
||||||
constructor() {
|
constructor() {
|
||||||
super({
|
super({
|
||||||
title: frappe._('Profit and Loss'),
|
title: frappe._('Profit and Loss'),
|
||||||
|
method: 'profit-and-loss',
|
||||||
filterFields: [
|
filterFields: [
|
||||||
{fieldtype: 'Date', label: 'From Date', required: 1},
|
{fieldtype: 'Date', label: 'From Date', required: 1},
|
||||||
{fieldtype: 'Date', label: 'To Date', required: 1},
|
{fieldtype: 'Date', label: 'To Date', required: 1},
|
||||||
{fieldtype: 'Select', options: ['Monthly', 'Quarterly', 'Half Yearly', 'Yearly'],
|
{fieldtype: 'Select', options: ['Monthly', 'Quarterly', 'Half Yearly', 'Yearly'],
|
||||||
label: 'Periodicity', fieldname: 'periodicity'}
|
label: 'Periodicity', fieldname: 'periodicity', default: 'Monthly'}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
this.method = 'profit-and-loss';
|
|
||||||
this.datatableOptions = {
|
|
||||||
treeView: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getRowsForDataTable(data) {
|
|
||||||
const { expense, income } = data;
|
|
||||||
const rows = [];
|
|
||||||
|
|
||||||
rows.push({
|
|
||||||
account: 'Income',
|
|
||||||
indent: 0
|
|
||||||
});
|
|
||||||
for (let account of Object.keys(income)) {
|
|
||||||
const row = {
|
|
||||||
account,
|
|
||||||
indent: 1
|
|
||||||
};
|
|
||||||
for (let periodKey of Object.keys(income[account] || {})) {
|
|
||||||
row[periodKey] = income[account][periodKey];
|
|
||||||
}
|
|
||||||
rows.push(row);
|
|
||||||
}
|
|
||||||
|
|
||||||
rows.push({
|
|
||||||
account: 'Expense',
|
|
||||||
indent: 0
|
|
||||||
});
|
|
||||||
for (let account of Object.keys(expense)) {
|
|
||||||
const row = {
|
|
||||||
account,
|
|
||||||
indent: 1
|
|
||||||
};
|
|
||||||
for (let periodKey of Object.keys(expense[account] || {})) {
|
|
||||||
row[periodKey] = expense[account][periodKey];
|
|
||||||
}
|
|
||||||
rows.push(row);
|
|
||||||
}
|
|
||||||
|
|
||||||
return rows;
|
|
||||||
}
|
|
||||||
|
|
||||||
getColumns(data) {
|
|
||||||
debugger
|
|
||||||
const columns = [
|
|
||||||
{ label: 'Account', fieldtype: 'Data' }
|
|
||||||
];
|
|
||||||
|
|
||||||
if (data) {
|
|
||||||
const { income, expense } = data;
|
|
||||||
let currencyColumns = [];
|
|
||||||
|
|
||||||
for (let account of Object.keys(income)) {
|
|
||||||
const periods = Object.keys(income[account] || {});
|
|
||||||
currencyColumns.push(...periods);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let account of Object.keys(expense)) {
|
|
||||||
const periods = Object.keys(expense[account] || {});
|
|
||||||
currencyColumns.push(...periods);
|
|
||||||
}
|
|
||||||
|
|
||||||
currencyColumns = unique(currencyColumns);
|
|
||||||
|
|
||||||
const columnDefs = currencyColumns.map(name => ({
|
|
||||||
label: name,
|
|
||||||
fieldname: name,
|
|
||||||
fieldtype: 'Currency'
|
|
||||||
}));
|
|
||||||
|
|
||||||
columns.push(...columnDefs);
|
|
||||||
}
|
|
||||||
|
|
||||||
return columns;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,91 +0,0 @@
|
|||||||
const frappe = require('frappejs');
|
|
||||||
const { DateTime } = require('luxon');
|
|
||||||
|
|
||||||
async function getData({
|
|
||||||
rootType,
|
|
||||||
balanceMustBe = 'Debit',
|
|
||||||
fromDate,
|
|
||||||
toDate,
|
|
||||||
periodicity = 'Monthly'
|
|
||||||
}) {
|
|
||||||
|
|
||||||
const accounts = await getAccounts(rootType);
|
|
||||||
if (!accounts || accounts.length === 0) return [];
|
|
||||||
|
|
||||||
const ledgerEntries = await frappe.db.getAll({
|
|
||||||
doctype: 'AccountingLedgerEntry',
|
|
||||||
fields: ['account', 'debit', 'credit', 'date'],
|
|
||||||
filters: {
|
|
||||||
account: ['in', accounts],
|
|
||||||
date: ['>=', fromDate, '<=', toDate]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let data = {};
|
|
||||||
|
|
||||||
for (let entry of ledgerEntries) {
|
|
||||||
let periodKey = getPeriodKey(entry.date, periodicity);
|
|
||||||
|
|
||||||
if (!data[entry.account]) {
|
|
||||||
data[entry.account] = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!data[entry.account][periodKey]) {
|
|
||||||
data[entry.account][periodKey] = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const multiplier = balanceMustBe === 'Debit' ? 1 : -1;
|
|
||||||
data[entry.account][periodKey] += (entry.debit - entry.credit) * multiplier;
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPeriodKey(date, periodicity) {
|
|
||||||
let key;
|
|
||||||
let dateObj = DateTime.fromISO(date);
|
|
||||||
let year = dateObj.year;
|
|
||||||
let quarter = dateObj.quarter;
|
|
||||||
let month = dateObj.month;
|
|
||||||
|
|
||||||
let getKey = {
|
|
||||||
'Monthly': () => `${dateObj.monthShort} ${year}`,
|
|
||||||
'Quarterly': () => {
|
|
||||||
return {
|
|
||||||
1: `Jan ${year} - Mar ${year}`,
|
|
||||||
2: `Apr ${year} - Jun ${year}`,
|
|
||||||
3: `Jun ${year} - Sep ${year}`,
|
|
||||||
4: `Oct ${year} - Dec ${year}`
|
|
||||||
}[quarter]
|
|
||||||
},
|
|
||||||
'Half Yearly': () => {
|
|
||||||
return {
|
|
||||||
1: `Apr ${year} - Sep ${year}`,
|
|
||||||
2: `Oct ${year} - Mar ${year}`
|
|
||||||
}[[2, 3].includes(quarter) ? 1 : 2]
|
|
||||||
},
|
|
||||||
'Yearly': () => {
|
|
||||||
if (month > 3) {
|
|
||||||
return `${year} - ${year + 1}`
|
|
||||||
}
|
|
||||||
return `${year - 1} - ${year}`
|
|
||||||
}
|
|
||||||
}[periodicity];
|
|
||||||
|
|
||||||
return getKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getAccounts(rootType) {
|
|
||||||
return (await frappe.db.getAll({
|
|
||||||
doctype: 'Account',
|
|
||||||
fields: ['name'],
|
|
||||||
filters: {
|
|
||||||
rootType
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
.map(d => d.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
getData
|
|
||||||
}
|
|
@ -24,13 +24,13 @@ module.exports = class GeneralLedgerView extends ReportPage {
|
|||||||
return [
|
return [
|
||||||
{label: 'Date', fieldtype: 'Date'},
|
{label: 'Date', fieldtype: 'Date'},
|
||||||
{label: 'Account', fieldtype: 'Link'},
|
{label: 'Account', fieldtype: 'Link'},
|
||||||
|
{label: 'Debit', fieldtype: 'Currency'},
|
||||||
|
{label: 'Credit', fieldtype: 'Currency'},
|
||||||
|
{label: 'Balance', fieldtype: 'Currency'},
|
||||||
{label: 'Reference Type', fieldtype: 'Data'},
|
{label: 'Reference Type', fieldtype: 'Data'},
|
||||||
{label: 'Reference Name', fieldtype: 'Data'},
|
{label: 'Reference Name', fieldtype: 'Data'},
|
||||||
{label: 'Party', fieldtype: 'Link'},
|
{label: 'Party', fieldtype: 'Link'},
|
||||||
{label: 'Description', fieldtype: 'Data'},
|
{label: 'Description', fieldtype: 'Data'},
|
||||||
{label: 'Debit', fieldtype: 'Currency'},
|
|
||||||
{label: 'Credit', fieldtype: 'Currency'},
|
|
||||||
{label: 'Balance', fieldtype: 'Currency'}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,9 @@ const GeneralLedgerView = require('../reports/generalLedger/GeneralLedgerView');
|
|||||||
const ProfitAndLoss = require('./ProfitAndLoss/ProfitAndLoss');
|
const ProfitAndLoss = require('./ProfitAndLoss/ProfitAndLoss');
|
||||||
const ProfitAndLossView = require('./ProfitAndLoss/ProfitAndLossView');
|
const ProfitAndLossView = require('./ProfitAndLoss/ProfitAndLossView');
|
||||||
|
|
||||||
|
const BalanceSheet = require('./BalanceSheet/BalanceSheet');
|
||||||
|
const BalanceSheetView = require('./BalanceSheet/BalanceSheetView');
|
||||||
|
|
||||||
// called on server side
|
// called on server side
|
||||||
function registerReportMethods() {
|
function registerReportMethods() {
|
||||||
frappe.registerMethod({
|
frappe.registerMethod({
|
||||||
@ -17,6 +20,11 @@ function registerReportMethods() {
|
|||||||
method: 'profit-and-loss',
|
method: 'profit-and-loss',
|
||||||
handler: args => ProfitAndLoss(args)
|
handler: args => ProfitAndLoss(args)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
frappe.registerMethod({
|
||||||
|
method: 'balance-sheet',
|
||||||
|
handler: args => BalanceSheet(args)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// called on client side
|
// called on client side
|
||||||
@ -34,6 +42,13 @@ function registerReportRoutes() {
|
|||||||
}
|
}
|
||||||
await frappe.views.ProfitAndLoss.show(params);
|
await frappe.views.ProfitAndLoss.show(params);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
frappe.router.add('report/balance-sheet', async (params) => {
|
||||||
|
if (!frappe.views.BalanceSheet) {
|
||||||
|
frappe.views.BalanceSheet = new BalanceSheetView();
|
||||||
|
}
|
||||||
|
await frappe.views.BalanceSheet.show(params);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
@ -46,7 +46,21 @@ module.exports = {
|
|||||||
"label": "Bank Name",
|
"label": "Bank Name",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"required": 1
|
"required": 1
|
||||||
}
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"fieldname": "fiscalYearStart",
|
||||||
|
"label": "Fiscal Year Start Date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"required": 1
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"fieldname": "fiscalYearEnd",
|
||||||
|
"label": "Fiscal Year End Date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"required": 1
|
||||||
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
layout: [
|
layout: [
|
||||||
@ -67,7 +81,7 @@ module.exports = {
|
|||||||
|
|
||||||
{
|
{
|
||||||
title: 'Add your Company',
|
title: 'Add your Company',
|
||||||
fields: ['companyName', 'bankName']
|
fields: ['companyName', 'bankName', 'fiscalYearStart', 'fiscalYearEnd']
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
317
www/dist/css/style.css
vendored
317
www/dist/css/style.css
vendored
@ -7130,40 +7130,160 @@ div.CodeMirror-dragcursors {
|
|||||||
/* Help users use markselection to safely style text background */
|
/* Help users use markselection to safely style text background */
|
||||||
span.CodeMirror-selectedtext {
|
span.CodeMirror-selectedtext {
|
||||||
background: none; }
|
background: none; }
|
||||||
/* This file is processed by postcss */
|
.datatable *, .datatable *::after, .datatable *::before {
|
||||||
/* variables */
|
|
||||||
.data-table {
|
|
||||||
/* styling */
|
|
||||||
position: relative;
|
|
||||||
overflow: auto; }
|
|
||||||
/* resets */
|
|
||||||
.data-table *, .data-table *::after, .data-table *::before {
|
|
||||||
-webkit-box-sizing: border-box;
|
-webkit-box-sizing: border-box;
|
||||||
box-sizing: border-box; }
|
box-sizing: border-box; }
|
||||||
.data-table button, .data-table input {
|
.datatable {
|
||||||
|
position: relative;
|
||||||
|
overflow: auto; }
|
||||||
|
.dt-header {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-bottom: 1px solid #d1d8dd;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
background-color: #fff; }
|
||||||
|
.dt-body {
|
||||||
|
border-collapse: collapse; }
|
||||||
|
.dt-scrollable {
|
||||||
|
max-height: 40vw;
|
||||||
|
overflow: auto;
|
||||||
|
border-bottom: 1px solid #d1d8dd; }
|
||||||
|
.dt-scrollable--highlight-all {
|
||||||
|
background-color: #fffce7; }
|
||||||
|
.dt-scrollable__no-data {
|
||||||
|
text-align: center;
|
||||||
|
padding: 16px;
|
||||||
|
padding: 1rem;
|
||||||
|
border-left: 1px solid #d1d8dd;
|
||||||
|
border-right: 1px solid #d1d8dd; }
|
||||||
|
.dt-row--highlight {
|
||||||
|
background-color: #fffce7; }
|
||||||
|
.dt-row--unhighlight {
|
||||||
|
background-color: #fff; }
|
||||||
|
.dt-row--hide {
|
||||||
|
display: none; }
|
||||||
|
.dt-cell {
|
||||||
|
border: 1px solid #d1d8dd;
|
||||||
|
position: relative;
|
||||||
|
outline: none;
|
||||||
|
padding: 0; }
|
||||||
|
.dt-cell__content {
|
||||||
|
padding: 8px;
|
||||||
|
padding: 0.5rem;
|
||||||
|
border: 2px solid transparent;
|
||||||
|
height: 100%;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden; }
|
||||||
|
.dt-cell__edit {
|
||||||
|
display: none;
|
||||||
|
padding: 8px;
|
||||||
|
padding: 0.5rem;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 2px solid #ffa00a;
|
||||||
|
z-index: 1;
|
||||||
|
height: 100%; }
|
||||||
|
.dt-cell__resize-handle {
|
||||||
|
opacity: 0;
|
||||||
|
position: absolute;
|
||||||
|
right: -3px;
|
||||||
|
top: 0;
|
||||||
|
width: 5px;
|
||||||
|
height: 100%;
|
||||||
|
cursor: col-resize;
|
||||||
|
z-index: 1; }
|
||||||
|
.dt-cell--editing .dt-cell__content {
|
||||||
|
display: none; }
|
||||||
|
.dt-cell--editing .dt-cell__edit {
|
||||||
|
display: block; }
|
||||||
|
.dt-cell--focus .dt-cell__content {
|
||||||
|
border-color: #5292f7; }
|
||||||
|
.dt-cell--highlight {
|
||||||
|
background-color: #f5f7fa; }
|
||||||
|
.dt-cell--dragging {
|
||||||
|
background-color: #f5f7fa; }
|
||||||
|
.dt-cell--header .dt-cell__content {
|
||||||
|
padding-right: 16px;
|
||||||
|
padding-right: 1rem;
|
||||||
|
font-weight: bold; }
|
||||||
|
.dt-cell--header:hover .dt-dropdown__toggle {
|
||||||
|
opacity: 1; }
|
||||||
|
.dt-cell--tree-close .dt-tree-node__toggle:before {
|
||||||
|
content: '►'; }
|
||||||
|
.dt-dropdown {
|
||||||
|
position: absolute;
|
||||||
|
right: 10px;
|
||||||
|
display: -webkit-inline-box;
|
||||||
|
display: -ms-inline-flexbox;
|
||||||
|
display: inline-flex;
|
||||||
|
vertical-align: top;
|
||||||
|
text-align: left;
|
||||||
|
font-weight: normal;
|
||||||
|
cursor: pointer; }
|
||||||
|
.dt-dropdown__toggle {
|
||||||
|
opacity: 0; }
|
||||||
|
.dt-dropdown__list {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
min-width: 128px;
|
||||||
|
min-width: 8rem;
|
||||||
|
top: 100%;
|
||||||
|
right: 0;
|
||||||
|
z-index: 1;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 8px 0;
|
||||||
|
padding: 0.5rem 0;
|
||||||
|
-webkit-box-shadow: 0 2px 3px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1);
|
||||||
|
box-shadow: 0 2px 3px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1); }
|
||||||
|
.dt-dropdown__list-item {
|
||||||
|
padding: 8px 16px;
|
||||||
|
padding: 0.5rem 1rem; }
|
||||||
|
.dt-dropdown__list-item:hover {
|
||||||
|
background-color: #f5f7fa; }
|
||||||
|
.dt-dropdown--active .dt-dropdown__list {
|
||||||
|
display: block; }
|
||||||
|
.dt-tree-node {
|
||||||
|
display: inline-block;
|
||||||
|
position: relative; }
|
||||||
|
.dt-tree-node__toggle {
|
||||||
|
display: inline-block;
|
||||||
|
position: absolute;
|
||||||
|
font-size: 10px;
|
||||||
|
padding: 0 4px;
|
||||||
|
cursor: pointer; }
|
||||||
|
.dt-tree-node__toggle:before {
|
||||||
|
content: '▼'; }
|
||||||
|
.dt-toast {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 16px;
|
||||||
|
bottom: 1rem;
|
||||||
|
left: 50%;
|
||||||
|
-webkit-transform: translateX(-50%);
|
||||||
|
transform: translateX(-50%); }
|
||||||
|
.dt-toast__message {
|
||||||
|
display: inline-block;
|
||||||
|
background-color: rgba(0, 0, 0, 0.8);
|
||||||
|
color: #dfe2e5;
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 8px 16px;
|
||||||
|
padding: 0.5rem 1rem; }
|
||||||
|
.dt-input {
|
||||||
|
outline: none;
|
||||||
|
width: 100%;
|
||||||
|
border: none;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
font-size: inherit;
|
font-size: inherit;
|
||||||
line-height: inherit;
|
line-height: inherit;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0; }
|
padding: 0; }
|
||||||
.data-table .input-style {
|
.dt-freeze {
|
||||||
outline: none;
|
|
||||||
width: 100%;
|
|
||||||
border: none; }
|
|
||||||
.data-table *, .data-table *:focus {
|
|
||||||
outline: none;
|
|
||||||
border-radius: 0px;
|
|
||||||
-webkit-box-shadow: none;
|
|
||||||
box-shadow: none; }
|
|
||||||
.data-table table {
|
|
||||||
border-collapse: collapse; }
|
|
||||||
.data-table table td {
|
|
||||||
padding: 0;
|
|
||||||
border: 1px solid #d1d8dd; }
|
|
||||||
.data-table thead td {
|
|
||||||
border-bottom-width: 1px; }
|
|
||||||
.data-table .freeze-container {
|
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
display: -ms-flexbox;
|
display: -ms-flexbox;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -7180,150 +7300,15 @@ span.CodeMirror-selectedtext {
|
|||||||
background-color: #f5f7fa;
|
background-color: #f5f7fa;
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
font-size: 2em; }
|
font-size: 2em; }
|
||||||
.data-table .freeze-container span {
|
.dt-freeze__message {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
-webkit-transform: translateY(-50%);
|
-webkit-transform: translateY(-50%);
|
||||||
transform: translateY(-50%); }
|
transform: translateY(-50%); }
|
||||||
.data-table .hide {
|
.dt-paste-target {
|
||||||
display: none; }
|
position: fixed;
|
||||||
.data-table .toast-message {
|
left: -999em; }
|
||||||
position: absolute;
|
body.dt-resize {
|
||||||
bottom: 16px;
|
|
||||||
bottom: 1rem;
|
|
||||||
left: 50%;
|
|
||||||
-webkit-transform: translateX(-50%);
|
|
||||||
transform: translateX(-50%); }
|
|
||||||
.data-table .toast-message span {
|
|
||||||
display: inline-block;
|
|
||||||
background-color: rgba(0, 0, 0, 0.8);
|
|
||||||
color: #dfe2e5;
|
|
||||||
border-radius: 3px;
|
|
||||||
padding: 8px 16px;
|
|
||||||
padding: 0.5rem 1rem; }
|
|
||||||
.body-scrollable {
|
|
||||||
max-height: 500px;
|
|
||||||
overflow: auto;
|
|
||||||
border-bottom: 1px solid #d1d8dd; }
|
|
||||||
.body-scrollable.row-highlight-all .data-table-row:not(.row-unhighlight) {
|
|
||||||
background-color: #f5f7fa; }
|
|
||||||
.body-scrollable .no-data td {
|
|
||||||
text-align: center;
|
|
||||||
padding: 8px;
|
|
||||||
padding: 0.5rem; }
|
|
||||||
.data-table-header {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
background-color: white;
|
|
||||||
font-weight: bold; }
|
|
||||||
.data-table-header .content span:not(.column-resizer) {
|
|
||||||
cursor: pointer; }
|
|
||||||
.data-table-header .column-resizer {
|
|
||||||
display: none;
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
width: 4px;
|
|
||||||
width: 0.25rem;
|
|
||||||
height: 100%;
|
|
||||||
background-color: #5292f7;
|
|
||||||
cursor: col-resize; }
|
|
||||||
.data-table-header .data-table-dropdown {
|
|
||||||
position: absolute;
|
|
||||||
right: 10px;
|
|
||||||
display: -webkit-inline-box;
|
|
||||||
display: -ms-inline-flexbox;
|
|
||||||
display: inline-flex;
|
|
||||||
vertical-align: top;
|
|
||||||
text-align: left; }
|
|
||||||
.data-table-header .data-table-dropdown.is-active .data-table-dropdown-list {
|
|
||||||
display: block; }
|
|
||||||
.data-table-header .data-table-dropdown.is-active .data-table-dropdown-toggle {
|
|
||||||
display: block; }
|
|
||||||
.data-table-header .data-table-dropdown-toggle {
|
|
||||||
display: none;
|
|
||||||
background-color: transparent;
|
|
||||||
border: none; }
|
|
||||||
.data-table-header .data-table-dropdown-list {
|
|
||||||
display: none;
|
|
||||||
font-weight: normal;
|
|
||||||
position: absolute;
|
|
||||||
min-width: 128px;
|
|
||||||
min-width: 8rem;
|
|
||||||
top: 100%;
|
|
||||||
right: 0;
|
|
||||||
z-index: 1;
|
|
||||||
background-color: white;
|
|
||||||
border-radius: 3px;
|
|
||||||
-webkit-box-shadow: 0 2px 3px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1);
|
|
||||||
box-shadow: 0 2px 3px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1);
|
|
||||||
padding-bottom: 8px;
|
|
||||||
padding-bottom: 0.5rem;
|
|
||||||
padding-top: 8px;
|
|
||||||
padding-top: 0.5rem; }
|
|
||||||
.data-table-header .data-table-dropdown-list > div {
|
|
||||||
padding: 8px 16px;
|
|
||||||
padding: 0.5rem 1rem; }
|
|
||||||
.data-table-header .data-table-dropdown-list > div:hover {
|
|
||||||
background-color: #f5f7fa; }
|
|
||||||
.data-table-header .data-table-cell.remove-column {
|
|
||||||
background-color: #FD8B8B;
|
|
||||||
-webkit-transition: 300ms background-color ease-in-out;
|
|
||||||
transition: 300ms background-color ease-in-out; }
|
|
||||||
.data-table-header .data-table-cell.sortable-chosen {
|
|
||||||
background-color: #f5f7fa; }
|
|
||||||
.data-table-cell {
|
|
||||||
position: relative; }
|
|
||||||
.data-table-cell .content {
|
|
||||||
padding: 8px;
|
|
||||||
padding: 0.5rem;
|
|
||||||
border: 2px solid transparent; }
|
|
||||||
.data-table-cell .content.ellipsis {
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden; }
|
|
||||||
.data-table-cell .edit-cell {
|
|
||||||
display: none;
|
|
||||||
padding: 8px;
|
|
||||||
padding: 0.5rem;
|
|
||||||
background: #fff;
|
|
||||||
z-index: 1;
|
|
||||||
height: 100%; }
|
|
||||||
.data-table-cell.selected .content {
|
|
||||||
border: 2px solid #5292f7; }
|
|
||||||
.data-table-cell.editing .content {
|
|
||||||
display: none; }
|
|
||||||
.data-table-cell.editing .edit-cell {
|
|
||||||
border: 2px solid #5292f7;
|
|
||||||
display: block; }
|
|
||||||
.data-table-cell.highlight {
|
|
||||||
background-color: #f5f7fa; }
|
|
||||||
.data-table-cell:hover .column-resizer {
|
|
||||||
display: inline-block; }
|
|
||||||
.data-table-cell:hover .data-table-dropdown-toggle {
|
|
||||||
display: block; }
|
|
||||||
.data-table-cell .tree-node {
|
|
||||||
display: inline-block;
|
|
||||||
position: relative; }
|
|
||||||
.data-table-cell .toggle {
|
|
||||||
display: inline-block;
|
|
||||||
position: absolute;
|
|
||||||
padding: 0 4px;
|
|
||||||
cursor: pointer; }
|
|
||||||
.data-table-cell .toggle:before {
|
|
||||||
content: '▼'; }
|
|
||||||
.data-table-cell.tree-close .toggle:before {
|
|
||||||
content: '►'; }
|
|
||||||
.data-table-row.row-highlight {
|
|
||||||
background-color: #f5f7fa; }
|
|
||||||
.noselect {
|
|
||||||
-webkit-touch-callout: none;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
-moz-user-select: none;
|
|
||||||
-ms-user-select: none;
|
|
||||||
user-select: none; }
|
|
||||||
body.data-table-resize {
|
|
||||||
cursor: col-resize; }
|
cursor: col-resize; }
|
||||||
.indicator, .indicator-right {
|
.indicator, .indicator-right {
|
||||||
background: none;
|
background: none;
|
||||||
|
8635
www/dist/js/bundle.js
vendored
8635
www/dist/js/bundle.js
vendored
File diff suppressed because it is too large
Load Diff
@ -2039,9 +2039,8 @@ fragment-cache@^0.2.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
map-cache "^0.2.2"
|
map-cache "^0.2.2"
|
||||||
|
|
||||||
frappe-datatable@frappe/datatable:
|
frappe-datatable@../datatable:
|
||||||
version "0.0.3"
|
version "0.0.5"
|
||||||
resolved "https://codeload.github.com/frappe/datatable/tar.gz/e5af37fb07ddaaa43cfb42dd84ac4f98d93816bc"
|
|
||||||
dependencies:
|
dependencies:
|
||||||
clusterize.js "^0.18.0"
|
clusterize.js "^0.18.0"
|
||||||
lodash "^4.17.5"
|
lodash "^4.17.5"
|
||||||
@ -2061,7 +2060,7 @@ frappejs@../frappejs:
|
|||||||
eslint "^4.19.1"
|
eslint "^4.19.1"
|
||||||
express "^4.16.2"
|
express "^4.16.2"
|
||||||
flatpickr "^4.3.2"
|
flatpickr "^4.3.2"
|
||||||
frappe-datatable frappe/datatable
|
frappe-datatable "../datatable"
|
||||||
frappejs "../frappejs"
|
frappejs "../frappejs"
|
||||||
jquery "^3.3.1"
|
jquery "^3.3.1"
|
||||||
luxon "^1.0.0"
|
luxon "^1.0.0"
|
||||||
|
Loading…
Reference in New Issue
Block a user