Cutomisable Cash Flow Reports (#12969)
* add child doctype - Cash Flow Mapping Account * adds new doctype - Cash Flow Mapping * adds new doctype - Cash Flow Mapper * adds new doctype Cash Flow Mapping Template * adds new doctype Cash Flow Mapping Template * adds adjustments to Cash Flow Mapper: - remove fields from Cash Flow Mapping Template Details - update in Cash FLow Mapper * get cash_flow_accouts from Cash Flow Mapping * change `tmp` to `mappers` and make sure `mappers` is sorted by its `position` field * changes description from 'Net Profit/Loss' to 'Profit for the year' * set `net_profit_loss` `parent_account` properly * modify `get_account_type_based_data`: - changed signature such that `account_type` parameter is now `account_name` - where clause in query is now based on `name` * remove zero rows * de-duplicates row, summing similar accounts in the process * makes gl sum calculation use `parent_account` as a condition * add the `section_leader` immediately after adding net profit, sorts `accounts` by `is_working_capital` field * adds `is_working_capital` to "account_types" so that we can use this to determine when to add "Changes in working capital" for operating activities * add "Movement in working capital" subheader * refactor code for readability * adds new fields to `Cash Flow Mapping`: - `is_interest_paid` to allow me recognise accounts for 'Interest Paid' - `is_income_tax_paid` to allow me recognise accounts for 'Income Taxes Paid' * allow `Cash Flow Mapping` to be renamable * adds new field - `section_subtotal` useful for only Operating Activities * changes `Cash Flow Mapping` doctype fields: - remove `is_income_tax`_field - add `is_income_tax_liability` field to identify tax payable accounts - add `is_income_tax_expense` field to identify tax expense accounts in P or L * calculates and shows tax paid adjustment in cash flow statement * renames `is_interest_paid` to `is_finance_cost` * - adds finance costs calculation - correctly sets opening balance dates * prevents users from selecting extra options in Cash Flow Mapping * adds validation to prevent selecting multiple options * adds new fields to Cash Flow Mapping * calculate non cash p or l items (2nd pass) * separates default cash flow generation from custom * adds new setting to Accounts Settings: - allow user elect to use customised cash flow report * clean up * removes mandatory constraint from accounts field * allow rename, disallow create and delete * adds patch to add default Cash Flow Mappers * refactors custom_cashflow * add article to explain configuration * refactor * further refactor * final clean up (hopefully) * clean up for codacy * more codacy fixes * more codacy fixes * fix broken patch * rename article to .md * create default mappers after install * PEP 8 * create the tables in `after_install` call
@ -514,6 +514,68 @@
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "report_settings_sb",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Report Settings",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "0",
|
||||
"description": "Only select if you have setup Cash Flow Mapper documents",
|
||||
"fieldname": "use_custom_cash_flow",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Use Custom Cash Flow Format",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
|
@ -0,0 +1,6 @@
|
||||
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Cash Flow Mapper', {
|
||||
|
||||
});
|
275
erpnext/accounts/doctype/cash_flow_mapper/cash_flow_mapper.json
Normal file
@ -0,0 +1,275 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 1,
|
||||
"autoname": "field:section_name",
|
||||
"beta": 0,
|
||||
"creation": "2018-02-08 10:00:14.066519",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_name",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Section Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_header",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Section Header",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "e.g Adjustments for:",
|
||||
"fieldname": "section_leader",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Section Leader",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_subtotal",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Section Subtotal",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_footer",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Section Footer",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "accounts",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Accounts",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Cash Flow Mapping Template Details",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "position",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Position",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-02-15 18:28:55.034933",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Cash Flow Mapper",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 0,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "name",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class CashFlowMapper(Document):
|
||||
pass
|
@ -0,0 +1,25 @@
|
||||
DEFAULT_MAPPERS = [
|
||||
{
|
||||
'doctype': 'Cash Flow Mapper',
|
||||
'section_footer': 'Net cash generated by operating activities',
|
||||
'section_header': 'Cash flows from operating activities',
|
||||
'section_leader': 'Adjustments for',
|
||||
'section_name': 'Operating Activities',
|
||||
'position': 0,
|
||||
'section_subtotal': 'Cash generated from operations',
|
||||
},
|
||||
{
|
||||
'doctype': 'Cash Flow Mapper',
|
||||
'position': 1,
|
||||
'section_footer': 'Net cash used in investing activities',
|
||||
'section_header': 'Cash flows from investing activities',
|
||||
'section_name': 'Investing Activities'
|
||||
},
|
||||
{
|
||||
'doctype': 'Cash Flow Mapper',
|
||||
'position': 2,
|
||||
'section_footer': 'Net cash used in financing activites',
|
||||
'section_header': 'Cash flows from financing activities',
|
||||
'section_name': 'Financing Activities',
|
||||
}
|
||||
]
|
@ -0,0 +1,23 @@
|
||||
/* eslint-disable */
|
||||
// rename this file from _test_[name] to test_[name] to activate
|
||||
// and remove above this line
|
||||
|
||||
QUnit.test("test: Cash Flow Mapper", function (assert) {
|
||||
let done = assert.async();
|
||||
|
||||
// number of asserts
|
||||
assert.expect(1);
|
||||
|
||||
frappe.run_serially([
|
||||
// insert a new Cash Flow Mapper
|
||||
() => frappe.tests.make('Cash Flow Mapper', [
|
||||
// values to be set
|
||||
{key: 'value'}
|
||||
]),
|
||||
() => {
|
||||
assert.equal(cur_frm.doc.key, 'value');
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
|
||||
});
|
@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import unittest
|
||||
|
||||
|
||||
class TestCashFlowMapper(unittest.TestCase):
|
||||
pass
|
@ -0,0 +1,43 @@
|
||||
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Cash Flow Mapping', {
|
||||
refresh: function(frm) {
|
||||
frm.events.disable_unchecked_fields(frm);
|
||||
},
|
||||
reset_check_fields: function(frm) {
|
||||
frm.fields.filter(field => field.df.fieldtype === 'Check')
|
||||
.map(field => frm.set_df_property(field.df.fieldname, 'read_only', 0));
|
||||
},
|
||||
has_checked_field(frm) {
|
||||
const val = frm.fields.filter(field => field.value === 1);
|
||||
return val.length ? 1 : 0;
|
||||
},
|
||||
_disable_unchecked_fields: function(frm) {
|
||||
// get value of clicked field
|
||||
frm.fields.filter(field => field.value === 0)
|
||||
.map(field => frm.set_df_property(field.df.fieldname, 'read_only', 1));
|
||||
},
|
||||
disable_unchecked_fields: function(frm) {
|
||||
frm.events.reset_check_fields(frm);
|
||||
const checked = frm.events.has_checked_field(frm);
|
||||
if (checked) {
|
||||
frm.events._disable_unchecked_fields(frm);
|
||||
}
|
||||
},
|
||||
is_working_capital: function(frm) {
|
||||
frm.events.disable_unchecked_fields(frm);
|
||||
},
|
||||
is_finance_cost: function(frm) {
|
||||
frm.events.disable_unchecked_fields(frm);
|
||||
},
|
||||
is_income_tax_liability: function(frm) {
|
||||
frm.events.disable_unchecked_fields(frm);
|
||||
},
|
||||
is_income_tax_expense: function(frm) {
|
||||
frm.events.disable_unchecked_fields(frm);
|
||||
},
|
||||
is_finance_cost_adjustment: function(frm) {
|
||||
frm.events.disable_unchecked_fields(frm);
|
||||
}
|
||||
});
|
@ -0,0 +1,359 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 1,
|
||||
"autoname": "field:mapping_name",
|
||||
"beta": 0,
|
||||
"creation": "2018-02-08 09:28:44.678364",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "mapping_name",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "label",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Label",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "accounts",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Accounts",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Cash Flow Mapping Accounts",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "sb_1",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Select Maximum Of 1",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "0",
|
||||
"fieldname": "is_finance_cost",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Is Finance Cost",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "0",
|
||||
"fieldname": "is_working_capital",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Is Working Capital",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "0",
|
||||
"fieldname": "is_finance_cost_adjustment",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Is Finance Cost Adjustment",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "0",
|
||||
"fieldname": "is_income_tax_liability",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Is Income Tax Liability",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "0",
|
||||
"fieldname": "is_income_tax_expense",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Is Income Tax Expense",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-02-15 08:25:18.693533",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Cash Flow Mapping",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Administrator",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "name",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class CashFlowMapping(Document):
|
||||
def validate(self):
|
||||
self.validate_checked_options()
|
||||
|
||||
def validate_checked_options(self):
|
||||
checked_fields = [d for d in self.meta.fields if d.fieldtype == 'Check' and self.get(d.fieldname) == 1]
|
||||
if len(checked_fields) > 1:
|
||||
frappe.throw(
|
||||
frappe._('You can only select a maximum of one option from the list of check boxes.'),
|
||||
title='Error'
|
||||
)
|
||||
|
||||
|
@ -0,0 +1,23 @@
|
||||
/* eslint-disable */
|
||||
// rename this file from _test_[name] to test_[name] to activate
|
||||
// and remove above this line
|
||||
|
||||
QUnit.test("test: Cash Flow Mapping", function (assert) {
|
||||
let done = assert.async();
|
||||
|
||||
// number of asserts
|
||||
assert.expect(1);
|
||||
|
||||
frappe.run_serially([
|
||||
// insert a new Cash Flow Mapping
|
||||
() => frappe.tests.make('Cash Flow Mapping', [
|
||||
// values to be set
|
||||
{key: 'value'}
|
||||
]),
|
||||
() => {
|
||||
assert.equal(cur_frm.doc.key, 'value');
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
|
||||
});
|
@ -0,0 +1,32 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
import unittest
|
||||
|
||||
|
||||
class TestCashFlowMapping(unittest.TestCase):
|
||||
def setUp(self):
|
||||
if frappe.db.exists("Cash Flow Mapping", "Test Mapping"):
|
||||
frappe.delete_doc('Cash Flow Mappping', 'Test Mapping')
|
||||
|
||||
def tearDown(self):
|
||||
frappe.delete_doc('Cash Flow Mapping', 'Test Mapping')
|
||||
|
||||
def test_multiple_selections_not_allowed(self):
|
||||
doc = frappe.new_doc('Cash Flow Mapping')
|
||||
doc.mapping_name = 'Test Mapping'
|
||||
doc.label = 'Test label'
|
||||
doc.append(
|
||||
'accounts',
|
||||
{'account': 'Accounts Receivable - _TC'}
|
||||
)
|
||||
doc.is_working_capital = 1
|
||||
doc.is_finance_cost = 1
|
||||
|
||||
self.assertRaises(frappe.ValidationError, doc.insert)
|
||||
|
||||
doc.is_finance_cost = 0
|
||||
doc.insert()
|
@ -0,0 +1,73 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"autoname": "field:account",
|
||||
"beta": 0,
|
||||
"creation": "2018-02-08 09:25:34.353995",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "account",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Account",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-02-08 09:25:34.353995",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Cash Flow Mapping Accounts",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class CashFlowMappingAccounts(Document):
|
||||
pass
|
@ -0,0 +1,6 @@
|
||||
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Cash Flow Mapping Template', {
|
||||
|
||||
});
|
@ -0,0 +1,123 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
"creation": "2018-02-08 10:20:18.316801",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "template_name",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Template Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "mapping",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Cash Flow Mapping",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Cash Flow Mapping Template Details",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-02-08 10:20:18.316801",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Cash Flow Mapping Template",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class CashFlowMappingTemplate(Document):
|
||||
pass
|
@ -0,0 +1,23 @@
|
||||
/* eslint-disable */
|
||||
// rename this file from _test_[name] to test_[name] to activate
|
||||
// and remove above this line
|
||||
|
||||
QUnit.test("test: Cash Flow Mapping Template", function (assert) {
|
||||
let done = assert.async();
|
||||
|
||||
// number of asserts
|
||||
assert.expect(1);
|
||||
|
||||
frappe.run_serially([
|
||||
// insert a new Cash Flow Mapping Template
|
||||
() => frappe.tests.make('Cash Flow Mapping Template', [
|
||||
// values to be set
|
||||
{key: 'value'}
|
||||
]),
|
||||
() => {
|
||||
assert.equal(cur_frm.doc.key, 'value');
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
|
||||
});
|
@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import unittest
|
||||
|
||||
|
||||
class TestCashFlowMappingTemplate(unittest.TestCase):
|
||||
pass
|
@ -0,0 +1,6 @@
|
||||
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Cash Flow Mapping Template Details', {
|
||||
|
||||
});
|
@ -0,0 +1,94 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"autoname": "field:mapping",
|
||||
"beta": 0,
|
||||
"creation": "2018-02-08 10:18:48.513608",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "mapping",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Mapping",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Cash Flow Mapping",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-02-08 10:33:39.413930",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Cash Flow Mapping Template Details",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class CashFlowMappingTemplateDetails(Document):
|
||||
pass
|
@ -0,0 +1,23 @@
|
||||
/* eslint-disable */
|
||||
// rename this file from _test_[name] to test_[name] to activate
|
||||
// and remove above this line
|
||||
|
||||
QUnit.test("test: Cash Flow Mapping Template Details", function (assert) {
|
||||
let done = assert.async();
|
||||
|
||||
// number of asserts
|
||||
assert.expect(1);
|
||||
|
||||
frappe.run_serially([
|
||||
// insert a new Cash Flow Mapping Template Details
|
||||
() => frappe.tests.make('Cash Flow Mapping Template Details', [
|
||||
// values to be set
|
||||
{key: 'value'}
|
||||
]),
|
||||
() => {
|
||||
assert.equal(cur_frm.doc.key, 'value');
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
|
||||
});
|
@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import unittest
|
||||
|
||||
|
||||
class TestCashFlowMappingTemplateDetails(unittest.TestCase):
|
||||
pass
|
@ -4,12 +4,17 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import cint
|
||||
from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data)
|
||||
from erpnext.accounts.report.profit_and_loss_statement.profit_and_loss_statement import get_net_profit_loss
|
||||
from erpnext.accounts.utils import get_fiscal_year
|
||||
|
||||
|
||||
def execute(filters=None):
|
||||
if cint(frappe.db.get_single_value('Accounts Settings', 'use_custom_cash_flow')):
|
||||
from erpnext.accounts.report.cash_flow.custom_cash_flow import execute as execute_custom
|
||||
return execute_custom(filters=filters)
|
||||
|
||||
period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
|
||||
filters.periodicity, filters.accumulated_values, filters.company)
|
||||
|
||||
@ -44,10 +49,7 @@ def execute(filters=None):
|
||||
}
|
||||
|
||||
# combine all cash flow accounts for iteration
|
||||
cash_flow_accounts = []
|
||||
cash_flow_accounts.append(operation_accounts)
|
||||
cash_flow_accounts.append(investing_accounts)
|
||||
cash_flow_accounts.append(financing_accounts)
|
||||
cash_flow_accounts = [operation_accounts, investing_accounts, financing_accounts]
|
||||
|
||||
# compute net profit / loss
|
||||
income = get_data(filters.company, "Income", "Credit", period_list,
|
||||
@ -100,6 +102,7 @@ def execute(filters=None):
|
||||
|
||||
return columns, data
|
||||
|
||||
|
||||
def get_account_type_based_data(company, account_type, period_list, accumulated_values):
|
||||
data = {}
|
||||
total = 0
|
||||
@ -127,6 +130,7 @@ def get_account_type_based_data(company, account_type, period_list, accumulated_
|
||||
data["total"] = total
|
||||
return data
|
||||
|
||||
|
||||
def get_start_date(period, accumulated_values, company):
|
||||
start_date = period["year_start_date"]
|
||||
if accumulated_values:
|
||||
@ -134,6 +138,7 @@ def get_start_date(period, accumulated_values, company):
|
||||
|
||||
return start_date
|
||||
|
||||
|
||||
def add_total_row_account(out, data, label, period_list, currency):
|
||||
total_row = {
|
||||
"account_name": "'" + _("{0}").format(label) + "'",
|
||||
|
443
erpnext/accounts/report/cash_flow/custom_cash_flow.py
Normal file
@ -0,0 +1,443 @@
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import add_to_date
|
||||
from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data)
|
||||
from erpnext.accounts.report.profit_and_loss_statement.profit_and_loss_statement import get_net_profit_loss
|
||||
|
||||
|
||||
def get_mapper_for(mappers, position):
|
||||
mapper_list = filter(lambda x: x['position'] == position, mappers)
|
||||
return mapper_list[0] if mapper_list else []
|
||||
|
||||
|
||||
def get_mappers_from_db():
|
||||
return frappe.get_all(
|
||||
'Cash Flow Mapper',
|
||||
fields=[
|
||||
'section_name', 'section_header', 'section_leader', 'section_subtotal',
|
||||
'section_footer', 'name', 'position'],
|
||||
order_by='position'
|
||||
)
|
||||
|
||||
|
||||
def get_accounts_in_mappers(mapping_names):
|
||||
return frappe.db.sql(
|
||||
'select cfma.name, cfm.label, cfm.is_working_capital, cfm.is_income_tax_liability, '
|
||||
'cfm.is_income_tax_expense, cfm.is_finance_cost, cfm.is_finance_cost_adjustment '
|
||||
'from `tabCash Flow Mapping Accounts` cfma '
|
||||
'join `tabCash Flow Mapping` cfm on cfma.parent=cfm.name '
|
||||
'where cfma.parent in %s '
|
||||
'order by cfm.is_working_capital',
|
||||
(mapping_names,)
|
||||
)
|
||||
|
||||
|
||||
def setup_mappers(mappers):
|
||||
cash_flow_accounts = []
|
||||
|
||||
for mapping in mappers:
|
||||
mapping['account_types'] = []
|
||||
mapping['tax_liabilities'] = []
|
||||
mapping['tax_expenses'] = []
|
||||
mapping['finance_costs'] = []
|
||||
mapping['finance_costs_adjustments'] = []
|
||||
doc = frappe.get_doc('Cash Flow Mapper', mapping['name'])
|
||||
mapping_names = [item.name for item in doc.accounts]
|
||||
|
||||
if not mapping_names:
|
||||
continue
|
||||
|
||||
accounts = get_accounts_in_mappers(mapping_names)
|
||||
|
||||
account_types = [
|
||||
dict(
|
||||
name=account[0], label=account[1], is_working_capital=account[2],
|
||||
is_income_tax_liability=account[3], is_income_tax_expense=account[4]
|
||||
) for account in accounts if not account[3]]
|
||||
|
||||
finance_costs_adjustments = [
|
||||
dict(
|
||||
name=account[0], label=account[1], is_finance_cost=account[5],
|
||||
is_finance_cost_adjustment=account[6]
|
||||
) for account in accounts if account[6]]
|
||||
|
||||
tax_liabilities = [
|
||||
dict(
|
||||
name=account[0], label=account[1], is_income_tax_liability=account[3],
|
||||
is_income_tax_expense=account[4]
|
||||
) for account in accounts if account[3]]
|
||||
|
||||
tax_expenses = [
|
||||
dict(
|
||||
name=account[0], label=account[1], is_income_tax_liability=account[3],
|
||||
is_income_tax_expense=account[4]
|
||||
) for account in accounts if account[4]]
|
||||
|
||||
finance_costs = [
|
||||
dict(
|
||||
name=account[0], label=account[1], is_finance_cost=account[5])
|
||||
for account in accounts if account[5]]
|
||||
|
||||
account_types_labels = sorted(
|
||||
set(
|
||||
[(d['label'], d['is_working_capital'], d['is_income_tax_liability'], d['is_income_tax_expense'])
|
||||
for d in account_types]
|
||||
),
|
||||
key=lambda x: x[1]
|
||||
)
|
||||
|
||||
fc_adjustment_labels = sorted(
|
||||
set(
|
||||
[(d['label'], d['is_finance_cost'], d['is_finance_cost_adjustment'])
|
||||
for d in finance_costs_adjustments if d['is_finance_cost_adjustment']]
|
||||
),
|
||||
key=lambda x: x[2]
|
||||
)
|
||||
|
||||
unique_liability_labels = sorted(
|
||||
set(
|
||||
[(d['label'], d['is_income_tax_liability'], d['is_income_tax_expense'])
|
||||
for d in tax_liabilities]
|
||||
),
|
||||
key=lambda x: x[0]
|
||||
)
|
||||
|
||||
unique_expense_labels = sorted(
|
||||
set(
|
||||
[(d['label'], d['is_income_tax_liability'], d['is_income_tax_expense'])
|
||||
for d in tax_expenses]
|
||||
),
|
||||
key=lambda x: x[0]
|
||||
)
|
||||
|
||||
unique_finance_costs_labels = sorted(
|
||||
set(
|
||||
[(d['label'], d['is_finance_cost']) for d in finance_costs]
|
||||
),
|
||||
key=lambda x: x[0]
|
||||
)
|
||||
|
||||
for label in account_types_labels:
|
||||
names = [d['name'] for d in account_types if d['label'] == label[0]]
|
||||
m = dict(label=label[0], names=names, is_working_capital=label[1])
|
||||
mapping['account_types'].append(m)
|
||||
|
||||
for label in fc_adjustment_labels:
|
||||
names = [d['name'] for d in finance_costs_adjustments if d['label'] == label[0]]
|
||||
m = dict(label=label[0], names=names)
|
||||
mapping['finance_costs_adjustments'].append(m)
|
||||
|
||||
for label in unique_liability_labels:
|
||||
names = [d['name'] for d in tax_liabilities if d['label'] == label[0]]
|
||||
m = dict(label=label[0], names=names, tax_liability=label[1], tax_expense=label[2])
|
||||
mapping['tax_liabilities'].append(m)
|
||||
|
||||
for label in unique_expense_labels:
|
||||
names = [d['name'] for d in tax_expenses if d['label'] == label[0]]
|
||||
m = dict(label=label[0], names=names, tax_liability=label[1], tax_expense=label[2])
|
||||
mapping['tax_expenses'].append(m)
|
||||
|
||||
for label in unique_finance_costs_labels:
|
||||
names = [d['name'] for d in finance_costs if d['label'] == label[0]]
|
||||
m = dict(label=label[0], names=names, is_finance_cost=label[1])
|
||||
mapping['finance_costs'].append(m)
|
||||
|
||||
cash_flow_accounts.append(mapping)
|
||||
|
||||
return cash_flow_accounts
|
||||
|
||||
|
||||
def add_data_for_operating_activities(
|
||||
filters, company_currency, profit_data, period_list, light_mappers, mapper, data):
|
||||
has_added_working_capital_header = False
|
||||
section_data = []
|
||||
|
||||
data.append({
|
||||
"account_name": mapper['section_header'],
|
||||
"parent_account": None,
|
||||
"indent": 0.0,
|
||||
"account": mapper['section_header']
|
||||
})
|
||||
|
||||
if profit_data:
|
||||
profit_data.update({
|
||||
"indent": 1,
|
||||
"parent_account": get_mapper_for(light_mappers, position=0)['section_header']
|
||||
})
|
||||
data.append(profit_data)
|
||||
section_data.append(profit_data)
|
||||
|
||||
data.append({
|
||||
"account_name": mapper["section_leader"],
|
||||
"parent_account": None,
|
||||
"indent": 1.0,
|
||||
"account": mapper["section_leader"]
|
||||
})
|
||||
|
||||
for account in mapper['account_types']:
|
||||
if account['is_working_capital'] and not has_added_working_capital_header:
|
||||
data.append({
|
||||
"account_name": 'Movement in working capital',
|
||||
"parent_account": None,
|
||||
"indent": 1.0,
|
||||
"account": ""
|
||||
})
|
||||
has_added_working_capital_header = True
|
||||
|
||||
account_data = _get_account_type_based_data(
|
||||
filters, account['names'], period_list, filters.accumulated_values)
|
||||
|
||||
if not account['is_working_capital']:
|
||||
for key in account_data:
|
||||
if key != 'total':
|
||||
account_data[key] *= -1
|
||||
|
||||
if account_data['total'] != 0:
|
||||
account_data.update({
|
||||
"account_name": account['label'],
|
||||
"account": account['names'],
|
||||
"indent": 1.0,
|
||||
"parent_account": mapper['section_header'],
|
||||
"currency": company_currency
|
||||
})
|
||||
data.append(account_data)
|
||||
section_data.append(account_data)
|
||||
|
||||
_add_total_row_account(
|
||||
data, section_data, mapper['section_subtotal'], period_list, company_currency, indent=1)
|
||||
|
||||
# calculate adjustment for tax paid and add to data
|
||||
if not mapper['tax_liabilities']:
|
||||
mapper['tax_liabilities'] = [
|
||||
dict(label='Income tax paid', names=[''], tax_liability=1, tax_expense=0)]
|
||||
|
||||
for account in mapper['tax_liabilities']:
|
||||
tax_paid = calculate_adjustment(
|
||||
filters, mapper['tax_liabilities'], mapper['tax_expenses'],
|
||||
filters.accumulated_values, period_list)
|
||||
|
||||
if tax_paid:
|
||||
tax_paid.update({
|
||||
'parent_account': mapper['section_header'],
|
||||
'currency': company_currency,
|
||||
'account_name': account['label'],
|
||||
'indent': 1.0
|
||||
})
|
||||
data.append(tax_paid)
|
||||
section_data.append(tax_paid)
|
||||
|
||||
if not mapper['finance_costs_adjustments']:
|
||||
mapper['finance_costs_adjustments'] = [dict(label='Interest Paid', names=[''])]
|
||||
|
||||
for account in mapper['finance_costs_adjustments']:
|
||||
interest_paid = calculate_adjustment(
|
||||
filters, mapper['finance_costs_adjustments'], mapper['finance_costs'],
|
||||
filters.accumulated_values, period_list
|
||||
)
|
||||
|
||||
if interest_paid:
|
||||
interest_paid.update({
|
||||
'parent_account': mapper['section_header'],
|
||||
'currency': company_currency,
|
||||
'account_name': account['label'],
|
||||
'indent': 1.0
|
||||
})
|
||||
data.append(interest_paid)
|
||||
section_data.append(interest_paid)
|
||||
|
||||
_add_total_row_account(
|
||||
data, section_data, mapper['section_footer'], period_list, company_currency)
|
||||
|
||||
|
||||
def calculate_adjustment(filters, non_expense_mapper, expense_mapper, use_accumulated_values, period_list):
|
||||
liability_accounts = [d['names'] for d in non_expense_mapper]
|
||||
expense_accounts = [d['names'] for d in expense_mapper]
|
||||
|
||||
non_expense_closing = _get_account_type_based_data(
|
||||
filters, liability_accounts, period_list, 0)
|
||||
|
||||
non_expense_opening = _get_account_type_based_data(
|
||||
filters, liability_accounts, period_list, use_accumulated_values, opening_balances=1)
|
||||
|
||||
expense_data = _get_account_type_based_data(
|
||||
filters, expense_accounts, period_list, use_accumulated_values)
|
||||
|
||||
data = _calculate_adjustment(non_expense_closing, non_expense_opening, expense_data)
|
||||
return data
|
||||
|
||||
|
||||
def _calculate_adjustment(non_expense_closing, non_expense_opening, expense_data):
|
||||
account_data = {}
|
||||
for month in non_expense_opening.keys():
|
||||
if non_expense_opening[month] and non_expense_closing[month]:
|
||||
account_data[month] = non_expense_opening[month] - expense_data[month] + non_expense_closing[month]
|
||||
elif expense_data[month]:
|
||||
account_data[month] = expense_data[month]
|
||||
|
||||
return account_data
|
||||
|
||||
|
||||
def add_data_for_other_activities(
|
||||
filters, company_currency, profit_data, period_list, light_mappers, mapper_list, data):
|
||||
for mapper in mapper_list:
|
||||
section_data = []
|
||||
data.append({
|
||||
"account_name": mapper['section_header'],
|
||||
"parent_account": None,
|
||||
"indent": 0.0,
|
||||
"account": mapper['section_header']
|
||||
})
|
||||
|
||||
for account in mapper['account_types']:
|
||||
account_data = _get_account_type_based_data(filters,
|
||||
account['names'], period_list, filters.accumulated_values)
|
||||
if account_data['total'] != 0:
|
||||
account_data.update({
|
||||
"account_name": account['label'],
|
||||
"account": account['names'],
|
||||
"indent": 1,
|
||||
"parent_account": mapper['section_header'],
|
||||
"currency": company_currency
|
||||
})
|
||||
data.append(account_data)
|
||||
section_data.append(account_data)
|
||||
|
||||
_add_total_row_account(data, section_data, mapper['section_footer'],
|
||||
period_list, company_currency)
|
||||
|
||||
|
||||
def compute_data(filters, company_currency, profit_data, period_list, light_mappers, full_mapper):
|
||||
data = []
|
||||
|
||||
operating_activities_mapper = get_mapper_for(light_mappers, position=0)
|
||||
other_mappers = [
|
||||
get_mapper_for(light_mappers, position=1),
|
||||
get_mapper_for(light_mappers, position=2)
|
||||
]
|
||||
|
||||
if operating_activities_mapper:
|
||||
add_data_for_operating_activities(
|
||||
filters, company_currency, profit_data, period_list, light_mappers,
|
||||
operating_activities_mapper, data
|
||||
)
|
||||
|
||||
if all(other_mappers):
|
||||
add_data_for_other_activities(
|
||||
filters, company_currency, profit_data, period_list, light_mappers, other_mappers, data
|
||||
)
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def execute(filters=None):
|
||||
period_list = get_period_list(
|
||||
filters.from_fiscal_year, filters.to_fiscal_year, filters.periodicity,
|
||||
filters.accumulated_values, filters.company
|
||||
)
|
||||
|
||||
mappers = get_mappers_from_db()
|
||||
|
||||
cash_flow_accounts = setup_mappers(mappers)
|
||||
|
||||
# compute net profit / loss
|
||||
income = get_data(
|
||||
filters.company, "Income", "Credit", period_list,
|
||||
accumulated_values=filters.accumulated_values, ignore_closing_entries=True,
|
||||
ignore_accumulated_values_for_fy=True
|
||||
)
|
||||
|
||||
expense = get_data(
|
||||
filters.company, "Expense", "Debit", period_list,
|
||||
accumulated_values=filters.accumulated_values, ignore_closing_entries=True,
|
||||
ignore_accumulated_values_for_fy=True
|
||||
)
|
||||
|
||||
net_profit_loss = get_net_profit_loss(income, expense, period_list, filters.company)
|
||||
|
||||
company_currency = frappe.db.get_value("Company", filters.company, "default_currency")
|
||||
|
||||
data = compute_data(filters, company_currency, net_profit_loss, period_list, mappers, cash_flow_accounts)
|
||||
|
||||
_add_total_row_account(data, data, _("Net Change in Cash"), period_list, company_currency)
|
||||
columns = get_columns(filters.periodicity, period_list, filters.accumulated_values, filters.company)
|
||||
|
||||
return columns, data
|
||||
|
||||
|
||||
def _get_account_type_based_data(filters, account_names, period_list, accumulated_values, opening_balances=0):
|
||||
from erpnext.accounts.report.cash_flow.cash_flow import get_start_date
|
||||
|
||||
company = filters.company
|
||||
data = {}
|
||||
total = 0
|
||||
for period in period_list:
|
||||
start_date = get_start_date(period, accumulated_values, company)
|
||||
|
||||
if opening_balances:
|
||||
date_info = dict(date=start_date)
|
||||
months_map = {'Monthly': -1, 'Quarterly': -3, 'Half-Yearly': -6}
|
||||
years_map = {'Yearly': -1}
|
||||
|
||||
if months_map.get(filters.periodicity):
|
||||
date_info.update(months=months_map[filters.periodicity])
|
||||
else:
|
||||
date_info.update(years=years_map[filters.periodicity])
|
||||
|
||||
if accumulated_values:
|
||||
start, end = add_to_date(start_date, years=-1), add_to_date(period['to_date'], years=-1)
|
||||
else:
|
||||
start, end = add_to_date(**date_info), add_to_date(**date_info)
|
||||
|
||||
gl_sum = frappe.db.sql_list("""
|
||||
select sum(credit) - sum(debit)
|
||||
from `tabGL Entry`
|
||||
where company=%s and posting_date >= %s and posting_date <= %s
|
||||
and voucher_type != 'Period Closing Voucher'
|
||||
and account in ( SELECT name FROM tabAccount WHERE name IN %s
|
||||
OR parent_account IN %s)
|
||||
""", (company, start, end, account_names, account_names))
|
||||
else:
|
||||
gl_sum = frappe.db.sql_list("""
|
||||
select sum(credit) - sum(debit)
|
||||
from `tabGL Entry`
|
||||
where company=%s and posting_date >= %s and posting_date <= %s
|
||||
and voucher_type != 'Period Closing Voucher'
|
||||
and account in ( SELECT name FROM tabAccount WHERE name IN %s
|
||||
OR parent_account IN %s)
|
||||
""", (company, start_date if accumulated_values else period['from_date'],
|
||||
period['to_date'], account_names, account_names))
|
||||
|
||||
if gl_sum and gl_sum[0]:
|
||||
amount = gl_sum[0]
|
||||
else:
|
||||
amount = 0
|
||||
|
||||
total += amount
|
||||
data.setdefault(period["key"], amount)
|
||||
|
||||
data["total"] = total
|
||||
return data
|
||||
|
||||
|
||||
def _add_total_row_account(out, data, label, period_list, currency, indent=0.0):
|
||||
total_row = {
|
||||
"indent": indent,
|
||||
"account_name": "'" + _("{0}").format(label) + "'",
|
||||
"account": "'" + _("{0}").format(label) + "'",
|
||||
"currency": currency
|
||||
}
|
||||
for row in data:
|
||||
if row.get("parent_account"):
|
||||
for period in period_list:
|
||||
total_row.setdefault(period.key, 0.0)
|
||||
total_row[period.key] += row.get(period.key, 0.0)
|
||||
|
||||
total_row.setdefault("total", 0.0)
|
||||
total_row["total"] += row["total"]
|
||||
|
||||
out.append(total_row)
|
||||
out.append({})
|
@ -36,8 +36,8 @@ def execute(filters=None):
|
||||
def get_net_profit_loss(income, expense, period_list, company):
|
||||
total = 0
|
||||
net_profit_loss = {
|
||||
"account_name": "'" + _("Net Profit / Loss") + "'",
|
||||
"account": "'" + _("Net Profit / Loss") + "'",
|
||||
"account_name": "'" + _("Profit for the year") + "'",
|
||||
"account": "'" + _("Profit for the year") + "'",
|
||||
"warn_if_negative": True,
|
||||
"currency": frappe.db.get_value("Company", company, "default_currency")
|
||||
}
|
||||
|
BIN
erpnext/docs/assets/img/articles/cash-flow-mapper-1.png
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
erpnext/docs/assets/img/articles/cash-flow-mapper-2.png
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
erpnext/docs/assets/img/articles/cash-flow-mapper-3.png
Normal file
After Width: | Height: | Size: 72 KiB |
BIN
erpnext/docs/assets/img/articles/cash-flow-mapper-4.png
Normal file
After Width: | Height: | Size: 66 KiB |
BIN
erpnext/docs/assets/img/articles/cash-flow-mapper-5.png
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
erpnext/docs/assets/img/articles/cash-flow-mapper-6.png
Normal file
After Width: | Height: | Size: 45 KiB |
BIN
erpnext/docs/assets/img/articles/cash-flow-mapping-1.png
Normal file
After Width: | Height: | Size: 42 KiB |
BIN
erpnext/docs/assets/img/articles/cash-flow-mapping-10.png
Normal file
After Width: | Height: | Size: 47 KiB |
BIN
erpnext/docs/assets/img/articles/cash-flow-mapping-2.png
Normal file
After Width: | Height: | Size: 44 KiB |
BIN
erpnext/docs/assets/img/articles/cash-flow-mapping-3.png
Normal file
After Width: | Height: | Size: 47 KiB |
BIN
erpnext/docs/assets/img/articles/cash-flow-mapping-4.png
Normal file
After Width: | Height: | Size: 50 KiB |
BIN
erpnext/docs/assets/img/articles/cash-flow-mapping-5.png
Normal file
After Width: | Height: | Size: 49 KiB |
BIN
erpnext/docs/assets/img/articles/cash-flow-mapping-7.png
Normal file
After Width: | Height: | Size: 45 KiB |
BIN
erpnext/docs/assets/img/articles/cash-flow-mapping-8.png
Normal file
After Width: | Height: | Size: 46 KiB |
BIN
erpnext/docs/assets/img/articles/cash-flow-mapping-9.png
Normal file
After Width: | Height: | Size: 62 KiB |
BIN
erpnext/docs/assets/img/articles/default-cash-flow-report.png
Normal file
After Width: | Height: | Size: 60 KiB |
BIN
erpnext/docs/assets/img/articles/final-cash-flow.png
Normal file
After Width: | Height: | Size: 65 KiB |
BIN
erpnext/docs/assets/img/articles/format-1.png
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
erpnext/docs/assets/img/articles/format-2.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
erpnext/docs/assets/img/articles/new-cash-flow-mapping.png
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
erpnext/docs/assets/img/articles/no-mappers.png
Normal file
After Width: | Height: | Size: 27 KiB |
@ -0,0 +1,156 @@
|
||||
# How To Customise Cash Flow Report
|
||||
|
||||
As your chart of accounts begins to get more complex and reporting standards change and evolve, the default cash flow
|
||||
report might no longer suffice. This is because ERPNext might not be able to accurately guess the classification and
|
||||
purpose of all accounts in the charts of accounts. Another gripe you might have is the inability to adjust the report
|
||||
format to fit your needs.
|
||||
|
||||
This will no longer be a problem because ERPNext now allows users to customise the cash flow report.
|
||||
|
||||
|
||||
## Technical Overview
|
||||
Customisation is made possible by the introduction of two new doctypes - Cash Flow Mapper and Cash Flow Mapping. Both
|
||||
doctypes contain the information required to generate a cash flow report.
|
||||
|
||||
Cash Flow Mapping shows how accounts in your charts of accounts map to a line item in your cash flow report while
|
||||
Cash Flow Mapper gets all the Cash Flow Mappings that relate to the three sections of a cash flow statement.
|
||||
|
||||
With this, you generate detailed cash flow reports to your requirements. This might not make a lot of sense but it will
|
||||
after we go through an example.
|
||||
|
||||
## Example
|
||||
### Background information
|
||||
Let's assume we have a fictitious company for which we want to generate a cash flow report.
|
||||
This is what the cash flow report looks like at the moment:
|
||||
<img alt="Default cash flow report" class="screenshot" src="{{docs_base_url}}/assets/img/articles/default-cash-flow-report.png">
|
||||
|
||||
We don't like the report for the following reasons:
|
||||
- The reporting format is too scant.
|
||||
- The 'Net Cash From Operations' figure is wrong
|
||||
|
||||
### Customisation Process
|
||||
|
||||
We wants the Cash Flow Report to look something similar to the format in the images below:
|
||||
<img alt="cash flow format 1" class="screenshot" src="{{docs_base_url}}/assets/img/articles/format-1.png">
|
||||
<img alt="cash flow format 1" class="screenshot" src="{{docs_base_url}}/assets/img/articles/format-2.png">
|
||||
|
||||
#### Activate Customised Cash Flow Report
|
||||
Do this in Accounts Settings by checking the 'Use Custom Cash Flow Format' checkbox. This will cause ERPNext to only
|
||||
use your custom format for cash flow reports.
|
||||
|
||||
After doing that, your cash flow report should look like this:
|
||||
<img alt="custom cash flow statement" class="screenshot" src="{{docs_base_url}}/assets/img/articles/no-mappers.png">
|
||||
|
||||
Move to the next section to build the report.
|
||||
|
||||
#### Create Cash Flow Mappings
|
||||
For each line, we need to create a Cash Flow Mapping document to represent it.
|
||||
|
||||
<img alt="new cash flow mapping form" class="screenshot" src="{{docs_base_url}}/assets/img/articles/new-cash-flow-mapping.png">
|
||||
|
||||
You can think of the Cash Flow Mapping as a representation of each line in the cash flow report. A Cash Flow Mapping
|
||||
is a child of a Cash Flow Mapper which will be explained later.
|
||||
|
||||
Let's start by creating Cash Flow Mappings that will represent the add back of non cash expenses already recodgnised in
|
||||
the Profit or Loss statement. We want them to appear on the cash statement as:
|
||||
- Income taxes recognised in profit or loss
|
||||
- Finance costs recognised in profit or loss
|
||||
- Depreciation of non-current assets
|
||||
|
||||
Start by opening a new Cash Flow Mapping form.
|
||||
|
||||
The fields in the Cash Flow Mapping doctype are:
|
||||
- **Name**: This something to identify this document. Name it something related to the label
|
||||
- **Label**: This is what will show in the cash flow statement
|
||||
- **Accounts**: This table contains all the accounts which this line relates to.
|
||||
|
||||
With this information, let's go ahead and create the Cash Flow Mapping Document for the line 'Income taxes recognised in profit or loss'
|
||||
|
||||
<img alt="custom cash flow statement" class="screenshot" src="{{docs_base_url}}/assets/img/articles/cash-flow-mapping-1.png">
|
||||
|
||||
I have named it 'Income Tax Charge' and given it a label 'Income taxes recognised in profit or loss'. We want this
|
||||
line to reflect income tax charges from our profit or loss statement. The account where this happens in our chart
|
||||
of account is named 'Income Taxes' (an expense) so I have added 'Income Taxes' into the accounts table. If you have
|
||||
more accounts representing income tax expenses, you should add all of them here.
|
||||
|
||||
Because Income Tax expense needs to be adjusted further in the cash flow statement, check the 'Is Income Tax Expense'
|
||||
checkbox. This is what will help ERPNext properly calculate the adjustments to be made.
|
||||
|
||||
*For best results, let parent accounts have child accounts that have the same treatment for cash flow reporting
|
||||
purposes because ERPNext will calculate net change of all children accounts in a situation where the selected account
|
||||
is a parent account.*
|
||||
|
||||
In the same way, I have created for the remaining two mappings.
|
||||
|
||||
<img alt="custom cash flow statement" class="screenshot" src="{{docs_base_url}}/assets/img/articles/cash-flow-mapping-2.png">
|
||||
|
||||
Finance costs also need to be adjusted so make sure to check the 'Is Finance Cost' checkbox.
|
||||
|
||||
<img alt="custom cash flow statement" class="screenshot" src="{{docs_base_url}}/assets/img/articles/cash-flow-mapping-3.png">
|
||||
|
||||
Next let's add Cash Flow Mapping for items that show changes in working capital:
|
||||
- Increase/(decrease) in other liabilities
|
||||
- (Increase)/decrease in trade and other receivables
|
||||
- Increase/(decrease) in trade and other payables
|
||||
- VAT payable
|
||||
- (Increase)/decrease in inventory
|
||||
|
||||
<img alt="custom cash flow statement" class="screenshot" src="{{docs_base_url}}/assets/img/articles/cash-flow-mapping-4.png">
|
||||
|
||||
<img alt="custom cash flow statement" class="screenshot" src="{{docs_base_url}}/assets/img/articles/cash-flow-mapping-5.png">
|
||||
|
||||
<img alt="custom cash flow statement" class="screenshot" src="{{docs_base_url}}/assets/img/articles/cash-flow-mapping-6.png">
|
||||
|
||||
<img alt="custom cash flow statement" class="screenshot" src="{{docs_base_url}}/assets/img/articles/cash-flow-mapping-7.png">
|
||||
|
||||
<img alt="custom cash flow statement" class="screenshot" src="{{docs_base_url}}/assets/img/articles/cash-flow-mapping-8.png">
|
||||
|
||||
Don't forget to tell ERPNext that these mappings represent changes in working capital by checking the 'Is Working
|
||||
Capital' checkbox.
|
||||
|
||||
At this point we have created all the mappings necessary for the Operating Activities section of our cash flow
|
||||
statement. However, ERPNext doesn't know that yet until we create Cash Flow Mapper documents. We'll create Cash Flow
|
||||
Mapper documents next.
|
||||
|
||||
|
||||
#### Create Cash Flow Mappers
|
||||
Cash Flow Mappers represents the sections of the cash flow statement. A standard cash flow statement has only three
|
||||
sections so when you view the Cash Flow Mapper list, you will that three have been created for you named:
|
||||
- Operating Activities
|
||||
- Financing Activities
|
||||
- Investing Activities
|
||||
|
||||
You will not be able to add or remove any of them but they are editable and can be renamed.
|
||||
<img alt="cash flow mapper list" class="screenshot" src="{{docs_base_url}}/assets/img/articles/cash-flow-mapper-2.png">
|
||||
|
||||
|
||||
Open the Operating Activities Cash Flow Mapper so we can add the Cash Flow Mappings we have created.
|
||||
|
||||
|
||||
- **Section Name**: This is the heading of the section.
|
||||
- **Section Leader**: This is the first sub-header immediately after the profit figure. Relates only to Operating
|
||||
Activities Cash Flow Mapper
|
||||
- **Section Subtotal**: This is the label for subtotal in the cash flow statement section. Relates only to Operating
|
||||
Activities Cash Flow Mapper
|
||||
- **Section Footer**: This is the label for the total in the cash flow statement section.
|
||||
- **Mapping**: This table contains all the Cash Flow Mappings related to the Cash Flow Mapper.
|
||||
|
||||
Now add all the Cash Flow Mappings you have created and Save. You should have something like this:
|
||||
<img alt="cash flow mapper for operating activities" class="screenshot" src="{{docs_base_url}}/assets/img/articles/cash-flow-mapper-4.png">
|
||||
|
||||
Refresh the cash flow statement and view the changes.
|
||||
<img alt="updated cash flow report" class="screenshot" src="{{docs_base_url}}/assets/img/articles/cash-flow-mapper-3.png">
|
||||
|
||||
Looks close to our requirements but we are not done yet. Create new mappings for 'Investing Activities' and 'Financing
|
||||
Activities' sections of the cash flow statement.
|
||||
|
||||
<img alt="cash flow mapping" class="screenshot" src="{{docs_base_url}}/assets/img/articles/cash-flow-mapping-9.png">
|
||||
|
||||
<img alt="cash flow mapping" class="screenshot" src="{{docs_base_url}}/assets/img/articles/cash-flow-mapping-10.png">
|
||||
|
||||
<img alt="cash flow mapper for operating activities" class="screenshot" src="{{docs_base_url}}/assets/img/articles/cash-flow-mapper-5.png">
|
||||
|
||||
<img alt="cash flow mapper for operating activities" class="screenshot" src="{{docs_base_url}}/assets/img/articles/cash-flow-mapper-6.png">
|
||||
|
||||
Here's what our cash flow statement now looks like:
|
||||
<img alt="final cash flow statement" class="screenshot" src="{{docs_base_url}}/assets/img/articles/final-cash-flow.png">
|
@ -502,5 +502,6 @@ erpnext.patches.v10_0.update_translatable_fields
|
||||
erpnext.patches.v10_0.rename_offer_letter_to_job_offer
|
||||
execute:frappe.delete_doc('DocType', 'Production Planning Tool', ignore_missing=True)
|
||||
erpnext.patches.v10_0.migrate_daily_work_summary_settings_to_daily_work_summary_group
|
||||
erpnext.patches.v10_0.add_default_cash_flow_mappers
|
||||
erpnext.patches.v11_0.make_quality_inspection_template
|
||||
erpnext.patches.v10_0.update_territory_and_customer_group
|
||||
|
15
erpnext/patches/v10_0/add_default_cash_flow_mappers.py
Normal file
@ -0,0 +1,15 @@
|
||||
# Copyright (c) 2017, Frappe and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
from erpnext.setup.install import create_default_cash_flow_mapper_templates
|
||||
|
||||
|
||||
def execute():
|
||||
frappe.reload_doc('accounts', 'doctype', frappe.scrub('Cash Flow Mapping'))
|
||||
frappe.reload_doc('accounts', 'doctype', frappe.scrub('Cash Flow Mapper'))
|
||||
frappe.reload_doc('accounts', 'doctype', frappe.scrub('Cash Flow Mapping Template Details'))
|
||||
|
||||
create_default_cash_flow_mapper_templates()
|
@ -4,6 +4,7 @@
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import frappe
|
||||
from erpnext.accounts.doctype.cash_flow_mapper.default_cash_flow_mapper import DEFAULT_MAPPERS
|
||||
from frappe import _
|
||||
from frappe.desk.page.setup_wizard.setup_wizard import add_all_roles_to
|
||||
from frappe.custom.doctype.custom_field.custom_field import create_custom_field
|
||||
@ -11,14 +12,17 @@ from frappe.custom.doctype.custom_field.custom_field import create_custom_field
|
||||
default_mail_footer = """<div style="padding: 7px; text-align: right; color: #888"><small>Sent via
|
||||
<a style="color: #888" href="http://erpnext.org">ERPNext</a></div>"""
|
||||
|
||||
|
||||
def after_install():
|
||||
frappe.get_doc({'doctype': "Role", "role_name": "Analytics"}).insert()
|
||||
set_single_defaults()
|
||||
create_compact_item_print_custom_field()
|
||||
create_print_zero_amount_taxes_custom_field()
|
||||
add_all_roles_to("Administrator")
|
||||
create_default_cash_flow_mapper_templates()
|
||||
frappe.db.commit()
|
||||
|
||||
|
||||
def check_setup_wizard_not_completed():
|
||||
if frappe.db.get_default('desktop:home_page') == 'desktop':
|
||||
print()
|
||||
@ -27,6 +31,7 @@ def check_setup_wizard_not_completed():
|
||||
print()
|
||||
return False
|
||||
|
||||
|
||||
def set_single_defaults():
|
||||
for dt in ('Accounts Settings', 'Print Settings', 'HR Settings', 'Buying Settings',
|
||||
'Selling Settings', 'Stock Settings'):
|
||||
@ -45,6 +50,7 @@ def set_single_defaults():
|
||||
|
||||
frappe.db.set_default("date_format", "dd-mm-yyyy")
|
||||
|
||||
|
||||
def create_compact_item_print_custom_field():
|
||||
create_custom_field('Print Settings', {
|
||||
'label': _('Compact Item Print'),
|
||||
@ -54,6 +60,7 @@ def create_compact_item_print_custom_field():
|
||||
'insert_after': 'with_letterhead'
|
||||
})
|
||||
|
||||
|
||||
def create_print_zero_amount_taxes_custom_field():
|
||||
create_custom_field('Print Settings', {
|
||||
'label': _('Print taxes with zero amount'),
|
||||
@ -61,4 +68,13 @@ def create_print_zero_amount_taxes_custom_field():
|
||||
'fieldtype': 'Check',
|
||||
'default': 0,
|
||||
'insert_after': 'allow_print_for_cancelled'
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
def create_default_cash_flow_mapper_templates():
|
||||
mappers = DEFAULT_MAPPERS
|
||||
|
||||
for mapper in mappers:
|
||||
if not frappe.db.exists('Cash Flow Mapper', mapper['section_name']):
|
||||
doc = frappe.get_doc(mapper)
|
||||
doc.insert(ignore_permissions=True)
|
||||
|