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,
|
"set_only_once": 0,
|
||||||
"translatable": 0,
|
"translatable": 0,
|
||||||
"unique": 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,
|
"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
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
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.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.report.profit_and_loss_statement.profit_and_loss_statement import get_net_profit_loss
|
||||||
from erpnext.accounts.utils import get_fiscal_year
|
from erpnext.accounts.utils import get_fiscal_year
|
||||||
|
|
||||||
|
|
||||||
def execute(filters=None):
|
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,
|
period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
|
||||||
filters.periodicity, filters.accumulated_values, filters.company)
|
filters.periodicity, filters.accumulated_values, filters.company)
|
||||||
|
|
||||||
@ -44,10 +49,7 @@ def execute(filters=None):
|
|||||||
}
|
}
|
||||||
|
|
||||||
# combine all cash flow accounts for iteration
|
# combine all cash flow accounts for iteration
|
||||||
cash_flow_accounts = []
|
cash_flow_accounts = [operation_accounts, investing_accounts, financing_accounts]
|
||||||
cash_flow_accounts.append(operation_accounts)
|
|
||||||
cash_flow_accounts.append(investing_accounts)
|
|
||||||
cash_flow_accounts.append(financing_accounts)
|
|
||||||
|
|
||||||
# compute net profit / loss
|
# compute net profit / loss
|
||||||
income = get_data(filters.company, "Income", "Credit", period_list,
|
income = get_data(filters.company, "Income", "Credit", period_list,
|
||||||
@ -100,6 +102,7 @@ def execute(filters=None):
|
|||||||
|
|
||||||
return columns, data
|
return columns, data
|
||||||
|
|
||||||
|
|
||||||
def get_account_type_based_data(company, account_type, period_list, accumulated_values):
|
def get_account_type_based_data(company, account_type, period_list, accumulated_values):
|
||||||
data = {}
|
data = {}
|
||||||
total = 0
|
total = 0
|
||||||
@ -127,6 +130,7 @@ def get_account_type_based_data(company, account_type, period_list, accumulated_
|
|||||||
data["total"] = total
|
data["total"] = total
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
def get_start_date(period, accumulated_values, company):
|
def get_start_date(period, accumulated_values, company):
|
||||||
start_date = period["year_start_date"]
|
start_date = period["year_start_date"]
|
||||||
if accumulated_values:
|
if accumulated_values:
|
||||||
@ -134,6 +138,7 @@ def get_start_date(period, accumulated_values, company):
|
|||||||
|
|
||||||
return start_date
|
return start_date
|
||||||
|
|
||||||
|
|
||||||
def add_total_row_account(out, data, label, period_list, currency):
|
def add_total_row_account(out, data, label, period_list, currency):
|
||||||
total_row = {
|
total_row = {
|
||||||
"account_name": "'" + _("{0}").format(label) + "'",
|
"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):
|
def get_net_profit_loss(income, expense, period_list, company):
|
||||||
total = 0
|
total = 0
|
||||||
net_profit_loss = {
|
net_profit_loss = {
|
||||||
"account_name": "'" + _("Net Profit / Loss") + "'",
|
"account_name": "'" + _("Profit for the year") + "'",
|
||||||
"account": "'" + _("Net Profit / Loss") + "'",
|
"account": "'" + _("Profit for the year") + "'",
|
||||||
"warn_if_negative": True,
|
"warn_if_negative": True,
|
||||||
"currency": frappe.db.get_value("Company", company, "default_currency")
|
"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
|
erpnext.patches.v10_0.rename_offer_letter_to_job_offer
|
||||||
execute:frappe.delete_doc('DocType', 'Production Planning Tool', ignore_missing=True)
|
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.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.v11_0.make_quality_inspection_template
|
||||||
erpnext.patches.v10_0.update_territory_and_customer_group
|
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
|
from __future__ import print_function, unicode_literals
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
|
from erpnext.accounts.doctype.cash_flow_mapper.default_cash_flow_mapper import DEFAULT_MAPPERS
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.desk.page.setup_wizard.setup_wizard import add_all_roles_to
|
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
|
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
|
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>"""
|
<a style="color: #888" href="http://erpnext.org">ERPNext</a></div>"""
|
||||||
|
|
||||||
|
|
||||||
def after_install():
|
def after_install():
|
||||||
frappe.get_doc({'doctype': "Role", "role_name": "Analytics"}).insert()
|
frappe.get_doc({'doctype': "Role", "role_name": "Analytics"}).insert()
|
||||||
set_single_defaults()
|
set_single_defaults()
|
||||||
create_compact_item_print_custom_field()
|
create_compact_item_print_custom_field()
|
||||||
create_print_zero_amount_taxes_custom_field()
|
create_print_zero_amount_taxes_custom_field()
|
||||||
add_all_roles_to("Administrator")
|
add_all_roles_to("Administrator")
|
||||||
|
create_default_cash_flow_mapper_templates()
|
||||||
frappe.db.commit()
|
frappe.db.commit()
|
||||||
|
|
||||||
|
|
||||||
def check_setup_wizard_not_completed():
|
def check_setup_wizard_not_completed():
|
||||||
if frappe.db.get_default('desktop:home_page') == 'desktop':
|
if frappe.db.get_default('desktop:home_page') == 'desktop':
|
||||||
print()
|
print()
|
||||||
@ -27,6 +31,7 @@ def check_setup_wizard_not_completed():
|
|||||||
print()
|
print()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def set_single_defaults():
|
def set_single_defaults():
|
||||||
for dt in ('Accounts Settings', 'Print Settings', 'HR Settings', 'Buying Settings',
|
for dt in ('Accounts Settings', 'Print Settings', 'HR Settings', 'Buying Settings',
|
||||||
'Selling Settings', 'Stock Settings'):
|
'Selling Settings', 'Stock Settings'):
|
||||||
@ -45,6 +50,7 @@ def set_single_defaults():
|
|||||||
|
|
||||||
frappe.db.set_default("date_format", "dd-mm-yyyy")
|
frappe.db.set_default("date_format", "dd-mm-yyyy")
|
||||||
|
|
||||||
|
|
||||||
def create_compact_item_print_custom_field():
|
def create_compact_item_print_custom_field():
|
||||||
create_custom_field('Print Settings', {
|
create_custom_field('Print Settings', {
|
||||||
'label': _('Compact Item Print'),
|
'label': _('Compact Item Print'),
|
||||||
@ -54,6 +60,7 @@ def create_compact_item_print_custom_field():
|
|||||||
'insert_after': 'with_letterhead'
|
'insert_after': 'with_letterhead'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
def create_print_zero_amount_taxes_custom_field():
|
def create_print_zero_amount_taxes_custom_field():
|
||||||
create_custom_field('Print Settings', {
|
create_custom_field('Print Settings', {
|
||||||
'label': _('Print taxes with zero amount'),
|
'label': _('Print taxes with zero amount'),
|
||||||
@ -62,3 +69,12 @@ def create_print_zero_amount_taxes_custom_field():
|
|||||||
'default': 0,
|
'default': 0,
|
||||||
'insert_after': 'allow_print_for_cancelled'
|
'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)
|
||||||
|