Compare commits

..

1 Commits

Author SHA1 Message Date
RitvikSardana
3714b795d6 fix: POS opening issue because of Product Bundle 2023-09-18 17:22:02 +05:30
1111 changed files with 77124 additions and 47456 deletions

View File

@@ -9,13 +9,6 @@ trim_trailing_whitespace = true
charset = utf-8 charset = utf-8
# python, js indentation settings # python, js indentation settings
[{*.py,*.js,*.vue,*.css,*.scss,*.html}] [{*.py,*.js}]
indent_style = tab indent_style = tab
indent_size = 4 indent_size = 4
max_line_length = 110
# JSON files - mostly doctype schema files
[{*.json}]
insert_final_newline = false
indent_style = space
indent_size = 2

View File

@@ -156,7 +156,6 @@
"onScan": true, "onScan": true,
"html2canvas": true, "html2canvas": true,
"extend_cscript": true, "extend_cscript": true,
"localforage": true, "localforage": true
"Plaid": true
} }
} }

View File

@@ -17,7 +17,7 @@ jobs:
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v2 uses: actions/setup-node@v2
with: with:
node-version: 20 node-version: 18
- name: Setup dependencies - name: Setup dependencies
run: | run: |

View File

@@ -21,7 +21,7 @@ jobs:
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: 20 node-version: 14
check-latest: true check-latest: true
- name: Check commit titles - name: Check commit titles

View File

@@ -5,7 +5,7 @@ fail_fast: false
repos: repos:
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0 rev: v4.0.1
hooks: hooks:
- id: trailing-whitespace - id: trailing-whitespace
files: "erpnext.*" files: "erpnext.*"
@@ -15,55 +15,6 @@ repos:
args: ['--branch', 'develop'] args: ['--branch', 'develop']
- id: check-merge-conflict - id: check-merge-conflict
- id: check-ast - id: check-ast
- id: check-json
- id: check-toml
- id: check-yaml
- id: debug-statements
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v2.7.1
hooks:
- id: prettier
types_or: [javascript, vue, scss]
# Ignore any files that might contain jinja / bundles
exclude: |
(?x)^(
erpnext/public/dist/.*|
cypress/.*|
.*node_modules.*|
.*boilerplate.*|
erpnext/public/js/controllers/.*|
erpnext/templates/pages/order.js|
erpnext/templates/includes/.*|
.*/supplier_quotation.js|
.*/sales_taxes_and_charges_template.js|
.*/purchase_taxes_and_charges_template.js|
.*/subcontracting_order.js|
.*/landed_cost_voucher.js|
.*/payment_entry.js|
.*/loan_interest_accrual.js|
.*/loan_disbursement.js|
.*/loan_application.js|
.*/italy.js|
.*/sales_invoice.js|
.*/subcontracting_receipt.js|
.*/request_for_quotation.js|
.*/pos_profile.js|
.*/opportunity.js|
.*/quotation.js|
.*/sales_common.js|
.*/sales_order.js|
.*/pos_invoice.js|
.*/purchase_invoice.js|
.*/loan_repayment.js|
.*/material_request.js|
.*/purchase_receipt.js|
.*/delivery_note.js|
.*/loan.js|
.*/stock_entry.js|
.*/purchase_order.js|
.*/loan_write_off.js
)$
- repo: https://github.com/PyCQA/flake8 - repo: https://github.com/PyCQA/flake8
rev: 5.0.4 rev: 5.0.4

View File

@@ -1,13 +1,25 @@
module.exports = { module.exports = {
parserPreset: "conventional-changelog-conventionalcommits", parserPreset: 'conventional-changelog-conventionalcommits',
rules: { rules: {
"subject-empty": [2, "never"], 'subject-empty': [2, 'never'],
"type-case": [2, "always", "lower-case"], 'type-case': [2, 'always', 'lower-case'],
"type-empty": [2, "never"], 'type-empty': [2, 'never'],
"type-enum": [ 'type-enum': [
2, 2,
"always", 'always',
["build", "chore", "ci", "docs", "feat", "fix", "perf", "refactor", "revert", "style", "test"], [
'build',
'chore',
'ci',
'docs',
'feat',
'fix',
'perf',
'refactor',
'revert',
'style',
'test',
],
], ],
}, },
}; };

View File

@@ -3,7 +3,7 @@ import inspect
import frappe import frappe
__version__ = "14.66.0" __version__ = "14.34.3"
def get_default_company(user=None): def get_default_company(user=None):
@@ -13,7 +13,7 @@ def get_default_company(user=None):
if not user: if not user:
user = frappe.session.user user = frappe.session.user
companies = get_user_default_as_list("company", user) companies = get_user_default_as_list(user, "company")
if companies: if companies:
default_company = companies[0] default_company = companies[0]
else: else:

View File

@@ -1,4 +1,4 @@
frappe.provide("frappe.dashboards.chart_sources"); frappe.provide('frappe.dashboards.chart_sources');
frappe.dashboards.chart_sources["Account Balance Timeline"] = { frappe.dashboards.chart_sources["Account Balance Timeline"] = {
method: "erpnext.accounts.dashboard_chart_source.account_balance_timeline.account_balance_timeline.get", method: "erpnext.accounts.dashboard_chart_source.account_balance_timeline.account_balance_timeline.get",
@@ -9,14 +9,14 @@ frappe.dashboards.chart_sources["Account Balance Timeline"] = {
fieldtype: "Link", fieldtype: "Link",
options: "Company", options: "Company",
default: frappe.defaults.get_user_default("Company"), default: frappe.defaults.get_user_default("Company"),
reqd: 1, reqd: 1
}, },
{ {
fieldname: "account", fieldname: "account",
label: __("Account"), label: __("Account"),
fieldtype: "Link", fieldtype: "Link",
options: "Account", options: "Account",
reqd: 1, reqd: 1
}, },
], ]
}; };

View File

@@ -1,32 +1,33 @@
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors // Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt // License: GNU General Public License v3. See license.txt
frappe.ui.form.on("Account", { frappe.ui.form.on('Account', {
setup: function (frm) { setup: function(frm) {
frm.add_fetch("parent_account", "report_type", "report_type"); frm.add_fetch('parent_account', 'report_type', 'report_type');
frm.add_fetch("parent_account", "root_type", "root_type"); frm.add_fetch('parent_account', 'root_type', 'root_type');
}, },
onload: function (frm) { onload: function(frm) {
frm.set_query("parent_account", function (doc) { frm.set_query('parent_account', function(doc) {
return { return {
filters: { filters: {
is_group: 1, "is_group": 1,
company: doc.company, "company": doc.company
}, }
}; };
}); });
}, },
refresh: function (frm) { refresh: function(frm) {
frm.toggle_display("account_name", frm.is_new()); frm.toggle_display('account_name', frm.is_new());
// hide fields if group // hide fields if group
frm.toggle_display(["account_type", "tax_rate"], cint(frm.doc.is_group) == 0); frm.toggle_display(['account_type', 'tax_rate'], cint(frm.doc.is_group) == 0);
// disable fields // disable fields
frm.toggle_enable(["is_group", "company"], false); frm.toggle_enable(['is_group', 'company'], false);
if (cint(frm.doc.is_group) == 0) { if (cint(frm.doc.is_group) == 0) {
frm.toggle_display("freeze_account", frm.doc.__onload && frm.doc.__onload.can_freeze_account); frm.toggle_display('freeze_account', frm.doc.__onload
&& frm.doc.__onload.can_freeze_account);
} }
// read-only for root accounts // read-only for root accounts
@@ -37,101 +38,79 @@ frappe.ui.form.on("Account", {
} else { } else {
// credit days and type if customer or supplier // credit days and type if customer or supplier
frm.set_intro(null); frm.set_intro(null);
frm.trigger("account_type"); frm.trigger('account_type');
// show / hide convert buttons // show / hide convert buttons
frm.trigger("add_toolbar_buttons"); frm.trigger('add_toolbar_buttons');
} }
if (frm.has_perm("write")) { if (frm.has_perm('write')) {
frm.add_custom_button( frm.add_custom_button(__('Merge Account'), function () {
__("Merge Account"), frm.trigger("merge_account");
function () { }, __('Actions'));
frm.trigger("merge_account"); frm.add_custom_button(__('Update Account Name / Number'), function () {
}, frm.trigger("update_account_number");
__("Actions") }, __('Actions'));
);
frm.add_custom_button(
__("Update Account Name / Number"),
function () {
frm.trigger("update_account_number");
},
__("Actions")
);
} }
} }
}, },
account_type: function (frm) { account_type: function (frm) {
if (frm.doc.is_group == 0) { if (frm.doc.is_group == 0) {
frm.toggle_display(["tax_rate"], frm.doc.account_type == "Tax"); frm.toggle_display(['tax_rate'], frm.doc.account_type == 'Tax');
frm.toggle_display("warehouse", frm.doc.account_type == "Stock"); frm.toggle_display('warehouse', frm.doc.account_type == 'Stock');
} }
}, },
add_toolbar_buttons: function (frm) { add_toolbar_buttons: function(frm) {
frm.add_custom_button( frm.add_custom_button(__('Chart of Accounts'), () => {
__("Chart of Accounts"), frappe.set_route("Tree", "Account");
() => { }, __('View'));
frappe.set_route("Tree", "Account");
},
__("View")
);
if (frm.doc.is_group == 1) { if (frm.doc.is_group == 1) {
frm.add_custom_button( frm.add_custom_button(__('Convert to Non-Group'), function () {
__("Convert to Non-Group"), return frappe.call({
function () { doc: frm.doc,
return frappe.call({ method: 'convert_group_to_ledger',
doc: frm.doc, callback: function() {
method: "convert_group_to_ledger", frm.refresh();
callback: function () { }
frm.refresh(); });
}, }, __('Actions'));
});
},
__("Actions")
);
} else if (cint(frm.doc.is_group) == 0 && frappe.boot.user.can_read.indexOf("GL Entry") !== -1) {
frm.add_custom_button(
__("General Ledger"),
function () {
frappe.route_options = {
account: frm.doc.name,
from_date: frappe.sys_defaults.year_start_date,
to_date: frappe.sys_defaults.year_end_date,
company: frm.doc.company,
};
frappe.set_route("query-report", "General Ledger");
},
__("View")
);
frm.add_custom_button( } else if (cint(frm.doc.is_group) == 0
__("Convert to Group"), && frappe.boot.user.can_read.indexOf("GL Entry") !== -1) {
function () { frm.add_custom_button(__('General Ledger'), function () {
return frappe.call({ frappe.route_options = {
doc: frm.doc, "account": frm.doc.name,
method: "convert_ledger_to_group", "from_date": frappe.sys_defaults.year_start_date,
callback: function () { "to_date": frappe.sys_defaults.year_end_date,
frm.refresh(); "company": frm.doc.company
}, };
}); frappe.set_route("query-report", "General Ledger");
}, }, __('View'));
__("Actions")
); frm.add_custom_button(__('Convert to Group'), function () {
return frappe.call({
doc: frm.doc,
method: 'convert_ledger_to_group',
callback: function() {
frm.refresh();
}
});
}, __('Actions'));
} }
}, },
merge_account: function (frm) { merge_account: function(frm) {
var d = new frappe.ui.Dialog({ var d = new frappe.ui.Dialog({
title: __("Merge with Existing Account"), title: __('Merge with Existing Account'),
fields: [ fields: [
{ {
label: "Name", "label" : "Name",
fieldname: "name", "fieldname": "name",
fieldtype: "Data", "fieldtype": "Data",
reqd: 1, "reqd": 1,
default: frm.doc.name, "default": frm.doc.name
}, }
], ],
primary_action: function () { primary_action: function() {
var data = d.get_values(); var data = d.get_values();
frappe.call({ frappe.call({
method: "erpnext.accounts.doctype.account.account.merge_account", method: "erpnext.accounts.doctype.account.account.merge_account",
@@ -139,45 +118,42 @@ frappe.ui.form.on("Account", {
old: frm.doc.name, old: frm.doc.name,
new: data.name, new: data.name,
}, },
callback: function (r) { callback: function(r) {
if (!r.exc) { if(!r.exc) {
if (r.message) { if(r.message) {
frappe.set_route("Form", "Account", r.message); frappe.set_route("Form", "Account", r.message);
} }
d.hide(); d.hide();
} }
}, }
}); });
}, },
primary_action_label: __("Merge"), primary_action_label: __('Merge')
}); });
d.show(); d.show();
}, },
update_account_number: function (frm) { update_account_number: function(frm) {
var d = new frappe.ui.Dialog({ var d = new frappe.ui.Dialog({
title: __("Update Account Number / Name"), title: __('Update Account Number / Name'),
fields: [ fields: [
{ {
label: "Account Name", "label": "Account Name",
fieldname: "account_name", "fieldname": "account_name",
fieldtype: "Data", "fieldtype": "Data",
reqd: 1, "reqd": 1,
default: frm.doc.account_name, "default": frm.doc.account_name
}, },
{ {
label: "Account Number", "label": "Account Number",
fieldname: "account_number", "fieldname": "account_number",
fieldtype: "Data", "fieldtype": "Data",
default: frm.doc.account_number, "default": frm.doc.account_number
}, }
], ],
primary_action: function () { primary_action: function() {
var data = d.get_values(); var data = d.get_values();
if ( if(data.account_number === frm.doc.account_number && data.account_name === frm.doc.account_name) {
data.account_number === frm.doc.account_number &&
data.account_name === frm.doc.account_name
) {
d.hide(); d.hide();
return; return;
} }
@@ -187,11 +163,11 @@ frappe.ui.form.on("Account", {
args: { args: {
account_number: data.account_number, account_number: data.account_number,
account_name: data.account_name, account_name: data.account_name,
name: frm.doc.name, name: frm.doc.name
}, },
callback: function (r) { callback: function(r) {
if (!r.exc) { if(!r.exc) {
if (r.message) { if(r.message) {
frappe.set_route("Form", "Account", r.message); frappe.set_route("Form", "Account", r.message);
} else { } else {
frm.set_value("account_number", data.account_number); frm.set_value("account_number", data.account_number);
@@ -199,11 +175,11 @@ frappe.ui.form.on("Account", {
} }
d.hide(); d.hide();
} }
}, }
}); });
}, },
primary_action_label: __("Update"), primary_action_label: __('Update')
}); });
d.show(); d.show();
}, }
}); });

View File

@@ -58,7 +58,6 @@ class Account(NestedSet):
self.validate_balance_must_be_debit_or_credit() self.validate_balance_must_be_debit_or_credit()
self.validate_account_currency() self.validate_account_currency()
self.validate_root_company_and_sync_account_to_children() self.validate_root_company_and_sync_account_to_children()
self.validate_receivable_payable_account_type()
def validate_parent(self): def validate_parent(self):
"""Fetch Parent Details and validate parent account""" """Fetch Parent Details and validate parent account"""
@@ -115,24 +114,6 @@ class Account(NestedSet):
"Balance Sheet" if self.root_type in ("Asset", "Liability", "Equity") else "Profit and Loss" "Balance Sheet" if self.root_type in ("Asset", "Liability", "Equity") else "Profit and Loss"
) )
def validate_receivable_payable_account_type(self):
doc_before_save = self.get_doc_before_save()
receivable_payable_types = ["Receivable", "Payable"]
if (
doc_before_save
and doc_before_save.account_type in receivable_payable_types
and doc_before_save.account_type != self.account_type
):
# check for ledger entries
if frappe.db.get_all("GL Entry", filters={"account": self.name, "is_cancelled": 0}, limit=1):
msg = _(
"There are ledger entries against this account. Changing {0} to non-{1} in live system will cause incorrect output in 'Accounts {2}' report"
).format(
frappe.bold("Account Type"), doc_before_save.account_type, doc_before_save.account_type
)
frappe.msgprint(msg)
self.add_comment("Comment", msg)
def validate_root_details(self): def validate_root_details(self):
# does not exists parent # does not exists parent
if frappe.db.exists("Account", self.name): if frappe.db.exists("Account", self.name):

View File

@@ -1,4 +1,4 @@
frappe.provide("frappe.treeview_settings"); frappe.provide("frappe.treeview_settings")
frappe.treeview_settings["Account"] = { frappe.treeview_settings["Account"] = {
breadcrumb: "Accounts", breadcrumb: "Accounts",
@@ -7,12 +7,12 @@ frappe.treeview_settings["Account"] = {
filters: [ filters: [
{ {
fieldname: "company", fieldname: "company",
fieldtype: "Select", fieldtype:"Select",
options: erpnext.utils.get_tree_options("company"), options: erpnext.utils.get_tree_options("company"),
label: __("Company"), label: __("Company"),
default: erpnext.utils.get_tree_default("company"), default: erpnext.utils.get_tree_default("company"),
on_change: function () { on_change: function() {
var me = frappe.treeview_settings["Account"].treeview; var me = frappe.treeview_settings['Account'].treeview;
var company = me.page.fields_dict.company.get_value(); var company = me.page.fields_dict.company.get_value();
if (!company) { if (!company) {
frappe.throw(__("Please set a Company")); frappe.throw(__("Please set a Company"));
@@ -22,36 +22,30 @@ frappe.treeview_settings["Account"] = {
args: { args: {
company: company, company: company,
}, },
callback: function (r) { callback: function(r) {
if (r.message) { if(r.message) {
let root_company = r.message.length ? r.message[0] : ""; let root_company = r.message.length ? r.message[0] : "";
me.page.fields_dict.root_company.set_value(root_company); me.page.fields_dict.root_company.set_value(root_company);
frappe.db.get_value( frappe.db.get_value("Company", {"name": company}, "allow_account_creation_against_child_company", (r) => {
"Company", frappe.flags.ignore_root_company_validation = r.allow_account_creation_against_child_company;
{ name: company }, });
"allow_account_creation_against_child_company",
(r) => {
frappe.flags.ignore_root_company_validation =
r.allow_account_creation_against_child_company;
}
);
} }
}, }
}); });
}, }
}, },
{ {
fieldname: "root_company", fieldname: "root_company",
fieldtype: "Data", fieldtype:"Data",
label: __("Root Company"), label: __("Root Company"),
hidden: true, hidden: true,
disable_onchange: true, disable_onchange: true
}, }
], ],
root_label: "Accounts", root_label: "Accounts",
get_tree_nodes: "erpnext.accounts.utils.get_children", get_tree_nodes: 'erpnext.accounts.utils.get_children',
on_get_node: function (nodes, deep = false) { on_get_node: function(nodes, deep=false) {
if (frappe.boot.user.can_read.indexOf("GL Entry") == -1) return; if (frappe.boot.user.can_read.indexOf("GL Entry") == -1) return;
let accounts = []; let accounts = [];
@@ -63,231 +57,151 @@ frappe.treeview_settings["Account"] = {
} }
frappe.db.get_single_value("Accounts Settings", "show_balance_in_coa").then((value) => { frappe.db.get_single_value("Accounts Settings", "show_balance_in_coa").then((value) => {
if (value) { if(value) {
const get_balances = frappe.call({ const get_balances = frappe.call({
method: "erpnext.accounts.utils.get_account_balances", method: 'erpnext.accounts.utils.get_account_balances',
args: { args: {
accounts: accounts, accounts: accounts,
company: cur_tree.args.company, company: cur_tree.args.company
}, },
}); });
get_balances.then((r) => { get_balances.then(r => {
if (!r.message || r.message.length == 0) return; if (!r.message || r.message.length == 0) return;
for (let account of r.message) { for (let account of r.message) {
const node = cur_tree.nodes && cur_tree.nodes[account.value]; const node = cur_tree.nodes && cur_tree.nodes[account.value];
if (!node || node.is_root) continue; if (!node || node.is_root) continue;
// show Dr if positive since balance is calculated as debit - credit else show Cr // show Dr if positive since balance is calculated as debit - credit else show Cr
const balance = account.balance_in_account_currency || account.balance; const balance = account.balance_in_account_currency || account.balance;
const dr_or_cr = balance > 0 ? "Dr" : "Cr"; const dr_or_cr = balance > 0 ? "Dr": "Cr";
const format = (value, currency) => format_currency(Math.abs(value), currency); const format = (value, currency) => format_currency(Math.abs(value), currency);
if (account.balance !== undefined) { if (account.balance!==undefined) {
node.parent && node.parent.find(".balance-area").remove(); node.parent && node.parent.find('.balance-area').remove();
$( $('<span class="balance-area pull-right">'
'<span class="balance-area pull-right">' + + (account.balance_in_account_currency ?
(account.balance_in_account_currency (format(account.balance_in_account_currency, account.account_currency) + " / ") : "")
? format( + format(account.balance, account.company_currency)
account.balance_in_account_currency, + " " + dr_or_cr
account.account_currency + '</span>').insertBefore(node.$ul);
) + " / "
: "") +
format(account.balance, account.company_currency) +
" " +
dr_or_cr +
"</span>"
).insertBefore(node.$ul);
} }
} }
}); });
} }
}); });
}, },
add_tree_node: "erpnext.accounts.utils.add_ac", add_tree_node: 'erpnext.accounts.utils.add_ac',
menu_items: [ menu_items:[
{ {
label: __("New Company"), label: __('New Company'),
action: function () { action: function() { frappe.new_doc("Company", true) },
frappe.new_doc("Company", true); condition: 'frappe.boot.user.can_create.indexOf("Company") !== -1'
}, }
condition: 'frappe.boot.user.can_create.indexOf("Company") !== -1',
},
], ],
fields: [ fields: [
{ {fieldtype:'Data', fieldname:'account_name', label:__('New Account Name'), reqd:true,
fieldtype: "Data", description: __("Name of new Account. Note: Please don't create accounts for Customers and Suppliers")},
fieldname: "account_name", {fieldtype:'Data', fieldname:'account_number', label:__('Account Number'),
label: __("New Account Name"), description: __("Number of new Account, it will be included in the account name as a prefix")},
reqd: true, {fieldtype:'Check', fieldname:'is_group', label:__('Is Group'),
description: __( description: __('Further accounts can be made under Groups, but entries can be made against non-Groups')},
"Name of new Account. Note: Please don't create accounts for Customers and Suppliers" {fieldtype:'Select', fieldname:'root_type', label:__('Root Type'),
), options: ['Asset', 'Liability', 'Equity', 'Income', 'Expense'].join('\n'),
}, depends_on: 'eval:doc.is_group && !doc.parent_account'},
{ {fieldtype:'Select', fieldname:'account_type', label:__('Account Type'),
fieldtype: "Data", options: frappe.get_meta("Account").fields.filter(d => d.fieldname=='account_type')[0].options,
fieldname: "account_number", description: __("Optional. This setting will be used to filter in various transactions.")
label: __("Account Number"),
description: __("Number of new Account, it will be included in the account name as a prefix"),
},
{
fieldtype: "Check",
fieldname: "is_group",
label: __("Is Group"),
description: __(
"Further accounts can be made under Groups, but entries can be made against non-Groups"
),
},
{
fieldtype: "Select",
fieldname: "root_type",
label: __("Root Type"),
options: ["Asset", "Liability", "Equity", "Income", "Expense"].join("\n"),
depends_on: "eval:doc.is_group && !doc.parent_account",
},
{
fieldtype: "Select",
fieldname: "account_type",
label: __("Account Type"),
options: frappe.get_meta("Account").fields.filter((d) => d.fieldname == "account_type")[0]
.options,
description: __("Optional. This setting will be used to filter in various transactions."),
},
{
fieldtype: "Float",
fieldname: "tax_rate",
label: __("Tax Rate"),
depends_on: 'eval:doc.is_group==0&&doc.account_type=="Tax"',
},
{
fieldtype: "Link",
fieldname: "account_currency",
label: __("Currency"),
options: "Currency",
description: __("Optional. Sets company's default currency, if not specified."),
}, },
{fieldtype:'Float', fieldname:'tax_rate', label:__('Tax Rate'),
depends_on: 'eval:doc.is_group==0&&doc.account_type=="Tax"'},
{fieldtype:'Link', fieldname:'account_currency', label:__('Currency'), options:"Currency",
description: __("Optional. Sets company's default currency, if not specified.")}
], ],
ignore_fields: ["parent_account"], ignore_fields:["parent_account"],
onload: function (treeview) { onload: function(treeview) {
frappe.treeview_settings["Account"].treeview = {}; frappe.treeview_settings['Account'].treeview = {};
$.extend(frappe.treeview_settings["Account"].treeview, treeview); $.extend(frappe.treeview_settings['Account'].treeview, treeview);
function get_company() { function get_company() {
return treeview.page.fields_dict.company.get_value(); return treeview.page.fields_dict.company.get_value();
} }
// tools // tools
treeview.page.add_inner_button( treeview.page.add_inner_button(__("Chart of Cost Centers"), function() {
__("Chart of Cost Centers"), frappe.set_route('Tree', 'Cost Center', {company: get_company()});
function () { }, __('View'));
frappe.set_route("Tree", "Cost Center", { company: get_company() });
},
__("View")
);
treeview.page.add_inner_button( treeview.page.add_inner_button(__("Opening Invoice Creation Tool"), function() {
__("Opening Invoice Creation Tool"), frappe.set_route('Form', 'Opening Invoice Creation Tool', {company: get_company()});
function () { }, __('View'));
frappe.set_route("Form", "Opening Invoice Creation Tool", { company: get_company() });
},
__("View")
);
treeview.page.add_inner_button( treeview.page.add_inner_button(__("Period Closing Voucher"), function() {
__("Period Closing Voucher"), frappe.set_route('List', 'Period Closing Voucher', {company: get_company()});
function () { }, __('View'));
frappe.set_route("List", "Period Closing Voucher", { company: get_company() });
},
__("View")
);
treeview.page.add_inner_button(
__("Journal Entry"), treeview.page.add_inner_button(__("Journal Entry"), function() {
function () { frappe.new_doc('Journal Entry', {company: get_company()});
frappe.new_doc("Journal Entry", { company: get_company() }); }, __('Create'));
}, treeview.page.add_inner_button(__("Company"), function() {
__("Create") frappe.new_doc('Company');
); }, __('Create'));
treeview.page.add_inner_button(
__("Company"),
function () {
frappe.new_doc("Company");
},
__("Create")
);
// financial statements // financial statements
for (let report of [ for (let report of ['Trial Balance', 'General Ledger', 'Balance Sheet',
"Trial Balance", 'Profit and Loss Statement', 'Cash Flow Statement', 'Accounts Payable', 'Accounts Receivable']) {
"General Ledger", treeview.page.add_inner_button(__(report), function() {
"Balance Sheet", frappe.set_route('query-report', report, {company: get_company()});
"Profit and Loss Statement", }, __('Financial Statements'));
"Cash Flow Statement",
"Accounts Payable",
"Accounts Receivable",
]) {
treeview.page.add_inner_button(
__(report),
function () {
frappe.set_route("query-report", report, { company: get_company() });
},
__("Financial Statements")
);
} }
},
post_render: function (treeview) {
frappe.treeview_settings["Account"].treeview["tree"] = treeview.tree;
treeview.page.set_primary_action(
__("New"),
function () {
let root_company = treeview.page.fields_dict.root_company.get_value();
if (root_company) { },
frappe.throw(__("Please add the account to root level Company - {0}"), [root_company]); post_render: function(treeview) {
} else { frappe.treeview_settings['Account'].treeview["tree"] = treeview.tree;
treeview.new_node(); treeview.page.set_primary_action(__("New"), function() {
} let root_company = treeview.page.fields_dict.root_company.get_value();
},
"add" if(root_company) {
); frappe.throw(__("Please add the account to root level Company - {0}"), [root_company]);
} else {
treeview.new_node();
}
}, "add");
}, },
toolbar: [ toolbar: [
{ {
label: __("Add Child"), label:__("Add Child"),
condition: function (node) { condition: function(node) {
return ( return frappe.boot.user.can_create.indexOf("Account") !== -1
frappe.boot.user.can_create.indexOf("Account") !== -1 && && (!frappe.treeview_settings['Account'].treeview.page.fields_dict.root_company.get_value()
(!frappe.treeview_settings[ || frappe.flags.ignore_root_company_validation)
"Account" && node.expandable && !node.hide_add;
].treeview.page.fields_dict.root_company.get_value() ||
frappe.flags.ignore_root_company_validation) &&
node.expandable &&
!node.hide_add
);
}, },
click: function () { click: function() {
var me = frappe.views.trees["Account"]; var me = frappe.views.trees['Account'];
me.new_node(); me.new_node();
}, },
btnClass: "hidden-xs", btnClass: "hidden-xs"
}, },
{ {
condition: function (node) { condition: function(node) {
return !node.root && frappe.boot.user.can_read.indexOf("GL Entry") !== -1; return !node.root && frappe.boot.user.can_read.indexOf("GL Entry") !== -1
}, },
label: __("View Ledger"), label: __("View Ledger"),
click: function (node, btn) { click: function(node, btn) {
frappe.route_options = { frappe.route_options = {
account: node.label, "account": node.label,
from_date: frappe.sys_defaults.year_start_date, "from_date": frappe.sys_defaults.year_start_date,
to_date: frappe.sys_defaults.year_end_date, "to_date": frappe.sys_defaults.year_end_date,
company: "company": frappe.treeview_settings['Account'].treeview.page.fields_dict.company.get_value()
frappe.treeview_settings["Account"].treeview.page.fields_dict.company.get_value(),
}; };
frappe.set_route("query-report", "General Ledger"); frappe.set_route("query-report", "General Ledger");
}, },
btnClass: "hidden-xs", btnClass: "hidden-xs"
}, }
], ],
extend_toolbar: true, extend_toolbar: true
}; }

View File

@@ -53,13 +53,8 @@
}, },
"II. Forderungen und sonstige Vermögensgegenstände": { "II. Forderungen und sonstige Vermögensgegenstände": {
"is_group": 1, "is_group": 1,
"Forderungen aus Lieferungen und Leistungen mit Kontokorrent": { "Ford. a. Lieferungen und Leistungen": {
"account_number": "1400", "account_number": "1400",
"account_type": "Receivable",
"is_group": 1
},
"Forderungen aus Lieferungen und Leistungen ohne Kontokorrent": {
"account_number": "1410",
"account_type": "Receivable" "account_type": "Receivable"
}, },
"Durchlaufende Posten": { "Durchlaufende Posten": {
@@ -185,13 +180,8 @@
}, },
"IV. Verbindlichkeiten aus Lieferungen und Leistungen": { "IV. Verbindlichkeiten aus Lieferungen und Leistungen": {
"is_group": 1, "is_group": 1,
"Verbindlichkeiten aus Lieferungen und Leistungen mit Kontokorrent": { "Verbindlichkeiten aus Lieferungen u. Leistungen": {
"account_number": "1600", "account_number": "1600",
"account_type": "Payable",
"is_group": 1
},
"Verbindlichkeiten aus Lieferungen und Leistungen ohne Kontokorrent": {
"account_number": "1610",
"account_type": "Payable" "account_type": "Payable"
} }
}, },

View File

@@ -407,10 +407,13 @@
"Bewertungskorrektur zu Forderungen aus Lieferungen und Leistungen": { "Bewertungskorrektur zu Forderungen aus Lieferungen und Leistungen": {
"account_number": "9960" "account_number": "9960"
}, },
"Forderungen aus Lieferungen und Leistungen mit Kontokorrent": { "Debitoren": {
"is_group": 1,
"account_number": "10000"
},
"Forderungen aus Lieferungen und Leistungen": {
"account_number": "1200", "account_number": "1200",
"account_type": "Receivable", "account_type": "Receivable"
"is_group": 1
}, },
"Forderungen aus Lieferungen und Leistungen ohne Kontokorrent": { "Forderungen aus Lieferungen und Leistungen ohne Kontokorrent": {
"account_number": "1210" "account_number": "1210"
@@ -1135,15 +1138,18 @@
"Bewertungskorrektur zu Verb. aus Lieferungen und Leistungen": { "Bewertungskorrektur zu Verb. aus Lieferungen und Leistungen": {
"account_number": "9964" "account_number": "9964"
}, },
"Verb. aus Lieferungen und Leistungen mit Kontokorrent": { "Kreditoren": {
"account_number": "3300", "account_number": "70000",
"account_type": "Payable",
"is_group": 1, "is_group": 1,
"Wareneingangs-Verrechnungskonto" : { "Wareneingangs-­Verrechnungskonto" : {
"account_number": "70001", "account_number": "70001",
"account_type": "Stock Received But Not Billed" "account_type": "Stock Received But Not Billed"
} }
}, },
"Verb. aus Lieferungen und Leistungen": {
"account_number": "3300",
"account_type": "Payable"
},
"Verb. aus Lieferungen und Leistungen ohne Kontokorrent": { "Verb. aus Lieferungen und Leistungen ohne Kontokorrent": {
"account_number": "3310" "account_number": "3310"
}, },

View File

@@ -37,7 +37,6 @@ def make_closing_entries(closing_entries, voucher_name, company, closing_date):
} }
) )
cle.flags.ignore_permissions = True cle.flags.ignore_permissions = True
cle.flags.ignore_links = True
cle.submit() cle.submit()

View File

@@ -1,86 +1,74 @@
// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors // Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Accounting Dimension", { frappe.ui.form.on('Accounting Dimension', {
refresh: function (frm) { refresh: function(frm) {
frm.set_query("document_type", () => { frm.set_query('document_type', () => {
let invalid_doctypes = frappe.model.core_doctypes_list; let invalid_doctypes = frappe.model.core_doctypes_list;
invalid_doctypes.push( invalid_doctypes.push('Accounting Dimension', 'Project',
"Accounting Dimension", 'Cost Center', 'Accounting Dimension Detail', 'Company');
"Project",
"Cost Center",
"Accounting Dimension Detail",
"Company"
);
return { return {
filters: { filters: {
name: ["not in", invalid_doctypes], name: ['not in', invalid_doctypes]
}, }
}; };
}); });
frm.set_query("offsetting_account", "dimension_defaults", function (doc, cdt, cdn) { frm.set_query("offsetting_account", "dimension_defaults", function(doc, cdt, cdn) {
let d = locals[cdt][cdn]; let d = locals[cdt][cdn];
return { return {
filters: { filters: {
company: d.company, company: d.company,
root_type: ["in", ["Asset", "Liability"]], root_type: ["in", ["Asset", "Liability"]],
is_group: 0, is_group: 0
}, }
}; }
}); });
if (!frm.is_new()) { if (!frm.is_new()) {
frm.add_custom_button(__("Show {0}", [frm.doc.document_type]), function () { frm.add_custom_button(__('Show {0}', [frm.doc.document_type]), function () {
frappe.set_route("List", frm.doc.document_type); frappe.set_route("List", frm.doc.document_type);
}); });
let button = frm.doc.disabled ? "Enable" : "Disable"; let button = frm.doc.disabled ? "Enable" : "Disable";
frm.add_custom_button(__(button), function () { frm.add_custom_button(__(button), function() {
frm.set_value("disabled", 1 - frm.doc.disabled);
frm.set_value('disabled', 1 - frm.doc.disabled);
frappe.call({ frappe.call({
method: "erpnext.accounts.doctype.accounting_dimension.accounting_dimension.disable_dimension", method: "erpnext.accounts.doctype.accounting_dimension.accounting_dimension.disable_dimension",
args: { args: {
doc: frm.doc, doc: frm.doc
}, },
freeze: true, freeze: true,
callback: function (r) { callback: function(r) {
let message = frm.doc.disabled ? "Dimension Disabled" : "Dimension Enabled"; let message = frm.doc.disabled ? "Dimension Disabled" : "Dimension Enabled";
frm.save(); frm.save();
frappe.show_alert({ message: __(message), indicator: "green" }); frappe.show_alert({message:__(message), indicator:'green'});
}, }
}); });
}); });
} }
}, },
document_type: function (frm) { document_type: function(frm) {
frm.set_value("label", frm.doc.document_type);
frm.set_value("fieldname", frappe.model.scrub(frm.doc.document_type));
frappe.db.get_value( frm.set_value('label', frm.doc.document_type);
"Accounting Dimension", frm.set_value('fieldname', frappe.model.scrub(frm.doc.document_type));
{ document_type: frm.doc.document_type },
"document_type", frappe.db.get_value('Accounting Dimension', {'document_type': frm.doc.document_type}, 'document_type', (r) => {
(r) => { if (r && r.document_type) {
if (r && r.document_type) { frm.set_df_property('document_type', 'description', "Document type is already set as dimension");
frm.set_df_property(
"document_type",
"description",
"Document type is already set as dimension"
);
}
} }
); });
}, },
}); });
frappe.ui.form.on("Accounting Dimension Detail", { frappe.ui.form.on('Accounting Dimension Detail', {
dimension_defaults_add: function (frm, cdt, cdn) { dimension_defaults_add: function(frm, cdt, cdn) {
let row = locals[cdt][cdn]; let row = locals[cdt][cdn];
row.reference_document = frm.doc.document_type; row.reference_document = frm.doc.document_type;
}, }
}); });

View File

@@ -236,16 +236,14 @@ def get_accounting_dimensions(as_list=True, filters=None):
def get_checks_for_pl_and_bs_accounts(): def get_checks_for_pl_and_bs_accounts():
if frappe.flags.accounting_dimensions_details is None: dimensions = frappe.db.sql(
# nosemgrep """SELECT p.label, p.disabled, p.fieldname, c.default_dimension, c.company, c.mandatory_for_pl, c.mandatory_for_bs
frappe.flags.accounting_dimensions_details = frappe.db.sql( FROM `tabAccounting Dimension`p ,`tabAccounting Dimension Detail` c
"""SELECT p.label, p.disabled, p.fieldname, c.default_dimension, c.company, c.mandatory_for_pl, c.mandatory_for_bs WHERE p.name = c.parent""",
FROM `tabAccounting Dimension`p ,`tabAccounting Dimension Detail` c as_dict=1,
WHERE p.name = c.parent""", )
as_dict=1,
)
return frappe.flags.accounting_dimensions_details return dimensions
def get_dimension_with_children(doctype, dimensions): def get_dimension_with_children(doctype, dimensions):
@@ -303,30 +301,3 @@ def get_dimensions(with_cost_center_and_project=False):
default_dimensions_map[dimension.company][dimension.fieldname] = dimension.default_dimension default_dimensions_map[dimension.company][dimension.fieldname] = dimension.default_dimension
return dimension_filters, default_dimensions_map return dimension_filters, default_dimensions_map
def create_accounting_dimensions_for_doctype(doctype):
accounting_dimensions = frappe.db.get_all(
"Accounting Dimension", fields=["fieldname", "label", "document_type", "disabled"]
)
if not accounting_dimensions:
return
for d in accounting_dimensions:
field = frappe.db.get_value("Custom Field", {"dt": doctype, "fieldname": d.fieldname})
if field:
continue
df = {
"fieldname": d.fieldname,
"label": d.label,
"fieldtype": "Link",
"options": d.document_type,
"insert_after": "accounting_dimensions_section",
}
create_custom_field(doctype, df, ignore_validate=True)
frappe.clear_cache(doctype=doctype)

View File

@@ -78,8 +78,6 @@ class TestAccountingDimension(unittest.TestCase):
def tearDown(self): def tearDown(self):
disable_dimension() disable_dimension()
frappe.flags.accounting_dimensions_details = None
frappe.flags.dimension_filter_map = None
def create_dimension(): def create_dimension():

View File

@@ -1,9 +1,10 @@
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors // Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Accounting Dimension Filter", { frappe.ui.form.on('Accounting Dimension Filter', {
refresh: function (frm, cdt, cdn) { refresh: function(frm, cdt, cdn) {
let help_content = `<table class="table table-bordered" style="background-color: var(--scrollbar-track-color);"> let help_content =
`<table class="table table-bordered" style="background-color: var(--scrollbar-track-color);">
<tr><td> <tr><td>
<p> <p>
<i class="fa fa-hand-right"></i> <i class="fa fa-hand-right"></i>
@@ -12,70 +13,67 @@ frappe.ui.form.on("Accounting Dimension Filter", {
</td></tr> </td></tr>
</table>`; </table>`;
frm.set_df_property("dimension_filter_help", "options", help_content); frm.set_df_property('dimension_filter_help', 'options', help_content);
}, },
onload: function (frm) { onload: function(frm) {
frm.set_query("applicable_on_account", "accounts", function () { frm.set_query('applicable_on_account', 'accounts', function() {
return { return {
filters: { filters: {
company: frm.doc.company, 'company': frm.doc.company
}, }
}; };
}); });
frappe.db.get_list("Accounting Dimension", { fields: ["document_type"] }).then((res) => { frappe.db.get_list('Accounting Dimension',
let options = ["Cost Center", "Project"]; {fields: ['document_type']}).then((res) => {
let options = ['Cost Center', 'Project'];
res.forEach((dimension) => { res.forEach((dimension) => {
options.push(dimension.document_type); options.push(dimension.document_type);
}); });
frm.set_df_property("accounting_dimension", "options", options); frm.set_df_property('accounting_dimension', 'options', options);
}); });
frm.trigger("setup_filters"); frm.trigger('setup_filters');
}, },
setup_filters: function (frm) { setup_filters: function(frm) {
let filters = {}; let filters = {};
if (frm.doc.accounting_dimension) { if (frm.doc.accounting_dimension) {
frappe.model.with_doctype(frm.doc.accounting_dimension, function () { frappe.model.with_doctype(frm.doc.accounting_dimension, function() {
if (frappe.model.is_tree(frm.doc.accounting_dimension)) { if (frappe.model.is_tree(frm.doc.accounting_dimension)) {
filters["is_group"] = 0; filters['is_group'] = 0;
} }
if (frappe.meta.has_field(frm.doc.accounting_dimension, "company")) { if (frappe.meta.has_field(frm.doc.accounting_dimension, 'company')) {
filters["company"] = frm.doc.company; filters['company'] = frm.doc.company;
} }
frm.set_query("dimension_value", "dimensions", function () { frm.set_query('dimension_value', 'dimensions', function() {
return { return {
filters: filters, filters: filters
}; };
}); });
}); });
} }
}, },
accounting_dimension: function (frm) { accounting_dimension: function(frm) {
frm.clear_table("dimensions"); frm.clear_table("dimensions");
let row = frm.add_child("dimensions"); let row = frm.add_child("dimensions");
row.accounting_dimension = frm.doc.accounting_dimension; row.accounting_dimension = frm.doc.accounting_dimension;
frm.fields_dict["dimensions"].grid.update_docfield_property( frm.fields_dict["dimensions"].grid.update_docfield_property("dimension_value", "label", frm.doc.accounting_dimension);
"dimension_value",
"label",
frm.doc.accounting_dimension
);
frm.refresh_field("dimensions"); frm.refresh_field("dimensions");
frm.trigger("setup_filters"); frm.trigger('setup_filters');
}, },
}); });
frappe.ui.form.on("Allowed Dimension", { frappe.ui.form.on('Allowed Dimension', {
dimensions_add: function (frm, cdt, cdn) { dimensions_add: function(frm, cdt, cdn) {
let row = locals[cdt][cdn]; let row = locals[cdt][cdn];
row.accounting_dimension = frm.doc.accounting_dimension; row.accounting_dimension = frm.doc.accounting_dimension;
frm.refresh_field("dimensions"); frm.refresh_field("dimensions");
}, }
}); });

View File

@@ -38,41 +38,37 @@ class AccountingDimensionFilter(Document):
def get_dimension_filter_map(): def get_dimension_filter_map():
if not frappe.flags.get("dimension_filter_map"): filters = frappe.db.sql(
# nosemgrep """
filters = frappe.db.sql( SELECT
""" a.applicable_on_account, d.dimension_value, p.accounting_dimension,
SELECT p.allow_or_restrict, a.is_mandatory
a.applicable_on_account, d.dimension_value, p.accounting_dimension, FROM
p.allow_or_restrict, a.is_mandatory `tabApplicable On Account` a, `tabAllowed Dimension` d,
FROM `tabAccounting Dimension Filter` p
`tabApplicable On Account` a, `tabAllowed Dimension` d, WHERE
`tabAccounting Dimension Filter` p p.name = a.parent
WHERE AND p.disabled = 0
p.name = a.parent AND p.name = d.parent
AND p.disabled = 0 """,
AND p.name = d.parent as_dict=1,
""", )
as_dict=1,
dimension_filter_map = {}
for f in filters:
f.fieldname = scrub(f.accounting_dimension)
build_map(
dimension_filter_map,
f.fieldname,
f.applicable_on_account,
f.dimension_value,
f.allow_or_restrict,
f.is_mandatory,
) )
dimension_filter_map = {} return dimension_filter_map
for f in filters:
f.fieldname = scrub(f.accounting_dimension)
build_map(
dimension_filter_map,
f.fieldname,
f.applicable_on_account,
f.dimension_value,
f.allow_or_restrict,
f.is_mandatory,
)
frappe.flags.dimension_filter_map = dimension_filter_map
return frappe.flags.dimension_filter_map
def build_map(map_object, dimension, account, filter_value, allow_or_restrict, is_mandatory): def build_map(map_object, dimension, account, filter_value, allow_or_restrict, is_mandatory):

View File

@@ -47,8 +47,6 @@ class TestAccountingDimensionFilter(unittest.TestCase):
def tearDown(self): def tearDown(self):
disable_dimension_filter() disable_dimension_filter()
disable_dimension() disable_dimension()
frappe.flags.accounting_dimensions_details = None
frappe.flags.dimension_filter_map = None
for si in self.invoice_list: for si in self.invoice_list:
si.load_from_db() si.load_from_db()

View File

@@ -1,33 +1,30 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors // Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Accounting Period", { frappe.ui.form.on('Accounting Period', {
onload: function (frm) { onload: function(frm) {
if ( if(frm.doc.closed_documents.length === 0 || (frm.doc.closed_documents.length === 1 && frm.doc.closed_documents[0].document_type == undefined)) {
frm.doc.closed_documents.length === 0 ||
(frm.doc.closed_documents.length === 1 && frm.doc.closed_documents[0].document_type == undefined)
) {
frappe.call({ frappe.call({
method: "get_doctypes_for_closing", method: "get_doctypes_for_closing",
doc: frm.doc, doc:frm.doc,
callback: function (r) { callback: function(r) {
if (r.message) { if(r.message) {
cur_frm.clear_table("closed_documents"); cur_frm.clear_table("closed_documents");
r.message.forEach(function (element) { r.message.forEach(function(element) {
var c = frm.add_child("closed_documents"); var c = frm.add_child("closed_documents");
c.document_type = element.document_type; c.document_type = element.document_type;
c.closed = element.closed; c.closed = element.closed;
}); });
refresh_field("closed_documents"); refresh_field("closed_documents");
} }
}, }
}); });
} }
frm.set_query("document_type", "closed_documents", () => { frm.set_query("document_type", "closed_documents", () => {
return { return {
query: "erpnext.controllers.queries.get_doctypes_for_closing", query: "erpnext.controllers.queries.get_doctypes_for_closing",
}; }
}); });
}, }
}); });

View File

@@ -1,6 +1,8 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors // Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Accounts Settings", { frappe.ui.form.on('Accounts Settings', {
refresh: function (frm) {}, refresh: function(frm) {
}
}); });

View File

@@ -68,12 +68,7 @@
"enable_party_matching", "enable_party_matching",
"enable_fuzzy_matching", "enable_fuzzy_matching",
"tab_break_dpet", "tab_break_dpet",
"show_balance_in_coa", "show_balance_in_coa"
"reports_tab",
"remarks_section",
"general_ledger_remarks_length",
"column_break_lvjk",
"receivable_payable_remarks_length"
], ],
"fields": [ "fields": [
{ {
@@ -434,34 +429,6 @@
"fieldname": "show_balance_in_coa", "fieldname": "show_balance_in_coa",
"fieldtype": "Check", "fieldtype": "Check",
"label": "Show Balances in Chart Of Accounts" "label": "Show Balances in Chart Of Accounts"
},
{
"fieldname": "reports_tab",
"fieldtype": "Tab Break",
"label": "Reports"
},
{
"default": "0",
"description": "Truncates 'Remarks' column to set character length",
"fieldname": "general_ledger_remarks_length",
"fieldtype": "Int",
"label": "General Ledger"
},
{
"default": "0",
"description": "Truncates 'Remarks' column to set character length",
"fieldname": "receivable_payable_remarks_length",
"fieldtype": "Int",
"label": "Accounts Receivable/Payable"
},
{
"fieldname": "column_break_lvjk",
"fieldtype": "Column Break"
},
{
"fieldname": "remarks_section",
"fieldtype": "Section Break",
"label": "Remarks Column Length"
} }
], ],
"icon": "icon-cog", "icon": "icon-cog",
@@ -469,7 +436,7 @@
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"issingle": 1, "issingle": 1,
"links": [], "links": [],
"modified": "2023-11-20 09:37:47.650347", "modified": "2023-07-27 15:05:34.000264",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Accounts Settings", "name": "Accounts Settings",

View File

@@ -1,11 +1,8 @@
frappe.ui.form.on("Accounts Settings", {
refresh: function (frm) { frappe.ui.form.on('Accounts Settings', {
refresh: function(frm) {
frm.set_df_property("acc_frozen_upto", "label", "Books Closed Through"); frm.set_df_property("acc_frozen_upto", "label", "Books Closed Through");
frm.set_df_property( frm.set_df_property("frozen_accounts_modifier", "label", "Role Allowed to Close Books & Make Changes to Closed Periods");
"frozen_accounts_modifier",
"label",
"Role Allowed to Close Books & Make Changes to Closed Periods"
);
frm.set_df_property("credit_controller", "label", "Credit Manager"); frm.set_df_property("credit_controller", "label", "Credit Manager");
}, }
}); });

View File

@@ -11,7 +11,6 @@
{ {
"fieldname": "company", "fieldname": "company",
"fieldtype": "Link", "fieldtype": "Link",
"ignore_user_permissions": 1,
"in_list_view": 1, "in_list_view": 1,
"label": "Company", "label": "Company",
"options": "Company", "options": "Company",
@@ -20,7 +19,7 @@
], ],
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2024-01-03 11:13:02.669632", "modified": "2020-05-01 12:32:34.044911",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Allowed To Transact With", "name": "Allowed To Transact With",
@@ -29,6 +28,5 @@
"quick_entry": 1, "quick_entry": 1,
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"states": [],
"track_changes": 1 "track_changes": 1
} }

View File

@@ -1,39 +1,41 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors // Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.provide("erpnext.integrations"); frappe.provide('erpnext.integrations');
frappe.ui.form.on("Bank", { frappe.ui.form.on('Bank', {
onload: function (frm) { onload: function(frm) {
add_fields_to_mapping_table(frm); add_fields_to_mapping_table(frm);
}, },
refresh: function (frm) { refresh: function(frm) {
add_fields_to_mapping_table(frm); add_fields_to_mapping_table(frm);
frappe.dynamic_link = { doc: frm.doc, fieldname: "name", doctype: "Bank" }; frappe.dynamic_link = { doc: frm.doc, fieldname: 'name', doctype: 'Bank' };
frm.toggle_display(["address_html", "contact_html"], !frm.doc.__islocal); frm.toggle_display(['address_html','contact_html'], !frm.doc.__islocal);
if (frm.doc.__islocal) { if (frm.doc.__islocal) {
frm.set_df_property("address_and_contact", "hidden", 1); frm.set_df_property('address_and_contact', 'hidden', 1);
frappe.contacts.clear_address_and_contact(frm); frappe.contacts.clear_address_and_contact(frm);
} else { }
frm.set_df_property("address_and_contact", "hidden", 0); else {
frm.set_df_property('address_and_contact', 'hidden', 0);
frappe.contacts.render_address_and_contact(frm); frappe.contacts.render_address_and_contact(frm);
} }
if (frm.doc.plaid_access_token) { if (frm.doc.plaid_access_token) {
frm.add_custom_button(__("Refresh Plaid Link"), () => { frm.add_custom_button(__('Refresh Plaid Link'), () => {
new erpnext.integrations.refreshPlaidLink(frm.doc.plaid_access_token); new erpnext.integrations.refreshPlaidLink(frm.doc.plaid_access_token);
}); });
} }
}, }
}); });
let add_fields_to_mapping_table = function (frm) { let add_fields_to_mapping_table = function (frm) {
let options = []; let options = [];
frappe.model.with_doctype("Bank Transaction", function () { frappe.model.with_doctype("Bank Transaction", function() {
let meta = frappe.get_meta("Bank Transaction"); let meta = frappe.get_meta("Bank Transaction");
meta.fields.forEach((value) => { meta.fields.forEach(value => {
if (!["Section Break", "Column Break"].includes(value.fieldtype)) { if (!["Section Break", "Column Break"].includes(value.fieldtype)) {
options.push(value.fieldname); options.push(value.fieldname);
} }
@@ -41,32 +43,30 @@ let add_fields_to_mapping_table = function (frm) {
}); });
frm.fields_dict.bank_transaction_mapping.grid.update_docfield_property( frm.fields_dict.bank_transaction_mapping.grid.update_docfield_property(
"bank_transaction_field", 'bank_transaction_field', 'options', options
"options",
options
); );
}; };
erpnext.integrations.refreshPlaidLink = class refreshPlaidLink { erpnext.integrations.refreshPlaidLink = class refreshPlaidLink {
constructor(access_token) { constructor(access_token) {
this.access_token = access_token; this.access_token = access_token;
this.plaidUrl = "https://cdn.plaid.com/link/v2/stable/link-initialize.js"; this.plaidUrl = 'https://cdn.plaid.com/link/v2/stable/link-initialize.js';
this.init_config(); this.init_config();
} }
async init_config() { async init_config() {
this.plaid_env = await frappe.db.get_single_value("Plaid Settings", "plaid_env"); this.plaid_env = await frappe.db.get_single_value('Plaid Settings', 'plaid_env');
this.token = await this.get_link_token_for_update(); this.token = await this.get_link_token_for_update();
this.init_plaid(); this.init_plaid();
} }
async get_link_token_for_update() { async get_link_token_for_update() {
const token = frappe.xcall( const token = frappe.xcall(
"erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.get_link_token_for_update", 'erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.get_link_token_for_update',
{ access_token: this.access_token } { access_token: this.access_token }
); )
if (!token) { if (!token) {
frappe.throw(__("Cannot retrieve link token for update. Check Error Log for more information")); frappe.throw(__('Cannot retrieve link token for update. Check Error Log for more information'));
} }
return token; return token;
} }
@@ -93,13 +93,13 @@ erpnext.integrations.refreshPlaidLink = class refreshPlaidLink {
resolve(); resolve();
return; return;
} }
const el = document.createElement("script"); const el = document.createElement('script');
el.type = "text/javascript"; el.type = 'text/javascript';
el.async = true; el.async = true;
el.src = src; el.src = src;
el.addEventListener("load", resolve); el.addEventListener('load', resolve);
el.addEventListener("error", reject); el.addEventListener('error', reject);
el.addEventListener("abort", reject); el.addEventListener('abort', reject);
document.head.appendChild(el); document.head.appendChild(el);
}); });
} }
@@ -108,29 +108,20 @@ erpnext.integrations.refreshPlaidLink = class refreshPlaidLink {
me.linkHandler = Plaid.create({ me.linkHandler = Plaid.create({
env: me.plaid_env, env: me.plaid_env,
token: me.token, token: me.token,
onSuccess: me.plaid_success, onSuccess: me.plaid_success
}); });
} }
onScriptError(error) { onScriptError(error) {
frappe.msgprint( frappe.msgprint(__("There was an issue connecting to Plaid's authentication server. Check browser console for more information"));
__(
"There was an issue connecting to Plaid's authentication server. Check browser console for more information"
)
);
console.log(error); console.log(error);
} }
plaid_success(token, response) { plaid_success(token, response) {
frappe frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.update_bank_account_ids', {
.xcall( response: response,
"erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.update_bank_account_ids", }).then(() => {
{ frappe.show_alert({ message: __('Plaid Link Updated'), indicator: 'green' });
response: response, });
}
)
.then(() => {
frappe.show_alert({ message: __("Plaid Link Updated"), indicator: "green" });
});
} }
}; };

View File

@@ -1,49 +1,45 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors // Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Bank Account", { frappe.ui.form.on('Bank Account', {
setup: function (frm) { setup: function(frm) {
frm.set_query("account", function () { frm.set_query("account", function() {
return { return {
filters: { filters: {
account_type: "Bank", 'account_type': 'Bank',
company: frm.doc.company, 'company': frm.doc.company,
is_group: 0, 'is_group': 0
}, }
}; };
}); });
frm.set_query("party_type", function () { frm.set_query("party_type", function() {
return { return {
query: "erpnext.setup.doctype.party_type.party_type.get_party_type", query: "erpnext.setup.doctype.party_type.party_type.get_party_type",
}; };
}); });
}, },
refresh: function (frm) { refresh: function(frm) {
frappe.dynamic_link = { doc: frm.doc, fieldname: "name", doctype: "Bank Account" }; frappe.dynamic_link = { doc: frm.doc, fieldname: 'name', doctype: 'Bank Account' }
frm.toggle_display(["address_html", "contact_html"], !frm.doc.__islocal); frm.toggle_display(['address_html','contact_html'], !frm.doc.__islocal);
if (frm.doc.__islocal) { if (frm.doc.__islocal) {
frappe.contacts.clear_address_and_contact(frm); frappe.contacts.clear_address_and_contact(frm);
} else { }
else {
frappe.contacts.render_address_and_contact(frm); frappe.contacts.render_address_and_contact(frm);
} }
if (frm.doc.integration_id) { if (frm.doc.integration_id) {
frm.add_custom_button(__("Unlink external integrations"), function () { frm.add_custom_button(__("Unlink external integrations"), function() {
frappe.confirm( frappe.confirm(__("This action will unlink this account from any external service integrating ERPNext with your bank accounts. It cannot be undone. Are you certain ?"), function() {
__( frm.set_value("integration_id", "");
"This action will unlink this account from any external service integrating ERPNext with your bank accounts. It cannot be undone. Are you certain ?" });
),
function () {
frm.set_value("integration_id", "");
}
);
}); });
} }
}, },
is_company_account: function (frm) { is_company_account: function(frm) {
frm.set_df_property("account", "reqd", frm.doc.is_company_account); frm.set_df_property('account', 'reqd', frm.doc.is_company_account);
}, }
}); });

View File

@@ -13,7 +13,6 @@
"account_type", "account_type",
"account_subtype", "account_subtype",
"column_break_7", "column_break_7",
"disabled",
"is_default", "is_default",
"is_company_account", "is_company_account",
"company", "company",
@@ -200,16 +199,10 @@
"fieldtype": "Data", "fieldtype": "Data",
"in_global_search": 1, "in_global_search": 1,
"label": "Branch Code" "label": "Branch Code"
},
{
"default": "0",
"fieldname": "disabled",
"fieldtype": "Check",
"label": "Disabled"
} }
], ],
"links": [], "links": [],
"modified": "2024-02-02 17:50:09.768835", "modified": "2022-05-04 15:49:42.620630",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Bank Account", "name": "Bank Account",

View File

@@ -9,7 +9,6 @@ from frappe.contacts.address_and_contact import (
load_address_and_contact, load_address_and_contact,
) )
from frappe.model.document import Document from frappe.model.document import Document
from frappe.utils import comma_and, get_link_to_form
class BankAccount(Document): class BankAccount(Document):
@@ -26,19 +25,6 @@ class BankAccount(Document):
def validate(self): def validate(self):
self.validate_company() self.validate_company()
self.validate_iban() self.validate_iban()
self.validate_account()
def validate_account(self):
if self.account:
if accounts := frappe.db.get_all(
"Bank Account", filters={"account": self.account, "name": ["!=", self.name]}, as_list=1
):
frappe.throw(
_("'{0}' account is already used by {1}. Use another account.").format(
frappe.bold(self.account),
frappe.bold(comma_and([get_link_to_form(self.doctype, x[0]) for x in accounts])),
)
)
def validate_company(self): def validate_company(self):
if self.is_company_account and not self.company: if self.is_company_account and not self.company:

View File

@@ -1,6 +1,8 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors // Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Bank Account Subtype", { frappe.ui.form.on('Bank Account Subtype', {
refresh: function () {}, refresh: function() {
}
}); });

View File

@@ -1,7 +1,8 @@
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors // Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Bank Account Type", { frappe.ui.form.on('Bank Account Type', {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -2,76 +2,80 @@
// License: GNU General Public License v3. See license.txt // License: GNU General Public License v3. See license.txt
frappe.ui.form.on("Bank Clearance", { frappe.ui.form.on("Bank Clearance", {
setup: function (frm) { setup: function(frm) {
frm.add_fetch("account", "account_currency", "account_currency"); frm.add_fetch("account", "account_currency", "account_currency");
frm.set_query("account", function () { frm.set_query("account", function() {
return { return {
filters: { "filters": {
account_type: ["in", ["Bank", "Cash"]], "account_type": ["in",["Bank","Cash"]],
is_group: 0, "is_group": 0,
}, }
}; };
}); });
frm.set_query("bank_account", function () { frm.set_query("bank_account", function () {
return { return {
filters: { filters: {
is_company_account: 1, 'is_company_account': 1
}, },
}; };
}); });
}, },
onload: function (frm) { onload: function(frm) {
let default_bank_account = frappe.defaults.get_user_default("Company")
? locals[":Company"][frappe.defaults.get_user_default("Company")]["default_bank_account"] let default_bank_account = frappe.defaults.get_user_default("Company")?
: ""; locals[":Company"][frappe.defaults.get_user_default("Company")]["default_bank_account"]: "";
frm.set_value("account", default_bank_account); frm.set_value("account", default_bank_account);
frm.set_value("from_date", frappe.datetime.month_start()); frm.set_value("from_date", frappe.datetime.month_start());
frm.set_value("to_date", frappe.datetime.month_end()); frm.set_value("to_date", frappe.datetime.month_end());
}, },
refresh: function (frm) { refresh: function(frm) {
frm.disable_save(); frm.disable_save();
frm.add_custom_button(__("Get Payment Entries"), () => frm.trigger("get_payment_entries")); frm.add_custom_button(__('Get Payment Entries'), () =>
frm.trigger("get_payment_entries")
);
frm.change_custom_button_type("Get Payment Entries", null, "primary"); frm.change_custom_button_type('Get Payment Entries', null, 'primary');
}, },
update_clearance_date: function (frm) { update_clearance_date: function(frm) {
return frappe.call({ return frappe.call({
method: "update_clearance_date", method: "update_clearance_date",
doc: frm.doc, doc: frm.doc,
callback: function (r, rt) { callback: function(r, rt) {
frm.refresh_field("payment_entries"); frm.refresh_field("payment_entries");
frm.refresh_fields(); frm.refresh_fields();
if (!frm.doc.payment_entries.length) { if (!frm.doc.payment_entries.length) {
frm.change_custom_button_type("Get Payment Entries", null, "primary"); frm.change_custom_button_type('Get Payment Entries', null, 'primary');
frm.change_custom_button_type("Update Clearance Date", null, "default"); frm.change_custom_button_type('Update Clearance Date', null, 'default');
} }
}, }
}); });
}, },
get_payment_entries: function (frm) { get_payment_entries: function(frm) {
return frappe.call({ return frappe.call({
method: "get_payment_entries", method: "get_payment_entries",
doc: frm.doc, doc: frm.doc,
callback: function (r, rt) { callback: function(r, rt) {
frm.refresh_field("payment_entries"); frm.refresh_field("payment_entries");
if (frm.doc.payment_entries.length) { if (frm.doc.payment_entries.length) {
frm.add_custom_button(__("Update Clearance Date"), () => frm.add_custom_button(__('Update Clearance Date'), () =>
frm.trigger("update_clearance_date") frm.trigger("update_clearance_date")
); );
frm.change_custom_button_type("Get Payment Entries", null, "default"); frm.change_custom_button_type('Get Payment Entries', null, 'default');
frm.change_custom_button_type("Update Clearance Date", null, "primary"); frm.change_custom_button_type('Update Clearance Date', null, 'primary');
} }
}, }
}); });
}, }
}); });

View File

@@ -1,39 +1,39 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors // Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt // For license information, please see license.txt
cur_frm.add_fetch("bank_account", "account", "account"); cur_frm.add_fetch('bank_account','account','account');
cur_frm.add_fetch("bank_account", "bank_account_no", "bank_account_no"); cur_frm.add_fetch('bank_account','bank_account_no','bank_account_no');
cur_frm.add_fetch("bank_account", "iban", "iban"); cur_frm.add_fetch('bank_account','iban','iban');
cur_frm.add_fetch("bank_account", "branch_code", "branch_code"); cur_frm.add_fetch('bank_account','branch_code','branch_code');
cur_frm.add_fetch("bank", "swift_number", "swift_number"); cur_frm.add_fetch('bank','swift_number','swift_number');
frappe.ui.form.on("Bank Guarantee", { frappe.ui.form.on('Bank Guarantee', {
setup: function (frm) { setup: function(frm) {
frm.set_query("bank", function () { frm.set_query("bank", function() {
return {
filters: {
company: frm.doc.company
}
};
});
frm.set_query("bank_account", function() {
return { return {
filters: { filters: {
company: frm.doc.company, company: frm.doc.company,
}, bank: frm.doc.bank
}; }
}
}); });
frm.set_query("bank_account", function () { frm.set_query("project", function() {
return { return {
filters: { filters: {
company: frm.doc.company, customer: frm.doc.customer
bank: frm.doc.bank, }
},
};
});
frm.set_query("project", function () {
return {
filters: {
customer: frm.doc.customer,
},
}; };
}); });
}, },
bg_type: function (frm) { bg_type: function(frm) {
if (frm.doc.bg_type == "Receiving") { if (frm.doc.bg_type == "Receiving") {
frm.set_value("reference_doctype", "Sales Order"); frm.set_value("reference_doctype", "Sales Order");
} else if (frm.doc.bg_type == "Providing") { } else if (frm.doc.bg_type == "Providing") {
@@ -41,33 +41,34 @@ frappe.ui.form.on("Bank Guarantee", {
} }
}, },
reference_docname: function (frm) { reference_docname: function(frm) {
if (frm.doc.reference_docname && frm.doc.reference_doctype) { if (frm.doc.reference_docname && frm.doc.reference_doctype) {
let party_field = frm.doc.reference_doctype == "Sales Order" ? "customer" : "supplier"; let party_field = frm.doc.reference_doctype == "Sales Order" ? "customer" : "supplier";
frappe.call({ frappe.call({
method: "erpnext.accounts.doctype.bank_guarantee.bank_guarantee.get_voucher_details", method: "erpnext.accounts.doctype.bank_guarantee.bank_guarantee.get_voucher_details",
args: { args: {
bank_guarantee_type: frm.doc.bg_type, "bank_guarantee_type": frm.doc.bg_type,
reference_name: frm.doc.reference_docname, "reference_name": frm.doc.reference_docname
}, },
callback: function (r) { callback: function(r) {
if (r.message) { if (r.message) {
if (r.message[party_field]) frm.set_value(party_field, r.message[party_field]); if (r.message[party_field]) frm.set_value(party_field, r.message[party_field]);
if (r.message.project) frm.set_value("project", r.message.project); if (r.message.project) frm.set_value("project", r.message.project);
if (r.message.grand_total) frm.set_value("amount", r.message.grand_total); if (r.message.grand_total) frm.set_value("amount", r.message.grand_total);
} }
}, }
}); });
} }
}, },
start_date: function (frm) { start_date: function(frm) {
var end_date = frappe.datetime.add_days(cur_frm.doc.start_date, cur_frm.doc.validity - 1); var end_date = frappe.datetime.add_days(cur_frm.doc.start_date, cur_frm.doc.validity - 1);
cur_frm.set_value("end_date", end_date); cur_frm.set_value("end_date", end_date);
}, },
validity: function (frm) { validity: function(frm) {
var end_date = frappe.datetime.add_days(cur_frm.doc.start_date, cur_frm.doc.validity - 1); var end_date = frappe.datetime.add_days(cur_frm.doc.start_date, cur_frm.doc.validity - 1);
cur_frm.set_value("end_date", end_date); cur_frm.set_value("end_date", end_date);
}, }
}); });

View File

@@ -8,22 +8,21 @@ frappe.ui.form.on("Bank Reconciliation Tool", {
return { return {
filters: { filters: {
company: frm.doc.company, company: frm.doc.company,
is_company_account: 1, 'is_company_account': 1
}, },
}; };
}); });
let no_bank_transactions_text = `<div class="text-muted text-center">${__( let no_bank_transactions_text =
"No Matching Bank Transactions Found" `<div class="text-muted text-center">${__("No Matching Bank Transactions Found")}</div>`
)}</div>`;
set_field_options("no_bank_transactions", no_bank_transactions_text); set_field_options("no_bank_transactions", no_bank_transactions_text);
}, },
onload: function (frm) { onload: function (frm) {
// Set default filter dates // Set default filter dates
let today = frappe.datetime.get_today(); let today = frappe.datetime.get_today()
frm.doc.bank_statement_from_date = frappe.datetime.add_months(today, -1); frm.doc.bank_statement_from_date = frappe.datetime.add_months(today, -1);
frm.doc.bank_statement_to_date = today; frm.doc.bank_statement_to_date = today;
frm.trigger("bank_account"); frm.trigger('bank_account');
}, },
filter_by_reference_date: function (frm) { filter_by_reference_date: function (frm) {
@@ -38,27 +37,34 @@ frappe.ui.form.on("Bank Reconciliation Tool", {
refresh: function (frm) { refresh: function (frm) {
frm.disable_save(); frm.disable_save();
frappe.require("bank-reconciliation-tool.bundle.js", () => frm.trigger("make_reconciliation_tool")); frappe.require("bank-reconciliation-tool.bundle.js", () =>
frm.trigger("make_reconciliation_tool")
frm.add_custom_button(__("Upload Bank Statement"), () =>
frappe.call({
method: "erpnext.accounts.doctype.bank_statement_import.bank_statement_import.upload_bank_statement",
args: {
dt: frm.doc.doctype,
dn: frm.doc.name,
company: frm.doc.company,
bank_account: frm.doc.bank_account,
},
callback: function (r) {
if (!r.exc) {
var doc = frappe.model.sync(r.message);
frappe.set_route("Form", doc[0].doctype, doc[0].name);
}
},
})
); );
frm.add_custom_button(__("Auto Reconcile"), function () { frm.add_custom_button(__("Upload Bank Statement"), () =>
frappe.call({
method:
"erpnext.accounts.doctype.bank_statement_import.bank_statement_import.upload_bank_statement",
args: {
dt: frm.doc.doctype,
dn: frm.doc.name,
company: frm.doc.company,
bank_account: frm.doc.bank_account,
},
callback: function (r) {
if (!r.exc) {
var doc = frappe.model.sync(r.message);
frappe.set_route(
"Form",
doc[0].doctype,
doc[0].name
);
}
},
})
);
frm.add_custom_button(__('Auto Reconcile'), function() {
frappe.call({ frappe.call({
method: "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.auto_reconcile_vouchers", method: "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.auto_reconcile_vouchers",
args: { args: {
@@ -69,22 +75,33 @@ frappe.ui.form.on("Bank Reconciliation Tool", {
from_reference_date: frm.doc.from_reference_date, from_reference_date: frm.doc.from_reference_date,
to_reference_date: frm.doc.to_reference_date, to_reference_date: frm.doc.to_reference_date,
}, },
}); })
}); });
frm.add_custom_button(__("Get Unreconciled Entries"), function () { frm.add_custom_button(__('Get Unreconciled Entries'), function() {
frm.trigger("make_reconciliation_tool"); frm.trigger("make_reconciliation_tool");
}); });
frm.change_custom_button_type("Get Unreconciled Entries", null, "primary"); frm.change_custom_button_type('Get Unreconciled Entries', null, 'primary');
}, },
bank_account: function (frm) { bank_account: function (frm) {
frappe.db.get_value("Bank Account", frm.doc.bank_account, "account", (r) => { frappe.db.get_value(
frappe.db.get_value("Account", r.account, "account_currency", (r) => { "Bank Account",
frm.doc.account_currency = r.account_currency; frm.doc.bank_account,
frm.trigger("render_chart"); "account",
}); (r) => {
}); frappe.db.get_value(
"Account",
r.account,
"account_currency",
(r) => {
frm.doc.account_currency = r.account_currency;
frm.trigger("render_chart");
}
);
}
);
frm.trigger("get_account_opening_balance"); frm.trigger("get_account_opening_balance");
}, },
@@ -103,7 +120,11 @@ frappe.ui.form.on("Bank Reconciliation Tool", {
) { ) {
frm.trigger("render_chart"); frm.trigger("render_chart");
frm.trigger("render"); frm.trigger("render");
frappe.utils.scroll_to(frm.get_field("reconciliation_tool_cards").$wrapper, true, 30); frappe.utils.scroll_to(
frm.get_field("reconciliation_tool_cards").$wrapper,
true,
30
);
} }
}); });
} }
@@ -112,10 +133,11 @@ frappe.ui.form.on("Bank Reconciliation Tool", {
get_account_opening_balance(frm) { get_account_opening_balance(frm) {
if (frm.doc.bank_account && frm.doc.bank_statement_from_date) { if (frm.doc.bank_account && frm.doc.bank_statement_from_date) {
frappe.call({ frappe.call({
method: "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.get_account_balance", method:
"erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.get_account_balance",
args: { args: {
bank_account: frm.doc.bank_account, bank_account: frm.doc.bank_account,
till_date: frappe.datetime.add_days(frm.doc.bank_statement_from_date, -1), till_date: frm.doc.bank_statement_from_date,
}, },
callback: (response) => { callback: (response) => {
frm.set_value("account_opening_balance", response.message); frm.set_value("account_opening_balance", response.message);
@@ -127,7 +149,8 @@ frappe.ui.form.on("Bank Reconciliation Tool", {
get_cleared_balance(frm) { get_cleared_balance(frm) {
if (frm.doc.bank_account && frm.doc.bank_statement_to_date) { if (frm.doc.bank_account && frm.doc.bank_statement_to_date) {
return frappe.call({ return frappe.call({
method: "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.get_account_balance", method:
"erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.get_account_balance",
args: { args: {
bank_account: frm.doc.bank_account, bank_account: frm.doc.bank_account,
till_date: frm.doc.bank_statement_to_date, till_date: frm.doc.bank_statement_to_date,
@@ -140,30 +163,41 @@ frappe.ui.form.on("Bank Reconciliation Tool", {
}, },
render_chart(frm) { render_chart(frm) {
frm.cards_manager = new erpnext.accounts.bank_reconciliation.NumberCardManager({ frm.cards_manager = new erpnext.accounts.bank_reconciliation.NumberCardManager(
$reconciliation_tool_cards: frm.get_field("reconciliation_tool_cards").$wrapper, {
bank_statement_closing_balance: frm.doc.bank_statement_closing_balance, $reconciliation_tool_cards: frm.get_field(
cleared_balance: frm.cleared_balance, "reconciliation_tool_cards"
currency: frm.doc.account_currency, ).$wrapper,
}); bank_statement_closing_balance:
frm.doc.bank_statement_closing_balance,
cleared_balance: frm.cleared_balance,
currency: frm.doc.account_currency,
}
);
}, },
render(frm) { render(frm) {
if (frm.doc.bank_account) { if (frm.doc.bank_account) {
frm.bank_reconciliation_data_table_manager = frm.bank_reconciliation_data_table_manager = new erpnext.accounts.bank_reconciliation.DataTableManager(
new erpnext.accounts.bank_reconciliation.DataTableManager({ {
company: frm.doc.company, company: frm.doc.company,
bank_account: frm.doc.bank_account, bank_account: frm.doc.bank_account,
$reconciliation_tool_dt: frm.get_field("reconciliation_tool_dt").$wrapper, $reconciliation_tool_dt: frm.get_field(
$no_bank_transactions: frm.get_field("no_bank_transactions").$wrapper, "reconciliation_tool_dt"
).$wrapper,
$no_bank_transactions: frm.get_field(
"no_bank_transactions"
).$wrapper,
bank_statement_from_date: frm.doc.bank_statement_from_date, bank_statement_from_date: frm.doc.bank_statement_from_date,
bank_statement_to_date: frm.doc.bank_statement_to_date, bank_statement_to_date: frm.doc.bank_statement_to_date,
filter_by_reference_date: frm.doc.filter_by_reference_date, filter_by_reference_date: frm.doc.filter_by_reference_date,
from_reference_date: frm.doc.from_reference_date, from_reference_date: frm.doc.from_reference_date,
to_reference_date: frm.doc.to_reference_date, to_reference_date: frm.doc.to_reference_date,
bank_statement_closing_balance: frm.doc.bank_statement_closing_balance, bank_statement_closing_balance:
frm.doc.bank_statement_closing_balance,
cards_manager: frm.cards_manager, cards_manager: frm.cards_manager,
}); }
);
} }
}, },
}); });

View File

@@ -17,7 +17,6 @@ from erpnext.accounts.report.bank_reconciliation_statement.bank_reconciliation_s
get_entries, get_entries,
) )
from erpnext.accounts.utils import get_balance_on from erpnext.accounts.utils import get_balance_on
from erpnext.setup.utils import get_exchange_rate
class BankReconciliationTool(Document): class BankReconciliationTool(Document):
@@ -130,7 +129,7 @@ def create_journal_entry_bts(
bank_transaction = frappe.db.get_values( bank_transaction = frappe.db.get_values(
"Bank Transaction", "Bank Transaction",
bank_transaction_name, bank_transaction_name,
fieldname=["name", "deposit", "withdrawal", "bank_account", "currency"], fieldname=["name", "deposit", "withdrawal", "bank_account"],
as_dict=True, as_dict=True,
)[0] )[0]
company_account = frappe.get_value("Bank Account", bank_transaction.bank_account, "account") company_account = frappe.get_value("Bank Account", bank_transaction.bank_account, "account")
@@ -144,94 +143,29 @@ def create_journal_entry_bts(
) )
company = frappe.get_value("Account", company_account, "company") company = frappe.get_value("Account", company_account, "company")
company_default_currency = frappe.get_cached_value("Company", company, "default_currency")
company_account_currency = frappe.get_cached_value("Account", company_account, "account_currency")
second_account_currency = frappe.get_cached_value("Account", second_account, "account_currency")
# determine if multi-currency Journal or not
is_multi_currency = (
True
if company_default_currency != company_account_currency
or company_default_currency != second_account_currency
or company_default_currency != bank_transaction.currency
else False
)
accounts = [] accounts = []
second_account_dict = { # Multi Currency?
"account": second_account, accounts.append(
"account_currency": second_account_currency, {
"credit_in_account_currency": bank_transaction.deposit, "account": second_account,
"debit_in_account_currency": bank_transaction.withdrawal, "credit_in_account_currency": bank_transaction.deposit,
"party_type": party_type, "debit_in_account_currency": bank_transaction.withdrawal,
"party": party, "party_type": party_type,
"cost_center": get_default_cost_center(company), "party": party,
} "cost_center": get_default_cost_center(company),
}
)
company_account_dict = { accounts.append(
"account": company_account, {
"account_currency": company_account_currency, "account": company_account,
"bank_account": bank_transaction.bank_account, "bank_account": bank_transaction.bank_account,
"credit_in_account_currency": bank_transaction.withdrawal, "credit_in_account_currency": bank_transaction.withdrawal,
"debit_in_account_currency": bank_transaction.deposit, "debit_in_account_currency": bank_transaction.deposit,
"cost_center": get_default_cost_center(company), "cost_center": get_default_cost_center(company),
} }
)
# convert transaction amount to company currency
if is_multi_currency:
exc_rate = get_exchange_rate(bank_transaction.currency, company_default_currency, posting_date)
withdrawal_in_company_currency = flt(exc_rate * abs(bank_transaction.withdrawal))
deposit_in_company_currency = flt(exc_rate * abs(bank_transaction.deposit))
else:
withdrawal_in_company_currency = bank_transaction.withdrawal
deposit_in_company_currency = bank_transaction.deposit
# if second account is of foreign currency, convert and set debit and credit fields.
if second_account_currency != company_default_currency:
exc_rate = get_exchange_rate(second_account_currency, company_default_currency, posting_date)
second_account_dict.update(
{
"exchange_rate": exc_rate,
"credit": deposit_in_company_currency,
"debit": withdrawal_in_company_currency,
"credit_in_account_currency": flt(deposit_in_company_currency / exc_rate) or 0,
"debit_in_account_currency": flt(withdrawal_in_company_currency / exc_rate) or 0,
}
)
else:
second_account_dict.update(
{
"exchange_rate": 1,
"credit": deposit_in_company_currency,
"debit": withdrawal_in_company_currency,
"credit_in_account_currency": deposit_in_company_currency,
"debit_in_account_currency": withdrawal_in_company_currency,
}
)
# if company account is of foreign currency, convert and set debit and credit fields.
if company_account_currency != company_default_currency:
exc_rate = get_exchange_rate(company_account_currency, company_default_currency, posting_date)
company_account_dict.update(
{
"exchange_rate": exc_rate,
"credit": withdrawal_in_company_currency,
"debit": deposit_in_company_currency,
}
)
else:
company_account_dict.update(
{
"exchange_rate": 1,
"credit": withdrawal_in_company_currency,
"debit": deposit_in_company_currency,
"credit_in_account_currency": withdrawal_in_company_currency,
"debit_in_account_currency": deposit_in_company_currency,
}
)
accounts.append(second_account_dict)
accounts.append(company_account_dict)
journal_entry_dict = { journal_entry_dict = {
"voucher_type": entry_type, "voucher_type": entry_type,
@@ -241,9 +175,6 @@ def create_journal_entry_bts(
"cheque_no": reference_number, "cheque_no": reference_number,
"mode_of_payment": mode_of_payment, "mode_of_payment": mode_of_payment,
} }
if is_multi_currency:
journal_entry_dict.update({"multi_currency": True})
journal_entry = frappe.new_doc("Journal Entry") journal_entry = frappe.new_doc("Journal Entry")
journal_entry.update(journal_entry_dict) journal_entry.update(journal_entry_dict)
journal_entry.set("accounts", accounts) journal_entry.set("accounts", accounts)

View File

@@ -2,24 +2,16 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Bank Statement Import", { frappe.ui.form.on("Bank Statement Import", {
onload(frm) {
frm.set_query("bank_account", function (doc) {
return {
filters: {
company: doc.company,
},
};
});
},
setup(frm) { setup(frm) {
frappe.realtime.on("data_import_refresh", ({ data_import }) => { frappe.realtime.on("data_import_refresh", ({ data_import }) => {
frm.import_in_progress = false; frm.import_in_progress = false;
if (data_import !== frm.doc.name) return; if (data_import !== frm.doc.name) return;
frappe.model.clear_doc("Bank Statement Import", frm.doc.name); frappe.model.clear_doc("Bank Statement Import", frm.doc.name);
frappe.model.with_doc("Bank Statement Import", frm.doc.name).then(() => { frappe.model
frm.refresh(); .with_doc("Bank Statement Import", frm.doc.name)
}); .then(() => {
frm.refresh();
});
}); });
frappe.realtime.on("data_import_progress", (data) => { frappe.realtime.on("data_import_progress", (data) => {
frm.import_in_progress = true; frm.import_in_progress = true;
@@ -46,9 +38,20 @@ frappe.ui.form.on("Bank Statement Import", {
: __("Updating {0} of {1}, {2}", message_args); : __("Updating {0} of {1}, {2}", message_args);
} }
if (data.skipping) { if (data.skipping) {
message = __("Skipping {0} of {1}, {2}", [data.current, data.total, eta_message]); message = __(
"Skipping {0} of {1}, {2}",
[
data.current,
data.total,
eta_message,
]
);
} }
frm.dashboard.show_progress(__("Import Progress"), percent, message); frm.dashboard.show_progress(
__("Import Progress"),
percent,
message
);
frm.page.set_indicator(__("In Progress"), "orange"); frm.page.set_indicator(__("In Progress"), "orange");
// hide progress when complete // hide progress when complete
@@ -90,12 +93,15 @@ frappe.ui.form.on("Bank Statement Import", {
frm.trigger("show_report_error_button"); frm.trigger("show_report_error_button");
if (frm.doc.status === "Partial Success") { if (frm.doc.status === "Partial Success") {
frm.add_custom_button(__("Export Errored Rows"), () => frm.trigger("export_errored_rows")); frm.add_custom_button(__("Export Errored Rows"), () =>
frm.trigger("export_errored_rows")
);
} }
if (frm.doc.status.includes("Success")) { if (frm.doc.status.includes("Success")) {
frm.add_custom_button(__("Go to {0} List", [__(frm.doc.reference_doctype)]), () => frm.add_custom_button(
frappe.set_route("List", frm.doc.reference_doctype) __("Go to {0} List", [__(frm.doc.reference_doctype)]),
() => frappe.set_route("List", frm.doc.reference_doctype)
); );
} }
}, },
@@ -112,8 +118,13 @@ frappe.ui.form.on("Bank Statement Import", {
frm.disable_save(); frm.disable_save();
if (frm.doc.status !== "Success") { if (frm.doc.status !== "Success") {
if (!frm.is_new() && frm.has_import_file()) { if (!frm.is_new() && frm.has_import_file()) {
let label = frm.doc.status === "Pending" ? __("Start Import") : __("Retry"); let label =
frm.page.set_primary_action(label, () => frm.events.start_import(frm)); frm.doc.status === "Pending"
? __("Start Import")
: __("Retry");
frm.page.set_primary_action(label, () =>
frm.events.start_import(frm)
);
} else { } else {
frm.page.set_primary_action(__("Save"), () => frm.save()); frm.page.set_primary_action(__("Save"), () => frm.save());
} }
@@ -155,24 +166,24 @@ frappe.ui.form.on("Bank Statement Import", {
message = message =
successful_records.length > 1 successful_records.length > 1
? __( ? __(
"Successfully imported {0} records out of {1}. Click on Export Errored Rows, fix the errors and import again.", "Successfully imported {0} records out of {1}. Click on Export Errored Rows, fix the errors and import again.",
message_args message_args
) )
: __( : __(
"Successfully imported {0} record out of {1}. Click on Export Errored Rows, fix the errors and import again.", "Successfully imported {0} record out of {1}. Click on Export Errored Rows, fix the errors and import again.",
message_args message_args
); );
} else { } else {
message = message =
successful_records.length > 1 successful_records.length > 1
? __( ? __(
"Successfully updated {0} records out of {1}. Click on Export Errored Rows, fix the errors and import again.", "Successfully updated {0} records out of {1}. Click on Export Errored Rows, fix the errors and import again.",
message_args message_args
) )
: __( : __(
"Successfully updated {0} record out of {1}. Click on Export Errored Rows, fix the errors and import again.", "Successfully updated {0} record out of {1}. Click on Export Errored Rows, fix the errors and import again.",
message_args message_args
); );
} }
} }
frm.dashboard.set_headline(message); frm.dashboard.set_headline(message);
@@ -215,7 +226,8 @@ frappe.ui.form.on("Bank Statement Import", {
}, },
download_template() { download_template() {
let method = "/api/method/frappe.core.doctype.data_import.data_import.download_template"; let method =
"/api/method/frappe.core.doctype.data_import.data_import.download_template";
open_url_post(method, { open_url_post(method, {
doctype: "Bank Transaction", doctype: "Bank Transaction",
@@ -228,7 +240,7 @@ frappe.ui.form.on("Bank Statement Import", {
"description", "description",
"reference_number", "reference_number",
"bank_account", "bank_account",
"currency", "currency"
], ],
}, },
}); });
@@ -299,7 +311,10 @@ frappe.ui.form.on("Bank Statement Import", {
show_import_preview(frm, preview_data) { show_import_preview(frm, preview_data) {
let import_log = JSON.parse(frm.doc.statement_import_log || "[]"); let import_log = JSON.parse(frm.doc.statement_import_log || "[]");
if (frm.import_preview && frm.import_preview.doctype === frm.doc.reference_doctype) { if (
frm.import_preview &&
frm.import_preview.doctype === frm.doc.reference_doctype
) {
frm.import_preview.preview_data = preview_data; frm.import_preview.preview_data = preview_data;
frm.import_preview.import_log = import_log; frm.import_preview.import_log = import_log;
frm.import_preview.refresh(); frm.import_preview.refresh();
@@ -315,10 +330,19 @@ frappe.ui.form.on("Bank Statement Import", {
frm, frm,
events: { events: {
remap_column(changed_map) { remap_column(changed_map) {
let template_options = JSON.parse(frm.doc.template_options || "{}"); let template_options = JSON.parse(
template_options.column_to_field_map = template_options.column_to_field_map || {}; frm.doc.template_options || "{}"
Object.assign(template_options.column_to_field_map, changed_map); );
frm.set_value("template_options", JSON.stringify(template_options)); template_options.column_to_field_map =
template_options.column_to_field_map || {};
Object.assign(
template_options.column_to_field_map,
changed_map
);
frm.set_value(
"template_options",
JSON.stringify(template_options)
);
frm.save().then(() => frm.trigger("import_file")); frm.save().then(() => frm.trigger("import_file"));
}, },
}, },
@@ -328,11 +352,10 @@ frappe.ui.form.on("Bank Statement Import", {
export_errored_rows(frm) { export_errored_rows(frm) {
open_url_post( open_url_post(
"/api/method/erpnext.accounts.doctype.bank_statement_import.bank_statement_import.download_errored_template", "/api/method/frappe.core.doctype.data_import.data_import.download_errored_template",
{ {
data_import_name: frm.doc.name, data_import_name: frm.doc.name,
}, }
true
); );
}, },
@@ -352,7 +375,8 @@ frappe.ui.form.on("Bank Statement Import", {
let other_warnings = []; let other_warnings = [];
for (let warning of warnings) { for (let warning of warnings) {
if (warning.row) { if (warning.row) {
warnings_by_row[warning.row] = warnings_by_row[warning.row] || []; warnings_by_row[warning.row] =
warnings_by_row[warning.row] || [];
warnings_by_row[warning.row].push(warning); warnings_by_row[warning.row].push(warning);
} else { } else {
other_warnings.push(warning); other_warnings.push(warning);
@@ -367,7 +391,9 @@ frappe.ui.form.on("Bank Statement Import", {
if (w.field) { if (w.field) {
let label = let label =
w.field.label + w.field.label +
(w.field.parent !== frm.doc.reference_doctype ? ` (${w.field.parent})` : ""); (w.field.parent !== frm.doc.reference_doctype
? ` (${w.field.parent})`
: "");
return `<li>${label}: ${w.message}</li>`; return `<li>${label}: ${w.message}</li>`;
} }
return `<li>${w.message}</li>`; return `<li>${w.message}</li>`;
@@ -386,9 +412,10 @@ frappe.ui.form.on("Bank Statement Import", {
.map((warning) => { .map((warning) => {
let header = ""; let header = "";
if (warning.col) { if (warning.col) {
let column_number = `<span class="text-uppercase">${__("Column {0}", [ let column_number = `<span class="text-uppercase">${__(
warning.col, "Column {0}",
])}</span>`; [warning.col]
)}</span>`;
let column_header = columns[warning.col].header_title; let column_header = columns[warning.col].header_title;
header = `${column_number} (${column_header})`; header = `${column_number} (${column_header})`;
} }
@@ -427,28 +454,36 @@ frappe.ui.form.on("Bank Statement Import", {
let html = ""; let html = "";
if (log.success) { if (log.success) {
if (frm.doc.import_type === "Insert New Records") { if (frm.doc.import_type === "Insert New Records") {
html = __("Successfully imported {0}", [ html = __(
`<span class="underline">${frappe.utils.get_form_link( "Successfully imported {0}", [
frm.doc.reference_doctype, `<span class="underline">${frappe.utils.get_form_link(
log.docname, frm.doc.reference_doctype,
true log.docname,
)}<span>`, true
]); )}<span>`,
]
);
} else { } else {
html = __("Successfully updated {0}", [ html = __(
`<span class="underline">${frappe.utils.get_form_link( "Successfully updated {0}", [
frm.doc.reference_doctype, `<span class="underline">${frappe.utils.get_form_link(
log.docname, frm.doc.reference_doctype,
true log.docname,
)}<span>`, true
]); )}<span>`,
]
);
} }
} else { } else {
let messages = log.messages let messages = log.messages
.map(JSON.parse) .map(JSON.parse)
.map((m) => { .map((m) => {
let title = m.title ? `<strong>${m.title}</strong>` : ""; let title = m.title
let message = m.message ? `<div>${m.message}</div>` : ""; ? `<strong>${m.title}</strong>`
: "";
let message = m.message
? `<div>${m.message}</div>`
: "";
return title + message; return title + message;
}) })
.join(""); .join("");

View File

@@ -1,34 +1,36 @@
let imports_in_progress = []; let imports_in_progress = [];
frappe.listview_settings["Bank Statement Import"] = { frappe.listview_settings['Bank Statement Import'] = {
onload(listview) { onload(listview) {
frappe.realtime.on("data_import_progress", (data) => { frappe.realtime.on('data_import_progress', data => {
if (!imports_in_progress.includes(data.data_import)) { if (!imports_in_progress.includes(data.data_import)) {
imports_in_progress.push(data.data_import); imports_in_progress.push(data.data_import);
} }
}); });
frappe.realtime.on("data_import_refresh", (data) => { frappe.realtime.on('data_import_refresh', data => {
imports_in_progress = imports_in_progress.filter((d) => d !== data.data_import); imports_in_progress = imports_in_progress.filter(
d => d !== data.data_import
);
listview.refresh(); listview.refresh();
}); });
}, },
get_indicator: function (doc) { get_indicator: function(doc) {
var colors = { var colors = {
Pending: "orange", 'Pending': 'orange',
"Not Started": "orange", 'Not Started': 'orange',
"Partial Success": "orange", 'Partial Success': 'orange',
Success: "green", 'Success': 'green',
"In Progress": "orange", 'In Progress': 'orange',
Error: "red", 'Error': 'red'
}; };
let status = doc.status; let status = doc.status;
if (imports_in_progress.includes(doc.name)) { if (imports_in_progress.includes(doc.name)) {
status = "In Progress"; status = 'In Progress';
} }
if (status == "Pending") { if (status == 'Pending') {
status = "Not Started"; status = 'Not Started';
} }
return [__(status), colors[status], "status,=," + doc.status]; return [__(status), colors[status], 'status,=,' + doc.status];
}, },
hide_name_column: true, hide_name_column: true
}; };

View File

@@ -112,8 +112,7 @@ class AutoMatchbyPartyNameDescription:
for party in parties: for party in parties:
filters = {"status": "Active"} if party == "Employee" else {"disabled": 0} filters = {"status": "Active"} if party == "Employee" else {"disabled": 0}
field = party.lower() + "_name" names = frappe.get_all(party, filters=filters, pluck=party.lower() + "_name")
names = frappe.get_all(party, filters=filters, fields=[f"{field} as party_name", "name"])
for field in ["bank_party_name", "description"]: for field in ["bank_party_name", "description"]:
if not self.get(field): if not self.get(field):
@@ -132,11 +131,7 @@ class AutoMatchbyPartyNameDescription:
def fuzzy_search_and_return_result(self, party, names, field) -> Union[Tuple, None]: def fuzzy_search_and_return_result(self, party, names, field) -> Union[Tuple, None]:
skip = False skip = False
result = process.extract( result = process.extract(query=self.get(field), choices=names, scorer=fuzz.token_set_ratio)
query=self.get(field),
choices={row.get("name"): row.get("party_name") for row in names},
scorer=fuzz.token_set_ratio,
)
party_name, skip = self.process_fuzzy_result(result) party_name, skip = self.process_fuzzy_result(result)
if not party_name: if not party_name:
@@ -154,14 +149,14 @@ class AutoMatchbyPartyNameDescription:
Returns: Result, Skip (whether or not to discontinue matching) Returns: Result, Skip (whether or not to discontinue matching)
""" """
SCORE, PARTY_ID, CUTOFF = 1, 2, 80 PARTY, SCORE, CUTOFF = 0, 1, 80
if not result or not len(result): if not result or not len(result):
return None, False return None, False
first_result = result[0] first_result = result[0]
if len(result) == 1: if len(result) == 1:
return (first_result[PARTY_ID] if first_result[SCORE] > CUTOFF else None), True return (first_result[PARTY] if first_result[SCORE] > CUTOFF else None), True
second_result = result[1] second_result = result[1]
if first_result[SCORE] > CUTOFF: if first_result[SCORE] > CUTOFF:
@@ -170,7 +165,7 @@ class AutoMatchbyPartyNameDescription:
if first_result[SCORE] == second_result[SCORE]: if first_result[SCORE] == second_result[SCORE]:
return None, True return None, True
return first_result[PARTY_ID], True return first_result[PARTY], True
else: else:
return None, False return None, False

View File

@@ -3,7 +3,7 @@
frappe.ui.form.on("Bank Transaction", { frappe.ui.form.on("Bank Transaction", {
onload(frm) { onload(frm) {
frm.set_query("payment_document", "payment_entries", function () { frm.set_query("payment_document", "payment_entries", function() {
const payment_doctypes = frm.events.get_payment_doctypes(frm); const payment_doctypes = frm.events.get_payment_doctypes(frm);
return { return {
filters: { filters: {
@@ -23,7 +23,7 @@ frappe.ui.form.on("Bank Transaction", {
set_bank_statement_filter(frm); set_bank_statement_filter(frm);
}, },
setup: function (frm) { setup: function(frm) {
frm.set_query("party_type", function () { frm.set_query("party_type", function () {
return { return {
filters: { filters: {
@@ -33,10 +33,16 @@ frappe.ui.form.on("Bank Transaction", {
}); });
}, },
get_payment_doctypes: function () { get_payment_doctypes: function() {
// get payment doctypes from all the apps // get payment doctypes from all the apps
return ["Payment Entry", "Journal Entry", "Sales Invoice", "Purchase Invoice", "Bank Transaction"]; return [
}, "Payment Entry",
"Journal Entry",
"Sales Invoice",
"Purchase Invoice",
"Bank Transaction",
];
}
}); });
frappe.ui.form.on("Bank Transaction Payments", { frappe.ui.form.on("Bank Transaction Payments", {
@@ -48,11 +54,10 @@ frappe.ui.form.on("Bank Transaction Payments", {
const update_clearance_date = (frm, cdt, cdn) => { const update_clearance_date = (frm, cdt, cdn) => {
if (frm.doc.docstatus === 1) { if (frm.doc.docstatus === 1) {
frappe frappe
.xcall("erpnext.accounts.doctype.bank_transaction.bank_transaction.unclear_reference_payment", { .xcall(
doctype: cdt, "erpnext.accounts.doctype.bank_transaction.bank_transaction.unclear_reference_payment",
docname: cdn, { doctype: cdt, docname: cdn, bt_name: frm.doc.name }
bt_name: frm.doc.name, )
})
.then((e) => { .then((e) => {
if (e == "success") { if (e == "success") {
frappe.show_alert({ frappe.show_alert({

View File

@@ -2,7 +2,6 @@
# For license information, please see license.txt # For license information, please see license.txt
import frappe import frappe
from frappe.model.docstatus import DocStatus
from frappe.utils import flt from frappe.utils import flt
from erpnext.controllers.status_updater import StatusUpdater from erpnext.controllers.status_updater import StatusUpdater
@@ -41,10 +40,9 @@ class BankTransaction(StatusUpdater):
else: else:
allocated_amount = 0.0 allocated_amount = 0.0
unallocated_amount = abs(flt(self.withdrawal) - flt(self.deposit)) - allocated_amount amount = abs(flt(self.withdrawal) - flt(self.deposit))
self.db_set("allocated_amount", flt(allocated_amount))
self.db_set("allocated_amount", flt(allocated_amount, self.precision("allocated_amount"))) self.db_set("unallocated_amount", amount - flt(allocated_amount))
self.db_set("unallocated_amount", flt(unallocated_amount, self.precision("unallocated_amount")))
self.reload() self.reload()
self.set_status(update=True) self.set_status(update=True)
@@ -70,7 +68,7 @@ class BankTransaction(StatusUpdater):
"payment_entry": voucher["payment_name"], "payment_entry": voucher["payment_name"],
"allocated_amount": 0.0, # Temporary "allocated_amount": 0.0, # Temporary
} }
self.append("payment_entries", pe) child = self.append("payment_entries", pe)
added = True added = True
# runs on_update_after_submit # runs on_update_after_submit
@@ -91,6 +89,7 @@ class BankTransaction(StatusUpdater):
- 0 > a: Error: already over-allocated - 0 > a: Error: already over-allocated
- clear means: set the latest transaction date as clearance date - clear means: set the latest transaction date as clearance date
""" """
gl_bank_account = frappe.db.get_value("Bank Account", self.bank_account, "account")
remaining_amount = self.unallocated_amount remaining_amount = self.unallocated_amount
for payment_entry in self.payment_entries: for payment_entry in self.payment_entries:
if payment_entry.allocated_amount == 0.0: if payment_entry.allocated_amount == 0.0:
@@ -395,21 +394,3 @@ def unclear_reference_payment(doctype, docname, bt_name):
bt = frappe.get_doc("Bank Transaction", bt_name) bt = frappe.get_doc("Bank Transaction", bt_name)
set_voucher_clearance(doctype, docname, None, bt) set_voucher_clearance(doctype, docname, None, bt)
return docname return docname
def remove_from_bank_transaction(doctype, docname):
"""Remove a (cancelled) voucher from all Bank Transactions."""
for bt_name in get_reconciled_bank_transactions(doctype, docname):
bt = frappe.get_doc("Bank Transaction", bt_name)
if bt.docstatus == DocStatus.cancelled():
continue
modified = False
for pe in bt.payment_entries:
if pe.payment_document == doctype and pe.payment_entry == docname:
bt.remove(pe)
modified = True
if modified:
bt.save()

View File

@@ -1,15 +1,15 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors // Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt // License: GNU General Public License v3. See license.txt
frappe.listview_settings["Bank Transaction"] = { frappe.listview_settings['Bank Transaction'] = {
add_fields: ["unallocated_amount"], add_fields: ["unallocated_amount"],
get_indicator: function (doc) { get_indicator: function(doc) {
if (doc.docstatus == 2) { if(doc.docstatus == 2) {
return [__("Cancelled"), "red", "docstatus,=,2"]; return [__("Cancelled"), "red", "docstatus,=,2"];
} else if (flt(doc.unallocated_amount) <= 0) { } else if(flt(doc.unallocated_amount)<=0) {
return [__("Reconciled"), "green", "unallocated_amount,=,0"]; return [__("Reconciled"), "green", "unallocated_amount,=,0"];
} else if (flt(doc.unallocated_amount) > 0) { } else if(flt(doc.unallocated_amount)>0) {
return [__("Unreconciled"), "orange", "unallocated_amount,>,0"]; return [__("Unreconciled"), "orange", "unallocated_amount,>,0"];
} }
}, }
}; };

View File

@@ -2,10 +2,10 @@
# See license.txt # See license.txt
import json import json
import unittest
import frappe import frappe
from frappe import utils from frappe import utils
from frappe.model.docstatus import DocStatus
from frappe.tests.utils import FrappeTestCase from frappe.tests.utils import FrappeTestCase
from erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool import ( from erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool import (
@@ -32,16 +32,8 @@ class TestBankTransaction(FrappeTestCase):
frappe.db.delete(dt) frappe.db.delete(dt)
make_pos_profile() make_pos_profile()
add_transactions()
# generate and use a uniq hash identifier for 'Bank Account' and it's linked GL 'Account' to avoid validation error add_vouchers()
uniq_identifier = frappe.generate_hash(length=10)
gl_account = create_gl_account("_Test Bank " + uniq_identifier)
bank_account = create_bank_account(
gl_account=gl_account, bank_account_name="Checking Account " + uniq_identifier
)
add_transactions(bank_account=bank_account)
add_vouchers(gl_account=gl_account)
# This test checks if ERPNext is able to provide a linked payment for a bank transaction based on the amount of the bank transaction. # This test checks if ERPNext is able to provide a linked payment for a bank transaction based on the amount of the bank transaction.
def test_linked_payments(self): def test_linked_payments(self):
@@ -89,29 +81,6 @@ class TestBankTransaction(FrappeTestCase):
clearance_date = frappe.db.get_value("Payment Entry", payment.name, "clearance_date") clearance_date = frappe.db.get_value("Payment Entry", payment.name, "clearance_date")
self.assertFalse(clearance_date) self.assertFalse(clearance_date)
def test_cancel_voucher(self):
bank_transaction = frappe.get_doc(
"Bank Transaction",
dict(description="1512567 BG/000003025 OPSKATTUZWXXX AT776000000098709849 Herr G"),
)
payment = frappe.get_doc("Payment Entry", dict(party="Mr G", paid_amount=1700))
vouchers = json.dumps(
[
{
"payment_doctype": "Payment Entry",
"payment_name": payment.name,
"amount": bank_transaction.unallocated_amount,
}
]
)
reconcile_vouchers(bank_transaction.name, vouchers)
payment.reload()
payment.cancel()
bank_transaction.reload()
self.assertEqual(bank_transaction.docstatus, DocStatus.submitted())
self.assertEqual(bank_transaction.unallocated_amount, 1700)
self.assertEqual(bank_transaction.payment_entries, [])
# Check if ERPNext can correctly filter a linked payments based on the debit/credit amount # Check if ERPNext can correctly filter a linked payments based on the debit/credit amount
def test_debit_credit_output(self): def test_debit_credit_output(self):
bank_transaction = frappe.get_doc( bank_transaction = frappe.get_doc(
@@ -221,9 +190,7 @@ class TestBankTransaction(FrappeTestCase):
self.assertEqual(linked_payments[0][2], repayment_entry.name) self.assertEqual(linked_payments[0][2], repayment_entry.name)
def create_bank_account( def create_bank_account(bank_name="Citi Bank", account_name="_Test Bank - _TC"):
bank_name="Citi Bank", gl_account="_Test Bank - _TC", bank_account_name="Checking Account"
):
try: try:
frappe.get_doc( frappe.get_doc(
{ {
@@ -235,35 +202,21 @@ def create_bank_account(
pass pass
try: try:
bank_account = frappe.get_doc( frappe.get_doc(
{ {
"doctype": "Bank Account", "doctype": "Bank Account",
"account_name": bank_account_name, "account_name": "Checking Account",
"bank": bank_name, "bank": bank_name,
"account": gl_account, "account": account_name,
} }
).insert(ignore_if_duplicate=True) ).insert(ignore_if_duplicate=True)
except frappe.DuplicateEntryError: except frappe.DuplicateEntryError:
pass pass
return bank_account.name
def add_transactions():
create_bank_account()
def create_gl_account(gl_account_name="_Test Bank - _TC"):
gl_account = frappe.get_doc(
{
"doctype": "Account",
"company": "_Test Company",
"parent_account": "Current Assets - _TC",
"account_type": "Bank",
"is_group": 0,
"account_name": gl_account_name,
}
).insert()
return gl_account.name
def add_transactions(bank_account="_Test Bank - _TC"):
doc = frappe.get_doc( doc = frappe.get_doc(
{ {
"doctype": "Bank Transaction", "doctype": "Bank Transaction",
@@ -271,7 +224,7 @@ def add_transactions(bank_account="_Test Bank - _TC"):
"date": "2018-10-23", "date": "2018-10-23",
"deposit": 1200, "deposit": 1200,
"currency": "INR", "currency": "INR",
"bank_account": bank_account, "bank_account": "Checking Account - Citi Bank",
} }
).insert() ).insert()
doc.submit() doc.submit()
@@ -283,7 +236,7 @@ def add_transactions(bank_account="_Test Bank - _TC"):
"date": "2018-10-23", "date": "2018-10-23",
"deposit": 1700, "deposit": 1700,
"currency": "INR", "currency": "INR",
"bank_account": bank_account, "bank_account": "Checking Account - Citi Bank",
} }
).insert() ).insert()
doc.submit() doc.submit()
@@ -295,7 +248,7 @@ def add_transactions(bank_account="_Test Bank - _TC"):
"date": "2018-10-26", "date": "2018-10-26",
"withdrawal": 690, "withdrawal": 690,
"currency": "INR", "currency": "INR",
"bank_account": bank_account, "bank_account": "Checking Account - Citi Bank",
} }
).insert() ).insert()
doc.submit() doc.submit()
@@ -307,7 +260,7 @@ def add_transactions(bank_account="_Test Bank - _TC"):
"date": "2018-10-27", "date": "2018-10-27",
"deposit": 3900, "deposit": 3900,
"currency": "INR", "currency": "INR",
"bank_account": bank_account, "bank_account": "Checking Account - Citi Bank",
} }
).insert() ).insert()
doc.submit() doc.submit()
@@ -319,13 +272,13 @@ def add_transactions(bank_account="_Test Bank - _TC"):
"date": "2018-10-27", "date": "2018-10-27",
"withdrawal": 109080, "withdrawal": 109080,
"currency": "INR", "currency": "INR",
"bank_account": bank_account, "bank_account": "Checking Account - Citi Bank",
} }
).insert() ).insert()
doc.submit() doc.submit()
def add_vouchers(gl_account="_Test Bank - _TC"): def add_vouchers():
try: try:
frappe.get_doc( frappe.get_doc(
{ {
@@ -341,7 +294,7 @@ def add_vouchers(gl_account="_Test Bank - _TC"):
pi = make_purchase_invoice(supplier="Conrad Electronic", qty=1, rate=690) pi = make_purchase_invoice(supplier="Conrad Electronic", qty=1, rate=690)
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account=gl_account) pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
pe.reference_no = "Conrad Oct 18" pe.reference_no = "Conrad Oct 18"
pe.reference_date = "2018-10-24" pe.reference_date = "2018-10-24"
pe.insert() pe.insert()
@@ -360,14 +313,14 @@ def add_vouchers(gl_account="_Test Bank - _TC"):
pass pass
pi = make_purchase_invoice(supplier="Mr G", qty=1, rate=1200) pi = make_purchase_invoice(supplier="Mr G", qty=1, rate=1200)
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account=gl_account) pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
pe.reference_no = "Herr G Oct 18" pe.reference_no = "Herr G Oct 18"
pe.reference_date = "2018-10-24" pe.reference_date = "2018-10-24"
pe.insert() pe.insert()
pe.submit() pe.submit()
pi = make_purchase_invoice(supplier="Mr G", qty=1, rate=1700) pi = make_purchase_invoice(supplier="Mr G", qty=1, rate=1700)
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account=gl_account) pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
pe.reference_no = "Herr G Nov 18" pe.reference_no = "Herr G Nov 18"
pe.reference_date = "2018-11-01" pe.reference_date = "2018-11-01"
pe.insert() pe.insert()
@@ -398,10 +351,10 @@ def add_vouchers(gl_account="_Test Bank - _TC"):
pass pass
pi = make_purchase_invoice(supplier="Poore Simon's", qty=1, rate=3900, is_paid=1, do_not_save=1) pi = make_purchase_invoice(supplier="Poore Simon's", qty=1, rate=3900, is_paid=1, do_not_save=1)
pi.cash_bank_account = gl_account pi.cash_bank_account = "_Test Bank - _TC"
pi.insert() pi.insert()
pi.submit() pi.submit()
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account=gl_account) pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
pe.reference_no = "Poore Simon's Oct 18" pe.reference_no = "Poore Simon's Oct 18"
pe.reference_date = "2018-10-28" pe.reference_date = "2018-10-28"
pe.paid_amount = 690 pe.paid_amount = 690
@@ -410,7 +363,7 @@ def add_vouchers(gl_account="_Test Bank - _TC"):
pe.submit() pe.submit()
si = create_sales_invoice(customer="Poore Simon's", qty=1, rate=3900) si = create_sales_invoice(customer="Poore Simon's", qty=1, rate=3900)
pe = get_payment_entry("Sales Invoice", si.name, bank_account=gl_account) pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank - _TC")
pe.reference_no = "Poore Simon's Oct 18" pe.reference_no = "Poore Simon's Oct 18"
pe.reference_date = "2018-10-28" pe.reference_date = "2018-10-28"
pe.insert() pe.insert()
@@ -433,12 +386,16 @@ def add_vouchers(gl_account="_Test Bank - _TC"):
if not frappe.db.get_value( if not frappe.db.get_value(
"Mode of Payment Account", {"company": "_Test Company", "parent": "Cash"} "Mode of Payment Account", {"company": "_Test Company", "parent": "Cash"}
): ):
mode_of_payment.append("accounts", {"company": "_Test Company", "default_account": gl_account}) mode_of_payment.append(
"accounts", {"company": "_Test Company", "default_account": "_Test Bank - _TC"}
)
mode_of_payment.save() mode_of_payment.save()
si = create_sales_invoice(customer="Fayva", qty=1, rate=109080, do_not_save=1) si = create_sales_invoice(customer="Fayva", qty=1, rate=109080, do_not_save=1)
si.is_pos = 1 si.is_pos = 1
si.append("payments", {"mode_of_payment": "Cash", "account": gl_account, "amount": 109080}) si.append(
"payments", {"mode_of_payment": "Cash", "account": "_Test Bank - _TC", "amount": 109080}
)
si.insert() si.insert()
si.submit() si.submit()

View File

@@ -1,100 +0,0 @@
// Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on("Bisect Accounting Statements", {
onload(frm) {
frm.trigger("render_heatmap");
},
refresh(frm) {
frm.add_custom_button(__("Bisect Left"), () => {
frm.trigger("bisect_left");
});
frm.add_custom_button(__("Bisect Right"), () => {
frm.trigger("bisect_right");
});
frm.add_custom_button(__("Up"), () => {
frm.trigger("move_up");
});
frm.add_custom_button(__("Build Tree"), () => {
frm.trigger("build_tree");
});
},
render_heatmap(frm) {
let bisect_heatmap = frm.get_field("bisect_heatmap").$wrapper;
bisect_heatmap.addClass("bisect_heatmap_location");
// milliseconds in a day
let msiad = 24 * 60 * 60 * 1000;
let datapoints = {};
let fr_dt = new Date(frm.doc.from_date).getTime();
let to_dt = new Date(frm.doc.to_date).getTime();
let bisect_start = new Date(frm.doc.current_from_date).getTime();
let bisect_end = new Date(frm.doc.current_to_date).getTime();
for (let x = fr_dt; x <= to_dt; x += msiad) {
let epoch_in_seconds = x / 1000;
if (bisect_start <= x && x <= bisect_end) {
datapoints[epoch_in_seconds] = 1.0;
} else {
datapoints[epoch_in_seconds] = 0.0;
}
}
new frappe.Chart(".bisect_heatmap_location", {
type: "heatmap",
data: {
dataPoints: datapoints,
start: new Date(frm.doc.from_date),
end: new Date(frm.doc.to_date),
},
countLabel: "Bisecting",
discreteDomains: 1,
});
},
bisect_left(frm) {
frm.call({
doc: frm.doc,
method: "bisect_left",
freeze: true,
freeze_message: __("Bisecting Left ..."),
callback: (r) => {
frm.trigger("render_heatmap");
},
});
},
bisect_right(frm) {
frm.call({
doc: frm.doc,
freeze: true,
freeze_message: __("Bisecting Right ..."),
method: "bisect_right",
callback: (r) => {
frm.trigger("render_heatmap");
},
});
},
move_up(frm) {
frm.call({
doc: frm.doc,
freeze: true,
freeze_message: __("Moving up in tree ..."),
method: "move_up",
callback: (r) => {
frm.trigger("render_heatmap");
},
});
},
build_tree(frm) {
frm.call({
doc: frm.doc,
freeze: true,
freeze_message: __("Rebuilding BTree for period ..."),
method: "build_tree",
callback: (r) => {
frm.trigger("render_heatmap");
},
});
},
});

View File

@@ -1,194 +0,0 @@
{
"actions": [],
"allow_rename": 1,
"creation": "2023-09-15 21:28:28.054773",
"default_view": "List",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"section_break_cvfg",
"company",
"column_break_hcam",
"from_date",
"column_break_qxbi",
"to_date",
"column_break_iwny",
"algorithm",
"section_break_8ph9",
"current_node",
"section_break_ngid",
"bisect_heatmap",
"section_break_hmsy",
"bisecting_from",
"current_from_date",
"column_break_uqyd",
"bisecting_to",
"current_to_date",
"section_break_hbyo",
"heading_cppb",
"p_l_summary",
"column_break_aivo",
"balance_sheet_summary",
"b_s_summary",
"column_break_gvwx",
"difference_heading",
"difference"
],
"fields": [
{
"fieldname": "column_break_qxbi",
"fieldtype": "Column Break"
},
{
"fieldname": "from_date",
"fieldtype": "Datetime",
"label": "From Date"
},
{
"fieldname": "to_date",
"fieldtype": "Datetime",
"label": "To Date"
},
{
"default": "BFS",
"fieldname": "algorithm",
"fieldtype": "Select",
"label": "Algorithm",
"options": "BFS\nDFS"
},
{
"fieldname": "column_break_iwny",
"fieldtype": "Column Break"
},
{
"fieldname": "current_node",
"fieldtype": "Link",
"label": "Current Node",
"options": "Bisect Nodes"
},
{
"fieldname": "section_break_hmsy",
"fieldtype": "Section Break"
},
{
"fieldname": "current_from_date",
"fieldtype": "Datetime",
"read_only": 1
},
{
"fieldname": "current_to_date",
"fieldtype": "Datetime",
"read_only": 1
},
{
"fieldname": "column_break_uqyd",
"fieldtype": "Column Break"
},
{
"fieldname": "section_break_hbyo",
"fieldtype": "Section Break"
},
{
"fieldname": "p_l_summary",
"fieldtype": "Float",
"read_only": 1
},
{
"fieldname": "b_s_summary",
"fieldtype": "Float",
"read_only": 1
},
{
"fieldname": "difference",
"fieldtype": "Float",
"read_only": 1
},
{
"fieldname": "column_break_aivo",
"fieldtype": "Column Break"
},
{
"fieldname": "column_break_gvwx",
"fieldtype": "Column Break"
},
{
"fieldname": "company",
"fieldtype": "Link",
"label": "Company",
"options": "Company"
},
{
"fieldname": "column_break_hcam",
"fieldtype": "Column Break"
},
{
"fieldname": "section_break_ngid",
"fieldtype": "Section Break"
},
{
"fieldname": "section_break_8ph9",
"fieldtype": "Section Break",
"hidden": 1
},
{
"fieldname": "bisect_heatmap",
"fieldtype": "HTML",
"label": "Heatmap"
},
{
"fieldname": "heading_cppb",
"fieldtype": "Heading",
"label": "Profit and Loss Summary"
},
{
"fieldname": "balance_sheet_summary",
"fieldtype": "Heading",
"label": "Balance Sheet Summary"
},
{
"fieldname": "difference_heading",
"fieldtype": "Heading",
"label": "Difference"
},
{
"fieldname": "bisecting_from",
"fieldtype": "Heading",
"label": "Bisecting From"
},
{
"fieldname": "bisecting_to",
"fieldtype": "Heading",
"label": "Bisecting To"
},
{
"fieldname": "section_break_cvfg",
"fieldtype": "Section Break"
}
],
"hide_toolbar": 1,
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2023-12-01 16:49:54.073890",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bisect Accounting Statements",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"print": 1,
"read": 1,
"role": "Administrator",
"share": 1,
"write": 1
}
],
"read_only": 1,
"sort_field": "modified",
"sort_order": "DESC",
"states": []
}

View File

@@ -1,226 +0,0 @@
# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
import datetime
from collections import deque
from math import floor
import frappe
from dateutil.relativedelta import relativedelta
from frappe import _
from frappe.model.document import Document
from frappe.utils import getdate
from frappe.utils.data import guess_date_format
class BisectAccountingStatements(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
algorithm: DF.Literal["BFS", "DFS"]
b_s_summary: DF.Float
company: DF.Link | None
current_from_date: DF.Datetime | None
current_node: DF.Link | None
current_to_date: DF.Datetime | None
difference: DF.Float
from_date: DF.Datetime | None
p_l_summary: DF.Float
to_date: DF.Datetime | None
# end: auto-generated types
def validate(self):
self.validate_dates()
def validate_dates(self):
if getdate(self.from_date) > getdate(self.to_date):
frappe.throw(
_("From Date: {0} cannot be greater than To date: {1}").format(
frappe.bold(self.from_date), frappe.bold(self.to_date)
)
)
def bfs(self, from_date: datetime, to_date: datetime):
# Make Root node
node = frappe.new_doc("Bisect Nodes")
node.root = None
node.period_from_date = from_date
node.period_to_date = to_date
node.insert()
period_queue = deque([node])
while period_queue:
cur_node = period_queue.popleft()
delta = cur_node.period_to_date - cur_node.period_from_date
if delta.days == 0:
continue
else:
cur_floor = floor(delta.days / 2)
next_to_date = cur_node.period_from_date + relativedelta(days=+cur_floor)
left_node = frappe.new_doc("Bisect Nodes")
left_node.period_from_date = cur_node.period_from_date
left_node.period_to_date = next_to_date
left_node.root = cur_node.name
left_node.generated = False
left_node.insert()
cur_node.left_child = left_node.name
period_queue.append(left_node)
next_from_date = cur_node.period_from_date + relativedelta(days=+(cur_floor + 1))
right_node = frappe.new_doc("Bisect Nodes")
right_node.period_from_date = next_from_date
right_node.period_to_date = cur_node.period_to_date
right_node.root = cur_node.name
right_node.generated = False
right_node.insert()
cur_node.right_child = right_node.name
period_queue.append(right_node)
cur_node.save()
def dfs(self, from_date: datetime, to_date: datetime):
# Make Root node
node = frappe.new_doc("Bisect Nodes")
node.root = None
node.period_from_date = from_date
node.period_to_date = to_date
node.insert()
period_stack = [node]
while period_stack:
cur_node = period_stack.pop()
delta = cur_node.period_to_date - cur_node.period_from_date
if delta.days == 0:
continue
else:
cur_floor = floor(delta.days / 2)
next_to_date = cur_node.period_from_date + relativedelta(days=+cur_floor)
left_node = frappe.new_doc("Bisect Nodes")
left_node.period_from_date = cur_node.period_from_date
left_node.period_to_date = next_to_date
left_node.root = cur_node.name
left_node.generated = False
left_node.insert()
cur_node.left_child = left_node.name
period_stack.append(left_node)
next_from_date = cur_node.period_from_date + relativedelta(days=+(cur_floor + 1))
right_node = frappe.new_doc("Bisect Nodes")
right_node.period_from_date = next_from_date
right_node.period_to_date = cur_node.period_to_date
right_node.root = cur_node.name
right_node.generated = False
right_node.insert()
cur_node.right_child = right_node.name
period_stack.append(right_node)
cur_node.save()
@frappe.whitelist()
def build_tree(self):
frappe.db.delete("Bisect Nodes")
# Convert str to datetime format
dt_format = guess_date_format(self.from_date)
from_date = datetime.datetime.strptime(self.from_date, dt_format)
to_date = datetime.datetime.strptime(self.to_date, dt_format)
if self.algorithm == "BFS":
self.bfs(from_date, to_date)
if self.algorithm == "DFS":
self.dfs(from_date, to_date)
# set root as current node
root = frappe.db.get_all("Bisect Nodes", filters={"root": ["is", "not set"]})[0]
self.get_report_summary()
self.current_node = root.name
self.current_from_date = self.from_date
self.current_to_date = self.to_date
self.save()
def get_report_summary(self):
filters = {
"company": self.company,
"filter_based_on": "Date Range",
"period_start_date": self.current_from_date,
"period_end_date": self.current_to_date,
"periodicity": "Yearly",
}
pl_summary = frappe.get_doc("Report", "Profit and Loss Statement")
self.p_l_summary = pl_summary.execute_script_report(filters=filters)[5]
bs_summary = frappe.get_doc("Report", "Balance Sheet")
self.b_s_summary = bs_summary.execute_script_report(filters=filters)[5]
self.difference = abs(self.p_l_summary - self.b_s_summary)
def update_node(self):
current_node = frappe.get_doc("Bisect Nodes", self.current_node)
current_node.balance_sheet_summary = self.b_s_summary
current_node.profit_loss_summary = self.p_l_summary
current_node.difference = self.difference
current_node.generated = True
current_node.save()
def current_node_has_summary_info(self):
"Assertion method"
return frappe.db.get_value("Bisect Nodes", self.current_node, "generated")
def fetch_summary_info_from_current_node(self):
current_node = frappe.get_doc("Bisect Nodes", self.current_node)
self.p_l_summary = current_node.balance_sheet_summary
self.b_s_summary = current_node.profit_loss_summary
self.difference = abs(self.p_l_summary - self.b_s_summary)
def fetch_or_calculate(self):
if self.current_node_has_summary_info():
self.fetch_summary_info_from_current_node()
else:
self.get_report_summary()
self.update_node()
@frappe.whitelist()
def bisect_left(self):
if self.current_node is not None:
cur_node = frappe.get_doc("Bisect Nodes", self.current_node)
if cur_node.left_child is not None:
lft_node = frappe.get_doc("Bisect Nodes", cur_node.left_child)
self.current_node = cur_node.left_child
self.current_from_date = lft_node.period_from_date
self.current_to_date = lft_node.period_to_date
self.fetch_or_calculate()
self.save()
else:
frappe.msgprint(_("No more children on Left"))
@frappe.whitelist()
def bisect_right(self):
if self.current_node is not None:
cur_node = frappe.get_doc("Bisect Nodes", self.current_node)
if cur_node.right_child is not None:
rgt_node = frappe.get_doc("Bisect Nodes", cur_node.right_child)
self.current_node = cur_node.right_child
self.current_from_date = rgt_node.period_from_date
self.current_to_date = rgt_node.period_to_date
self.fetch_or_calculate()
self.save()
else:
frappe.msgprint(_("No more children on Right"))
@frappe.whitelist()
def move_up(self):
if self.current_node is not None:
cur_node = frappe.get_doc("Bisect Nodes", self.current_node)
if cur_node.root is not None:
root = frappe.get_doc("Bisect Nodes", cur_node.root)
self.current_node = cur_node.root
self.current_from_date = root.period_from_date
self.current_to_date = root.period_to_date
self.fetch_or_calculate()
self.save()
else:
frappe.msgprint(_("Reached Root"))

View File

@@ -1,9 +0,0 @@
# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
# import frappe
from frappe.tests.utils import FrappeTestCase
class TestBisectAccountingStatements(FrappeTestCase):
pass

View File

@@ -1,8 +0,0 @@
// Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
// frappe.ui.form.on("Bisect Nodes", {
// refresh(frm) {
// },
// });

View File

@@ -1,97 +0,0 @@
{
"actions": [],
"autoname": "autoincrement",
"creation": "2023-09-27 14:56:38.112462",
"default_view": "List",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"root",
"left_child",
"right_child",
"period_from_date",
"period_to_date",
"difference",
"balance_sheet_summary",
"profit_loss_summary",
"generated"
],
"fields": [
{
"fieldname": "root",
"fieldtype": "Link",
"label": "Root",
"options": "Bisect Nodes"
},
{
"fieldname": "left_child",
"fieldtype": "Link",
"label": "Left Child",
"options": "Bisect Nodes"
},
{
"fieldname": "right_child",
"fieldtype": "Link",
"label": "Right Child",
"options": "Bisect Nodes"
},
{
"fieldname": "period_from_date",
"fieldtype": "Datetime",
"label": "Period_from_date"
},
{
"fieldname": "period_to_date",
"fieldtype": "Datetime",
"label": "Period To Date"
},
{
"fieldname": "difference",
"fieldtype": "Float",
"label": "Difference"
},
{
"fieldname": "balance_sheet_summary",
"fieldtype": "Float",
"label": "Balance Sheet Summary"
},
{
"fieldname": "profit_loss_summary",
"fieldtype": "Float",
"label": "Profit and Loss Summary"
},
{
"default": "0",
"fieldname": "generated",
"fieldtype": "Check",
"label": "Generated"
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2023-12-01 17:46:12.437996",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bisect Nodes",
"naming_rule": "Autoincrement",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Administrator",
"share": 1,
"write": 1
}
],
"read_only": 1,
"sort_field": "modified",
"sort_order": "DESC",
"states": []
}

View File

@@ -1,29 +0,0 @@
# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class BisectNodes(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
balance_sheet_summary: DF.Float
difference: DF.Float
generated: DF.Check
left_child: DF.Link | None
name: DF.Int | None
period_from_date: DF.Datetime | None
period_to_date: DF.Datetime | None
profit_loss_summary: DF.Float
right_child: DF.Link | None
root: DF.Link | None
# end: auto-generated types
pass

View File

@@ -1,9 +0,0 @@
# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
# import frappe
from frappe.tests.utils import FrappeTestCase
class TestBisectNodes(FrappeTestCase):
pass

View File

@@ -2,48 +2,48 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.provide("erpnext.accounts.dimensions"); frappe.provide("erpnext.accounts.dimensions");
frappe.ui.form.on("Budget", { frappe.ui.form.on('Budget', {
onload: function (frm) { onload: function(frm) {
frm.set_query("account", "accounts", function () { frm.set_query("account", "accounts", function() {
return { return {
filters: { filters: {
company: frm.doc.company, company: frm.doc.company,
report_type: "Profit and Loss", report_type: "Profit and Loss",
is_group: 0, is_group: 0
}, }
}; };
}); });
frm.set_query("monthly_distribution", function () { frm.set_query("monthly_distribution", function() {
return { return {
filters: { filters: {
fiscal_year: frm.doc.fiscal_year, fiscal_year: frm.doc.fiscal_year
}, }
}; };
}); });
erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype); erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
}, },
refresh: function (frm) { refresh: function(frm) {
frm.trigger("toggle_reqd_fields"); frm.trigger("toggle_reqd_fields")
}, },
budget_against: function (frm) { budget_against: function(frm) {
frm.trigger("set_null_value"); frm.trigger("set_null_value")
frm.trigger("toggle_reqd_fields"); frm.trigger("toggle_reqd_fields")
}, },
set_null_value: function (frm) { set_null_value: function(frm) {
if (frm.doc.budget_against == "Cost Center") { if(frm.doc.budget_against == 'Cost Center') {
frm.set_value("project", null); frm.set_value('project', null)
} else { } else {
frm.set_value("cost_center", null); frm.set_value('cost_center', null)
} }
}, },
toggle_reqd_fields: function (frm) { toggle_reqd_fields: function(frm) {
frm.toggle_reqd("cost_center", frm.doc.budget_against == "Cost Center"); frm.toggle_reqd("cost_center", frm.doc.budget_against=="Cost Center");
frm.toggle_reqd("project", frm.doc.budget_against == "Project"); frm.toggle_reqd("project", frm.doc.budget_against=="Project");
}, }
}); });

View File

@@ -109,8 +109,6 @@ class Budget(Document):
def validate_expense_against_budget(args, expense_amount=0): def validate_expense_against_budget(args, expense_amount=0):
args = frappe._dict(args) args = frappe._dict(args)
if not frappe.get_all("Budget", limit=1):
return
if args.get("company") and not args.fiscal_year: if args.get("company") and not args.fiscal_year:
args.fiscal_year = get_fiscal_year(args.get("posting_date"), company=args.get("company"))[0] args.fiscal_year = get_fiscal_year(args.get("posting_date"), company=args.get("company"))[0]
@@ -118,11 +116,6 @@ def validate_expense_against_budget(args, expense_amount=0):
"Company", args.get("company"), "exception_budget_approver_role" "Company", args.get("company"), "exception_budget_approver_role"
) )
if not frappe.get_cached_value(
"Budget", {"fiscal_year": args.fiscal_year, "company": args.company}
): # nosec
return
if not args.account: if not args.account:
args.account = args.get("expense_account") args.account = args.get("expense_account")
@@ -149,13 +142,13 @@ def validate_expense_against_budget(args, expense_amount=0):
if ( if (
args.get(budget_against) args.get(budget_against)
and args.account and args.account
and (frappe.get_cached_value("Account", args.account, "root_type") == "Expense") and frappe.db.get_value("Account", {"name": args.account, "root_type": "Expense"})
): ):
doctype = dimension.get("document_type") doctype = dimension.get("document_type")
if frappe.get_cached_value("DocType", doctype, "is_tree"): if frappe.get_cached_value("DocType", doctype, "is_tree"):
lft, rgt = frappe.get_cached_value(doctype, args.get(budget_against), ["lft", "rgt"]) lft, rgt = frappe.db.get_value(doctype, args.get(budget_against), ["lft", "rgt"])
condition = """and exists(select name from `tab%s` condition = """and exists(select name from `tab%s`
where lft<=%s and rgt>=%s and name=b.%s)""" % ( where lft<=%s and rgt>=%s and name=b.%s)""" % (
doctype, doctype,

View File

@@ -1,42 +1,94 @@
{ {
"actions": [], "allow_copy": 0,
"creation": "2016-05-16 11:54:09.286135", "allow_import": 0,
"doctype": "DocType", "allow_rename": 0,
"editable_grid": 1, "beta": 0,
"engine": "InnoDB", "creation": "2016-05-16 11:54:09.286135",
"field_order": [ "custom": 0,
"account", "docstatus": 0,
"budget_amount" "doctype": "DocType",
], "document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [ "fields": [
{ {
"fieldname": "account", "allow_on_submit": 0,
"fieldtype": "Link", "bold": 0,
"in_list_view": 1, "collapsible": 0,
"label": "Account", "columns": 0,
"options": "Account", "fieldname": "account",
"reqd": 1, "fieldtype": "Link",
"search_index": 1 "hidden": 0,
}, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"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
},
{ {
"fieldname": "budget_amount", "allow_on_submit": 0,
"fieldtype": "Currency", "bold": 0,
"in_list_view": 1, "collapsible": 0,
"label": "Budget Amount", "columns": 0,
"options": "Company:company:default_currency", "fieldname": "budget_amount",
"reqd": 1 "fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Budget Amount",
"length": 0,
"no_copy": 0,
"options": "Company:company:default_currency",
"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
} }
], ],
"istable": 1, "hide_heading": 0,
"links": [], "hide_toolbar": 0,
"modified": "2024-03-04 15:43:27.016947", "idx": 0,
"modified_by": "Administrator", "image_view": 0,
"module": "Accounts", "in_create": 0,
"name": "Budget Account",
"owner": "Administrator", "is_submittable": 0,
"permissions": [], "issingle": 0,
"quick_entry": 1, "istable": 1,
"sort_field": "modified", "max_attachments": 0,
"sort_order": "DESC", "modified": "2017-01-02 17:02:53.339420",
"states": [] "modified_by": "Administrator",
"module": "Accounts",
"name": "Budget Account",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_seen": 0
} }

View File

@@ -1,4 +1,6 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors // Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Cash Flow Mapper", {}); frappe.ui.form.on('Cash Flow Mapper', {
});

View File

@@ -1,45 +1,43 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors // Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Cash Flow Mapping", { frappe.ui.form.on('Cash Flow Mapping', {
refresh: function (frm) { refresh: function(frm) {
frm.events.disable_unchecked_fields(frm); frm.events.disable_unchecked_fields(frm);
}, },
reset_check_fields: function (frm) { reset_check_fields: function(frm) {
frm.fields frm.fields.filter(field => field.df.fieldtype === 'Check')
.filter((field) => field.df.fieldtype === "Check") .map(field => frm.set_df_property(field.df.fieldname, 'read_only', 0));
.map((field) => frm.set_df_property(field.df.fieldname, "read_only", 0));
}, },
has_checked_field(frm) { has_checked_field(frm) {
const val = frm.fields.filter((field) => field.value === 1); const val = frm.fields.filter(field => field.value === 1);
return val.length ? 1 : 0; return val.length ? 1 : 0;
}, },
_disable_unchecked_fields: function (frm) { _disable_unchecked_fields: function(frm) {
// get value of clicked field // get value of clicked field
frm.fields frm.fields.filter(field => field.value === 0)
.filter((field) => field.value === 0) .map(field => frm.set_df_property(field.df.fieldname, 'read_only', 1));
.map((field) => frm.set_df_property(field.df.fieldname, "read_only", 1));
}, },
disable_unchecked_fields: function (frm) { disable_unchecked_fields: function(frm) {
frm.events.reset_check_fields(frm); frm.events.reset_check_fields(frm);
const checked = frm.events.has_checked_field(frm); const checked = frm.events.has_checked_field(frm);
if (checked) { if (checked) {
frm.events._disable_unchecked_fields(frm); frm.events._disable_unchecked_fields(frm);
} }
}, },
is_working_capital: function (frm) { is_working_capital: function(frm) {
frm.events.disable_unchecked_fields(frm); frm.events.disable_unchecked_fields(frm);
}, },
is_finance_cost: function (frm) { is_finance_cost: function(frm) {
frm.events.disable_unchecked_fields(frm); frm.events.disable_unchecked_fields(frm);
}, },
is_income_tax_liability: function (frm) { is_income_tax_liability: function(frm) {
frm.events.disable_unchecked_fields(frm); frm.events.disable_unchecked_fields(frm);
}, },
is_income_tax_expense: function (frm) { is_income_tax_expense: function(frm) {
frm.events.disable_unchecked_fields(frm); frm.events.disable_unchecked_fields(frm);
}, },
is_finance_cost_adjustment: function (frm) { is_finance_cost_adjustment: function(frm) {
frm.events.disable_unchecked_fields(frm); frm.events.disable_unchecked_fields(frm);
}, }
}); });

View File

@@ -1,4 +1,6 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors // Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Cash Flow Mapping Template", {}); frappe.ui.form.on('Cash Flow Mapping Template', {
});

View File

@@ -1,4 +1,6 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors // Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Cash Flow Mapping Template Details", {}); frappe.ui.form.on('Cash Flow Mapping Template Details', {
});

View File

@@ -1,10 +1,11 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt // License: GNU General Public License v3. See license.txt
frappe.ui.form.on("Cashier Closing", { frappe.ui.form.on('Cashier Closing', {
setup: function (frm) {
setup: function(frm){
if (frm.doc.user == "" || frm.doc.user == null) { if (frm.doc.user == "" || frm.doc.user == null) {
frm.doc.user = frappe.session.user; frm.doc.user = frappe.session.user;
} }
}, }
}); });

View File

@@ -1,152 +1,457 @@
{ {
"actions": [], "allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "naming_series:", "autoname": "naming_series:",
"beta": 0,
"creation": "2018-06-18 16:51:49.994750", "creation": "2018-06-18 16:51:49.994750",
"custom": 0,
"docstatus": 0,
"doctype": "DocType", "doctype": "DocType",
"document_type": "",
"editable_grid": 1, "editable_grid": 1,
"engine": "InnoDB", "engine": "InnoDB",
"field_order": [
"naming_series",
"user",
"date",
"from_time",
"time",
"expense",
"custody",
"returns",
"outstanding_amount",
"payments",
"net_amount",
"amended_from"
],
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "POS-CLO-", "default": "POS-CLO-",
"fieldname": "naming_series", "fieldname": "naming_series",
"fieldtype": "Select", "fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1, "in_filter": 1,
"in_global_search": 1, "in_global_search": 1,
"in_list_view": 0,
"in_standard_filter": 1, "in_standard_filter": 1,
"label": "Series", "label": "Series",
"length": 0,
"no_copy": 0,
"options": "POS-CLO-", "options": "POS-CLO-",
"read_only": 1 "permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "user", "fieldname": "user",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1, "in_filter": 1,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 1, "in_standard_filter": 1,
"label": "User", "label": "User",
"length": 0,
"no_copy": 0,
"options": "User", "options": "User",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1, "read_only": 1,
"reqd": 1 "remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "Today", "default": "Today",
"fieldname": "date", "fieldname": "date",
"fieldtype": "Date", "fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1, "in_filter": 1,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 1, "in_standard_filter": 1,
"label": "Date", "label": "Date",
"read_only": 1 "length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "from_time", "fieldname": "from_time",
"fieldtype": "Time", "fieldtype": "Time",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1, "in_filter": 1,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 1, "in_standard_filter": 1,
"label": "From Time", "label": "From Time",
"reqd": 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": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "",
"fieldname": "time", "fieldname": "time",
"fieldtype": "Time", "fieldtype": "Time",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1, "in_filter": 1,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 1, "in_standard_filter": 1,
"label": "To Time", "label": "To Time",
"reqd": 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": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0.00", "default": "0.00",
"fieldname": "expense", "fieldname": "expense",
"fieldtype": "Float", "fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1, "in_filter": 1,
"label": "Expense" "in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "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,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0.00", "default": "0.00",
"fieldname": "custody", "fieldname": "custody",
"fieldtype": "Float", "fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1, "in_filter": 1,
"label": "Custody" "in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Custody",
"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,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0.00", "default": "0.00",
"fieldname": "returns", "fieldname": "returns",
"fieldtype": "Float", "fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1, "in_filter": 1,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Returns", "label": "Returns",
"precision": "2" "length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "2",
"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.00", "default": "0.00",
"fieldname": "outstanding_amount", "fieldname": "outstanding_amount",
"fieldtype": "Float", "fieldtype": "Float",
"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": "Outstanding Amount", "label": "Outstanding Amount",
"read_only": 1 "length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0.0",
"fieldname": "payments", "fieldname": "payments",
"fieldtype": "Table", "fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1, "in_filter": 1,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Payments", "label": "Payments",
"options": "Cashier Closing Payments" "length": 0,
"no_copy": 0,
"options": "Cashier Closing Payments",
"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,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "net_amount", "fieldname": "net_amount",
"fieldtype": "Float", "fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1, "in_filter": 1,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 1, "in_standard_filter": 1,
"label": "Net Amount", "label": "Net Amount",
"read_only": 1 "length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "amended_from", "fieldname": "amended_from",
"fieldtype": "Link", "fieldtype": "Link",
"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": "Amended From", "label": "Amended From",
"length": 0,
"no_copy": 1, "no_copy": 1,
"options": "Cashier Closing", "options": "Cashier Closing",
"permlevel": 0,
"print_hide": 1, "print_hide": 1,
"read_only": 1 "print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
} }
], ],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 1, "is_submittable": 1,
"links": [], "issingle": 0,
"modified": "2023-12-28 13:15:46.858427", "istable": 0,
"max_attachments": 0,
"modified": "2019-02-19 08:35:24.157327",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Cashier Closing", "name": "Cashier Closing",
"naming_rule": "By \"Naming Series\" field", "name_case": "",
"owner": "Administrator", "owner": "Administrator",
"permissions": [ "permissions": [
{ {
"amend": 0,
"cancel": 0,
"create": 1, "create": 1,
"delete": 1, "delete": 1,
"email": 1, "email": 1,
"export": 1, "export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1, "print": 1,
"read": 1, "read": 1,
"report": 1, "report": 1,
"role": "System Manager", "role": "System Manager",
"set_user_permissions": 0,
"share": 1, "share": 1,
"submit": 1, "submit": 1,
"write": 1 "write": 1
} }
], ],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"states": [], "track_changes": 1,
"track_changes": 1 "track_seen": 0,
} "track_views": 0
}

View File

@@ -1,4 +1,4 @@
frappe.ui.form.on("Chart of Accounts Importer", { frappe.ui.form.on('Chart of Accounts Importer', {
onload: function (frm) { onload: function (frm) {
frm.set_value("company", ""); frm.set_value("company", "");
frm.set_value("import_file", ""); frm.set_value("import_file", "");
@@ -8,34 +8,31 @@ frappe.ui.form.on("Chart of Accounts Importer", {
frm.disable_save(); frm.disable_save();
// make company mandatory // make company mandatory
frm.set_df_property("company", "reqd", frm.doc.company ? 0 : 1); frm.set_df_property('company', 'reqd', frm.doc.company ? 0 : 1);
frm.set_df_property("import_file_section", "hidden", frm.doc.company ? 0 : 1); frm.set_df_property('import_file_section', 'hidden', frm.doc.company ? 0 : 1);
if (frm.doc.import_file) { if (frm.doc.import_file) {
frappe.run_serially([ frappe.run_serially([
() => generate_tree_preview(frm), () => generate_tree_preview(frm),
() => create_import_button(frm), () => create_import_button(frm),
() => frm.set_df_property("chart_preview", "hidden", 0), () => frm.set_df_property('chart_preview', 'hidden', 0)
]); ]);
} }
frm.set_df_property( frm.set_df_property('chart_preview', 'hidden',
"chart_preview", $(frm.fields_dict['chart_tree'].wrapper).html()!="" ? 0 : 1);
"hidden",
$(frm.fields_dict["chart_tree"].wrapper).html() != "" ? 0 : 1
);
}, },
download_template: function (frm) { download_template: function(frm) {
var d = new frappe.ui.Dialog({ var d = new frappe.ui.Dialog({
title: __("Download Template"), title: __("Download Template"),
fields: [ fields: [
{ {
label: "File Type", label : "File Type",
fieldname: "file_type", fieldname: "file_type",
fieldtype: "Select", fieldtype: "Select",
reqd: 1, reqd: 1,
options: ["Excel", "CSV"], options: ["Excel", "CSV"]
}, },
{ {
label: "Template Type", label: "Template Type",
@@ -44,53 +41,38 @@ frappe.ui.form.on("Chart of Accounts Importer", {
reqd: 1, reqd: 1,
options: ["Sample Template", "Blank Template"], options: ["Sample Template", "Blank Template"],
change: () => { change: () => {
let template_type = d.get_value("template_type"); let template_type = d.get_value('template_type');
if (template_type === "Sample Template") { if (template_type === "Sample Template") {
d.set_df_property( d.set_df_property('template_type', 'description',
"template_type",
"description",
`The Sample Template contains all the required accounts pre filled in the template. `The Sample Template contains all the required accounts pre filled in the template.
You can add more accounts or change existing accounts in the template as per your choice.` You can add more accounts or change existing accounts in the template as per your choice.`);
);
} else { } else {
d.set_df_property( d.set_df_property('template_type', 'description',
"template_type",
"description",
`The Blank Template contains just the account type and root type required to build the Chart `The Blank Template contains just the account type and root type required to build the Chart
of Accounts. Please enter the account names and add more rows as per your requirement.` of Accounts. Please enter the account names and add more rows as per your requirement.`);
);
} }
}, }
}, }
{
label: "Company",
fieldname: "company",
fieldtype: "Link",
reqd: 1,
hidden: 1,
default: frm.doc.company,
},
], ],
primary_action: function () { primary_action: function() {
let data = d.get_values(); var data = d.get_values();
if (!data.template_type) { if (!data.template_type) {
frappe.throw(__("Please select <b>Template Type</b> to download template")); frappe.throw(__('Please select <b>Template Type</b> to download template'));
} }
open_url_post( open_url_post(
"/api/method/erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.download_template", '/api/method/erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.download_template',
{ {
file_type: data.file_type, file_type: data.file_type,
template_type: data.template_type, template_type: data.template_type
company: data.company,
} }
); );
d.hide(); d.hide();
}, },
primary_action_label: __("Download"), primary_action_label: __('Download')
}); });
d.show(); d.show();
}, },
@@ -98,7 +80,7 @@ frappe.ui.form.on("Chart of Accounts Importer", {
import_file: function (frm) { import_file: function (frm) {
if (!frm.doc.import_file) { if (!frm.doc.import_file) {
frm.page.set_indicator(""); frm.page.set_indicator("");
$(frm.fields_dict["chart_tree"].wrapper).empty(); // empty wrapper on removing file $(frm.fields_dict['chart_tree'].wrapper).empty(); // empty wrapper on removing file
} }
}, },
@@ -108,97 +90,89 @@ frappe.ui.form.on("Chart of Accounts Importer", {
frappe.call({ frappe.call({
method: "erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.validate_company", method: "erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.validate_company",
args: { args: {
company: frm.doc.company, company: frm.doc.company
}, },
callback: function (r) { callback: function(r) {
if (r.message === false) { if(r.message===false) {
frm.set_value("company", ""); frm.set_value("company", "");
frappe.throw( frappe.throw(__("Transactions against the Company already exist! Chart of Accounts can only be imported for a Company with no transactions."));
__(
"Transactions against the Company already exist! Chart of Accounts can only be imported for a Company with no transactions."
)
);
} else { } else {
frm.trigger("refresh"); frm.trigger("refresh");
} }
}, }
}); });
} }
}, }
}); });
var create_import_button = function (frm) { var create_import_button = function(frm) {
frm.page frm.page.set_primary_action(__("Import"), function () {
.set_primary_action(__("Import"), function () {
return frappe.call({
method: "erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.import_coa",
args: {
file_name: frm.doc.import_file,
company: frm.doc.company,
},
freeze: true,
freeze_message: __("Creating Accounts..."),
callback: function (r) {
if (!r.exc) {
clearInterval(frm.page["interval"]);
frm.page.set_indicator(__("Import Successful"), "blue");
create_reset_button(frm);
}
},
});
})
.addClass("btn btn-primary");
};
var create_reset_button = function (frm) {
frm.page
.set_primary_action(__("Reset"), function () {
frm.page.clear_primary_action();
delete frm.page["show_import_button"];
frm.reload_doc();
})
.addClass("btn btn-primary");
};
var validate_coa = function (frm) {
if (frm.doc.import_file) {
let parent = __("All Accounts");
return frappe.call({ return frappe.call({
method: "erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.get_coa", method: "erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.import_coa",
args: { args: {
file_name: frm.doc.import_file, file_name: frm.doc.import_file,
parent: parent, company: frm.doc.company
doctype: "Chart of Accounts Importer",
file_type: frm.doc.file_type,
for_validate: 1,
}, },
callback: function (r) { freeze: true,
if (r.message["show_import_button"]) { freeze_message: __("Creating Accounts..."),
frm.page["show_import_button"] = Boolean(r.message["show_import_button"]); callback: function(r) {
if (!r.exc) {
clearInterval(frm.page["interval"]);
frm.page.set_indicator(__('Import Successful'), 'blue');
create_reset_button(frm);
} }
}
});
}).addClass('btn btn-primary');
};
var create_reset_button = function(frm) {
frm.page.set_primary_action(__("Reset"), function () {
frm.page.clear_primary_action();
delete frm.page["show_import_button"];
frm.reload_doc();
}).addClass('btn btn-primary');
};
var validate_coa = function(frm) {
if (frm.doc.import_file) {
let parent = __('All Accounts');
return frappe.call({
'method': 'erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.get_coa',
'args': {
file_name: frm.doc.import_file,
parent: parent,
doctype: 'Chart of Accounts Importer',
file_type: frm.doc.file_type,
for_validate: 1
}, },
callback: function(r) {
if (r.message['show_import_button']) {
frm.page['show_import_button'] = Boolean(r.message['show_import_button']);
}
}
}); });
} }
}; };
var generate_tree_preview = function (frm) { var generate_tree_preview = function(frm) {
let parent = __("All Accounts"); let parent = __('All Accounts');
$(frm.fields_dict["chart_tree"].wrapper).empty(); // empty wrapper to load new data $(frm.fields_dict['chart_tree'].wrapper).empty(); // empty wrapper to load new data
// generate tree structure based on the csv data // generate tree structure based on the csv data
return new frappe.ui.Tree({ return new frappe.ui.Tree({
parent: $(frm.fields_dict["chart_tree"].wrapper), parent: $(frm.fields_dict['chart_tree'].wrapper),
label: parent, label: parent,
expandable: true, expandable: true,
method: "erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.get_coa", method: 'erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.get_coa',
args: { args: {
file_name: frm.doc.import_file, file_name: frm.doc.import_file,
parent: parent, parent: parent,
doctype: "Chart of Accounts Importer", doctype: 'Chart of Accounts Importer',
file_type: frm.doc.file_type, file_type: frm.doc.file_type
}, },
onclick: function (node) { onclick: function(node) {
parent = node.value; parent = node.value;
}, }
}); });
}; };

View File

@@ -8,7 +8,6 @@ from functools import reduce
import frappe import frappe
from frappe import _ from frappe import _
from frappe.desk.form.linked_with import get_linked_fields
from frappe.model.document import Document from frappe.model.document import Document
from frappe.utils import cint, cstr from frappe.utils import cint, cstr
from frappe.utils.csvutils import UnicodeWriter from frappe.utils.csvutils import UnicodeWriter
@@ -113,7 +112,7 @@ def generate_data_from_csv(file_doc, as_dict=False):
if as_dict: if as_dict:
data.append({frappe.scrub(header): row[index] for index, header in enumerate(headers)}) data.append({frappe.scrub(header): row[index] for index, header in enumerate(headers)})
else: else:
if not row[1] and len(row) > 1: if not row[1]:
row[1] = row[0] row[1] = row[0]
row[3] = row[2] row[3] = row[2]
data.append(row) data.append(row)
@@ -295,8 +294,10 @@ def build_response_as_excel(writer):
@frappe.whitelist() @frappe.whitelist()
def download_template(file_type, template_type, company): def download_template(file_type, template_type):
writer = get_template(template_type, company) data = frappe._dict(frappe.local.form_dict)
writer = get_template(template_type)
if file_type == "CSV": if file_type == "CSV":
# download csv file # download csv file
@@ -307,7 +308,8 @@ def download_template(file_type, template_type, company):
build_response_as_excel(writer) build_response_as_excel(writer)
def get_template(template_type, company): def get_template(template_type):
fields = [ fields = [
"Account Name", "Account Name",
"Parent Account", "Parent Account",
@@ -333,17 +335,34 @@ def get_template(template_type, company):
["", "", "", "", 0, account_type.get("account_type"), account_type.get("root_type")] ["", "", "", "", 0, account_type.get("account_type"), account_type.get("root_type")]
) )
else: else:
writer = get_sample_template(writer, company) writer = get_sample_template(writer)
return writer return writer
def get_sample_template(writer, company): def get_sample_template(writer):
currency = frappe.db.get_value("Company", company, "default_currency") template = [
with open(os.path.join(os.path.dirname(__file__), "coa_sample_template.csv"), "r") as f: ["Application Of Funds(Assets)", "", "", "", 1, "", "Asset"],
for row in f: ["Sources Of Funds(Liabilities)", "", "", "", 1, "", "Liability"],
row = row.strip().split(",") + [currency] ["Equity", "", "", "", 1, "", "Equity"],
writer.writerow(row) ["Expenses", "", "", "", 1, "", "Expense"],
["Income", "", "", "", 1, "", "Income"],
["Bank Accounts", "Application Of Funds(Assets)", "", "", 1, "Bank", "Asset"],
["Cash In Hand", "Application Of Funds(Assets)", "", "", 1, "Cash", "Asset"],
["Stock Assets", "Application Of Funds(Assets)", "", "", 1, "Stock", "Asset"],
["Cost Of Goods Sold", "Expenses", "", "", 0, "Cost of Goods Sold", "Expense"],
["Asset Depreciation", "Expenses", "", "", 0, "Depreciation", "Expense"],
["Fixed Assets", "Application Of Funds(Assets)", "", "", 0, "Fixed Asset", "Asset"],
["Accounts Payable", "Sources Of Funds(Liabilities)", "", "", 0, "Payable", "Liability"],
["Accounts Receivable", "Application Of Funds(Assets)", "", "", 1, "Receivable", "Asset"],
["Stock Expenses", "Expenses", "", "", 0, "Stock Adjustment", "Expense"],
["Sample Bank", "Bank Accounts", "", "", 0, "Bank", "Asset"],
["Cash", "Cash In Hand", "", "", 0, "Cash", "Asset"],
["Stores", "Stock Assets", "", "", 0, "Stock", "Asset"],
]
for row in template:
writer.writerow(row)
return writer return writer
@@ -434,11 +453,14 @@ def get_mandatory_account_types():
def unset_existing_data(company): def unset_existing_data(company):
# remove accounts data from company linked = frappe.db.sql(
'''select fieldname from tabDocField
where fieldtype="Link" and options="Account" and parent="Company"''',
as_dict=True,
)
fieldnames = get_linked_fields("Account").get("Company", {}).get("fieldname", []) # remove accounts data from company
linked = [{"fieldname": name} for name in fieldnames] update_values = {d.fieldname: "" for d in linked}
update_values = {d.get("fieldname"): "" for d in linked}
frappe.db.set_value("Company", company, update_values, update_values) frappe.db.set_value("Company", company, update_values, update_values)
# remove accounts data from various doctypes # remove accounts data from various doctypes

View File

@@ -1,17 +0,0 @@
Application Of Funds(Assets),,,,1,,Asset
Sources Of Funds(Liabilities),,,,1,,Liability
Equity,,,,1,,Equity
Expenses,,,,1,Expense Account,Expense
Income,,,,1,Income Account,Income
Bank Accounts,Application Of Funds(Assets),,,1,Bank,Asset
Cash In Hand,Application Of Funds(Assets),,,1,Cash,Asset
Stock Assets,Application Of Funds(Assets),,,1,Stock,Asset
Cost Of Goods Sold,Expenses,,,0,Cost of Goods Sold,Expense
Asset Depreciation,Expenses,,,0,Depreciation,Expense
Fixed Assets,Application Of Funds(Assets),,,0,Fixed Asset,Asset
Accounts Payable,Sources Of Funds(Liabilities),,,0,Payable,Liability
Accounts Receivable,Application Of Funds(Assets),,,1,Receivable,Asset
Stock Expenses,Expenses,,,0,Stock Adjustment,Expense
Sample Bank,Bank Accounts,,,0,Bank,Asset
Cash,Cash In Hand,,,0,Cash,Asset
Stores,Stock Assets,,,0,Stock,Asset
1 Application Of Funds(Assets) 1 Asset
2 Sources Of Funds(Liabilities) 1 Liability
3 Equity 1 Equity
4 Expenses 1 Expense Account Expense
5 Income 1 Income Account Income
6 Bank Accounts Application Of Funds(Assets) 1 Bank Asset
7 Cash In Hand Application Of Funds(Assets) 1 Cash Asset
8 Stock Assets Application Of Funds(Assets) 1 Stock Asset
9 Cost Of Goods Sold Expenses 0 Cost of Goods Sold Expense
10 Asset Depreciation Expenses 0 Depreciation Expense
11 Fixed Assets Application Of Funds(Assets) 0 Fixed Asset Asset
12 Accounts Payable Sources Of Funds(Liabilities) 0 Payable Liability
13 Accounts Receivable Application Of Funds(Assets) 1 Receivable Asset
14 Stock Expenses Expenses 0 Stock Adjustment Expense
15 Sample Bank Bank Accounts 0 Bank Asset
16 Cash Cash In Hand 0 Cash Asset
17 Stores Stock Assets 0 Stock Asset

View File

@@ -3,20 +3,18 @@
frappe.provide("erpnext.cheque_print"); frappe.provide("erpnext.cheque_print");
frappe.ui.form.on("Cheque Print Template", { frappe.ui.form.on('Cheque Print Template', {
refresh: function (frm) { refresh: function(frm) {
if (!frm.doc.__islocal) { if(!frm.doc.__islocal) {
frm.add_custom_button( frm.add_custom_button(frm.doc.has_print_format?__("Update Print Format"):__("Create Print Format"),
frm.doc.has_print_format ? __("Update Print Format") : __("Create Print Format"), function() {
function () {
erpnext.cheque_print.view_cheque_print(frm); erpnext.cheque_print.view_cheque_print(frm);
} }).addClass("btn-primary");
).addClass("btn-primary");
$(frm.fields_dict.cheque_print_preview.wrapper).empty(); $(frm.fields_dict.cheque_print_preview.wrapper).empty()
var template =
'<div style="position: relative; overflow-x: scroll;">\ var template = '<div style="position: relative; overflow-x: scroll;">\
<div id="cheque_preview" style="width: {{ cheque_width }}cm; \ <div id="cheque_preview" style="width: {{ cheque_width }}cm; \
height: {{ cheque_height }}cm;\ height: {{ cheque_height }}cm;\
background-repeat: no-repeat;\ background-repeat: no-repeat;\
@@ -50,30 +48,30 @@ frappe.ui.form.on("Cheque Print Template", {
</div>\ </div>\
</div>'; </div>';
$(frappe.render(template, frm.doc)).appendTo(frm.fields_dict.cheque_print_preview.wrapper); $(frappe.render(template, frm.doc)).appendTo(frm.fields_dict.cheque_print_preview.wrapper)
if (frm.doc.scanned_cheque) { if (frm.doc.scanned_cheque) {
$(frm.fields_dict.cheque_print_preview.wrapper) $(frm.fields_dict.cheque_print_preview.wrapper).find("#cheque_preview").css('background-image', 'url(' + frm.doc.scanned_cheque + ')');
.find("#cheque_preview")
.css("background-image", "url(" + frm.doc.scanned_cheque + ")");
} }
} }
}, }
}); });
erpnext.cheque_print.view_cheque_print = function (frm) {
erpnext.cheque_print.view_cheque_print = function(frm) {
frappe.call({ frappe.call({
method: "erpnext.accounts.doctype.cheque_print_template.cheque_print_template.create_or_update_cheque_print_format", method: "erpnext.accounts.doctype.cheque_print_template.cheque_print_template.create_or_update_cheque_print_format",
args: { args:{
template_name: frm.doc.name, "template_name": frm.doc.name
}, },
callback: function (r) { callback: function(r) {
if (!r.exe && !frm.doc.has_print_format) { if (!r.exe && !frm.doc.has_print_format) {
var doc = frappe.model.sync(r.message); var doc = frappe.model.sync(r.message);
frappe.set_route("Form", r.message.doctype, r.message.name); frappe.set_route("Form", r.message.doctype, r.message.name);
} else {
frappe.msgprint(__("Print settings updated in respective print format"));
} }
}, else {
}); frappe.msgprint(__("Print settings updated in respective print format"))
}; }
}
})
}

View File

@@ -3,80 +3,75 @@
frappe.provide("erpnext.accounts"); frappe.provide("erpnext.accounts");
frappe.ui.form.on("Cost Center", {
onload: function (frm) {
frm.set_query("parent_cost_center", function () { frappe.ui.form.on('Cost Center', {
onload: function(frm) {
frm.set_query("parent_cost_center", function() {
return { return {
filters: { filters: {
company: frm.doc.company, company: frm.doc.company,
is_group: 1, is_group: 1
}, }
}; }
}); });
}, },
refresh: function (frm) { refresh: function(frm) {
if (!frm.is_new()) { if (!frm.is_new()) {
frm.add_custom_button(__("Update Cost Center Name / Number"), function () { frm.add_custom_button(__('Update Cost Center Name / Number'), function () {
frm.trigger("update_cost_center_number"); frm.trigger("update_cost_center_number");
}); });
} }
let intro_txt = ""; let intro_txt = '';
let doc = frm.doc; let doc = frm.doc;
frm.toggle_display("cost_center_name", doc.__islocal); frm.toggle_display('cost_center_name', doc.__islocal);
frm.toggle_enable(["is_group", "company"], doc.__islocal); frm.toggle_enable(['is_group', 'company'], doc.__islocal);
if (!doc.__islocal && doc.is_group == 1) { if(!doc.__islocal && doc.is_group==1) {
intro_txt += __( intro_txt += __('Note: This Cost Center is a Group. Cannot make accounting entries against groups.');
"Note: This Cost Center is a Group. Cannot make accounting entries against groups."
);
} }
frm.events.hide_unhide_group_ledger(frm); frm.events.hide_unhide_group_ledger(frm);
frm.toggle_display("sb1", doc.is_group == 0); frm.toggle_display('sb1', doc.is_group==0);
frm.set_intro(intro_txt); frm.set_intro(intro_txt);
if (!frm.doc.__islocal) { if(!frm.doc.__islocal) {
frm.add_custom_button(__("Chart of Cost Centers"), function () { frm.add_custom_button(__('Chart of Cost Centers'),
frappe.set_route("Tree", "Cost Center"); function() { frappe.set_route("Tree", "Cost Center"); });
});
frm.add_custom_button(__("Budget"), function () { frm.add_custom_button(__('Budget'),
frappe.set_route("List", "Budget", { cost_center: frm.doc.name }); function() { frappe.set_route("List", "Budget", {'cost_center': frm.doc.name}); });
});
} }
}, },
update_cost_center_number: function (frm) { update_cost_center_number: function(frm) {
var d = new frappe.ui.Dialog({ var d = new frappe.ui.Dialog({
title: __("Update Cost Center Name / Number"), title: __('Update Cost Center Name / Number'),
fields: [ fields: [
{ {
label: "Cost Center Name", "label": "Cost Center Name",
fieldname: "cost_center_name", "fieldname": "cost_center_name",
fieldtype: "Data", "fieldtype": "Data",
reqd: 1, "reqd": 1,
default: frm.doc.cost_center_name, "default": frm.doc.cost_center_name
}, },
{ {
label: "Cost Center Number", "label": "Cost Center Number",
fieldname: "cost_center_number", "fieldname": "cost_center_number",
fieldtype: "Data", "fieldtype": "Data",
default: frm.doc.cost_center_number, "default": frm.doc.cost_center_number
}, },
{ {
label: __("Merge with existing"), "label": __("Merge with existing"),
fieldname: "merge", "fieldname": "merge",
fieldtype: "Check", "fieldtype": "Check",
default: 0, "default": 0
}, }
], ],
primary_action: function () { primary_action: function() {
var data = d.get_values(); var data = d.get_values();
if ( if(data.cost_center_name === frm.doc.cost_center_name && data.cost_center_number === frm.doc.cost_center_number) {
data.cost_center_name === frm.doc.cost_center_name &&
data.cost_center_number === frm.doc.cost_center_number
) {
d.hide(); d.hide();
return; return;
} }
@@ -88,12 +83,12 @@ frappe.ui.form.on("Cost Center", {
cost_center_name: data.cost_center_name, cost_center_name: data.cost_center_name,
cost_center_number: cstr(data.cost_center_number), cost_center_number: cstr(data.cost_center_number),
company: frm.doc.company, company: frm.doc.company,
merge: data.merge, merge: data.merge
}, },
callback: function (r) { callback: function(r) {
frappe.dom.unfreeze(); frappe.dom.unfreeze();
if (!r.exc) { if(!r.exc) {
if (r.message) { if(r.message) {
frappe.set_route("Form", "Cost Center", r.message); frappe.set_route("Form", "Cost Center", r.message);
} else { } else {
me.frm.set_value("cost_center_name", data.cost_center_name); me.frm.set_value("cost_center_name", data.cost_center_name);
@@ -101,42 +96,44 @@ frappe.ui.form.on("Cost Center", {
} }
d.hide(); d.hide();
} }
}, }
}); });
}, },
primary_action_label: __("Update"), primary_action_label: __('Update')
}); });
d.show(); d.show();
}, },
parent_cost_center(frm) { parent_cost_center(frm) {
if (!frm.doc.company) { if(!frm.doc.company) {
frappe.msgprint(__("Please enter company name first")); frappe.msgprint(__('Please enter company name first'));
} }
}, },
hide_unhide_group_ledger(frm) { hide_unhide_group_ledger(frm) {
let doc = frm.doc; let doc = frm.doc;
if (doc.is_group == 1) { if (doc.is_group == 1) {
frm.add_custom_button(__("Convert to Non-Group"), () => frm.events.convert_to_ledger(frm)); frm.add_custom_button(__('Convert to Non-Group'),
() => frm.events.convert_to_ledger(frm));
} else if (doc.is_group == 0) { } else if (doc.is_group == 0) {
frm.add_custom_button(__("Convert to Group"), () => frm.events.convert_to_group(frm)); frm.add_custom_button(__('Convert to Group'),
() => frm.events.convert_to_group(frm));
} }
}, },
convert_to_group(frm) { convert_to_group(frm) {
frm.call("convert_ledger_to_group").then((r) => { frm.call('convert_ledger_to_group').then(r => {
if (r.message === 1) { if(r.message === 1) {
frm.refresh(); frm.refresh();
} }
}); });
}, },
convert_to_ledger(frm) { convert_to_ledger(frm) {
frm.call("convert_group_to_ledger").then((r) => { frm.call('convert_group_to_ledger').then(r => {
if (r.message === 1) { if(r.message === 1) {
frm.refresh(); frm.refresh();
} }
}); });
}, }
}); });

View File

@@ -1,84 +1,54 @@
frappe.treeview_settings["Cost Center"] = { frappe.treeview_settings["Cost Center"] = {
breadcrumb: "Accounts", breadcrumb: "Accounts",
get_tree_root: false, get_tree_root: false,
filters: [ filters: [{
{ fieldname: "company",
fieldname: "company", fieldtype:"Select",
fieldtype: "Select", options: erpnext.utils.get_tree_options("company"),
options: erpnext.utils.get_tree_options("company"), label: __("Company"),
label: __("Company"), default: erpnext.utils.get_tree_default("company")
default: erpnext.utils.get_tree_default("company"), }],
},
],
root_label: "Cost Centers", root_label: "Cost Centers",
get_tree_nodes: "erpnext.accounts.utils.get_children", get_tree_nodes: 'erpnext.accounts.utils.get_children',
add_tree_node: "erpnext.accounts.utils.add_cc", add_tree_node: 'erpnext.accounts.utils.add_cc',
menu_items: [ menu_items:[
{ {
label: __("New Company"), label: __('New Company'),
action: function () { action: function() { frappe.new_doc("Company", true) },
frappe.new_doc("Company", true); condition: 'frappe.boot.user.can_create.indexOf("Company") !== -1'
}, }
condition: 'frappe.boot.user.can_create.indexOf("Company") !== -1',
},
], ],
fields: [ fields:[
{ fieldtype: "Data", fieldname: "cost_center_name", label: __("New Cost Center Name"), reqd: true }, {fieldtype:'Data', fieldname:'cost_center_name', label:__('New Cost Center Name'), reqd:true},
{ {fieldtype:'Check', fieldname:'is_group', label:__('Is Group'),
fieldtype: "Check", description:__('Further cost centers can be made under Groups but entries can be made against non-Groups')},
fieldname: "is_group", {fieldtype:'Data', fieldname:'cost_center_number', label:__('Cost Center Number'),
label: __("Is Group"), description: __("Number of new Cost Center, it will be included in the cost center name as a prefix")}
description: __(
"Further cost centers can be made under Groups but entries can be made against non-Groups"
),
},
{
fieldtype: "Data",
fieldname: "cost_center_number",
label: __("Cost Center Number"),
description: __(
"Number of new Cost Center, it will be included in the cost center name as a prefix"
),
},
], ],
ignore_fields: ["parent_cost_center"], ignore_fields:["parent_cost_center"],
onload: function (treeview) { onload: function(treeview) {
function get_company() { function get_company() {
return treeview.page.fields_dict.company.get_value(); return treeview.page.fields_dict.company.get_value();
} }
// tools // tools
treeview.page.add_inner_button( treeview.page.add_inner_button(__("Chart of Accounts"), function() {
__("Chart of Accounts"), frappe.set_route('Tree', 'Account', {company: get_company()});
function () { }, __('View'));
frappe.set_route("Tree", "Account", { company: get_company() });
},
__("View")
);
// make // make
treeview.page.add_inner_button( treeview.page.add_inner_button(__("Budget List"), function() {
__("Budget List"), frappe.set_route('List', 'Budget', {company: get_company()});
function () { }, __('Budget'));
frappe.set_route("List", "Budget", { company: get_company() });
},
__("Budget")
);
treeview.page.add_inner_button( treeview.page.add_inner_button(__("Monthly Distribution"), function() {
__("Monthly Distribution"), frappe.set_route('List', 'Monthly Distribution', {company: get_company()});
function () { }, __('Budget'));
frappe.set_route("List", "Monthly Distribution", { company: get_company() });
},
__("Budget")
);
treeview.page.add_inner_button( treeview.page.add_inner_button(__("Budget Variance Report"), function() {
__("Budget Variance Report"), frappe.set_route('query-report', 'Budget Variance Report', {company: get_company()});
function () { }, __('Budget'));
frappe.set_route("query-report", "Budget Variance Report", { company: get_company() });
}, }
__("Budget")
); }
},
};

View File

@@ -1,24 +1,19 @@
// Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors // Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Cost Center Allocation", { frappe.ui.form.on('Cost Center Allocation', {
setup: function (frm) { setup: function(frm) {
frm.set_query("main_cost_center", function () { let filters = {"is_group": 0};
return { if (frm.doc.company) {
filters: { $.extend(filters, {
company: frm.doc.company, "company": frm.doc.company
is_group: 0, });
}, }
};
});
frm.set_query("cost_center", "allocation_percentages", function () { frm.set_query('main_cost_center', function() {
return { return {
filters: { filters: filters
company: frm.doc.company,
is_group: 0,
},
}; };
}); });
}, }
}); });

View File

@@ -1,41 +1,44 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors // Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Coupon Code", { frappe.ui.form.on('Coupon Code', {
setup: function (frm) { setup: function(frm) {
frm.set_query("pricing_rule", function () { frm.set_query("pricing_rule", function() {
return { return {
filters: [["Pricing Rule", "coupon_code_based", "=", "1"]], filters: [
["Pricing Rule","coupon_code_based", "=", "1"]
]
}; };
}); });
}, },
coupon_name: function (frm) { coupon_name:function(frm){
if (frm.doc.__islocal === 1) { if (frm.doc.__islocal===1) {
frm.trigger("make_coupon_code"); frm.trigger("make_coupon_code");
} }
}, },
coupon_type: function (frm) { coupon_type:function(frm){
if (frm.doc.__islocal === 1) { if (frm.doc.__islocal===1) {
frm.trigger("make_coupon_code"); frm.trigger("make_coupon_code");
} }
}, },
make_coupon_code: function (frm) { make_coupon_code: function(frm) {
var coupon_name = frm.doc.coupon_name; var coupon_name=frm.doc.coupon_name;
var coupon_code; var coupon_code;
if (frm.doc.coupon_type == "Gift Card") { if (frm.doc.coupon_type=='Gift Card') {
coupon_code = Math.random().toString(12).substring(2, 12).toUpperCase(); coupon_code=Math.random().toString(12).substring(2, 12).toUpperCase();
} else if (frm.doc.coupon_type == "Promotional") {
coupon_name = coupon_name.replace(/\s/g, "");
coupon_code = coupon_name.toUpperCase().slice(0, 8);
} }
frm.doc.coupon_code = coupon_code; else if(frm.doc.coupon_type=='Promotional'){
frm.refresh_field("coupon_code"); coupon_name=coupon_name.replace(/\s/g,'');
coupon_code=coupon_name.toUpperCase().slice(0,8);
}
frm.doc.coupon_code=coupon_code;
frm.refresh_field('coupon_code');
}, },
refresh: function (frm) { refresh: function(frm) {
if (frm.doc.pricing_rule) { if (frm.doc.pricing_rule) {
frm.add_custom_button(__("Add/Edit Coupon Conditions"), function () { frm.add_custom_button(__("Add/Edit Coupon Conditions"), function(){
frappe.set_route("Form", "Pricing Rule", frm.doc.pricing_rule); frappe.set_route("Form", "Pricing Rule", frm.doc.pricing_rule);
}); });
} }
}, }
}); });

View File

@@ -1,41 +1,28 @@
// Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors // Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Currency Exchange Settings", { frappe.ui.form.on('Currency Exchange Settings', {
service_provider: function (frm) { service_provider: function(frm) {
frm.call({ if (frm.doc.service_provider == "exchangerate.host") {
method: "erpnext.accounts.doctype.currency_exchange_settings.currency_exchange_settings.get_api_endpoint", let result = ['result'];
args: { let params = {
service_provider: frm.doc.service_provider, date: '{transaction_date}',
use_http: frm.doc.use_http, from: '{from_currency}',
}, to: '{to_currency}'
callback: function (r) { };
if (r && r.message) { add_param(frm, "https://api.exchangerate.host/convert", params, result);
if (frm.doc.service_provider == "exchangerate.host") { } else if (frm.doc.service_provider == "frankfurter.app") {
let result = ["result"]; let result = ['rates', '{to_currency}'];
let params = { let params = {
date: "{transaction_date}", base: '{from_currency}',
from: "{from_currency}", symbols: '{to_currency}'
to: "{to_currency}", };
}; add_param(frm, "https://frankfurter.app/{transaction_date}", params, result);
add_param(frm, r.message, params, result); }
} else if (frm.doc.service_provider == "frankfurter.app") { }
let result = ["rates", "{to_currency}"];
let params = {
base: "{from_currency}",
symbols: "{to_currency}",
};
add_param(frm, r.message, params, result);
}
}
},
});
},
use_http: function (frm) {
frm.trigger("service_provider");
},
}); });
function add_param(frm, api, params, result) { function add_param(frm, api, params, result) {
var row; var row;
frm.clear_table("req_params"); frm.clear_table("req_params");
@@ -43,13 +30,13 @@ function add_param(frm, api, params, result) {
frm.doc.api_endpoint = api; frm.doc.api_endpoint = api;
$.each(params, function (key, value) { $.each(params, function(key, value) {
row = frm.add_child("req_params"); row = frm.add_child("req_params");
row.key = key; row.key = key;
row.value = value; row.value = value;
}); });
$.each(result, function (key, value) { $.each(result, function(key, value) {
row = frm.add_child("result_key"); row = frm.add_child("result_key");
row.key = value; row.key = value;
}); });

View File

@@ -6,11 +6,8 @@
"engine": "InnoDB", "engine": "InnoDB",
"field_order": [ "field_order": [
"api_details_section", "api_details_section",
"disabled",
"service_provider", "service_provider",
"api_endpoint", "api_endpoint",
"use_http",
"access_key",
"url", "url",
"column_break_3", "column_break_3",
"help", "help",
@@ -80,31 +77,12 @@
"label": "Service Provider", "label": "Service Provider",
"options": "frankfurter.app\nexchangerate.host\nCustom", "options": "frankfurter.app\nexchangerate.host\nCustom",
"reqd": 1 "reqd": 1
},
{
"default": "0",
"fieldname": "disabled",
"fieldtype": "Check",
"label": "Disabled"
},
{
"depends_on": "eval:doc.service_provider == 'exchangerate.host';",
"fieldname": "access_key",
"fieldtype": "Data",
"label": "Access Key"
},
{
"default": "0",
"depends_on": "eval: doc.service_provider != \"Custom\"",
"fieldname": "use_http",
"fieldtype": "Check",
"label": "Use HTTP Protocol"
} }
], ],
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"issingle": 1, "issingle": 1,
"links": [], "links": [],
"modified": "2024-03-18 08:32:26.895076", "modified": "2022-01-10 15:51:14.521174",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Currency Exchange Settings", "name": "Currency Exchange Settings",

View File

@@ -18,21 +18,11 @@ class CurrencyExchangeSettings(Document):
def set_parameters_and_result(self): def set_parameters_and_result(self):
if self.service_provider == "exchangerate.host": if self.service_provider == "exchangerate.host":
if not self.access_key:
frappe.throw(
_("Access Key is required for Service Provider: {0}").format(
frappe.bold(self.service_provider)
)
)
self.set("result_key", []) self.set("result_key", [])
self.set("req_params", []) self.set("req_params", [])
self.api_endpoint = get_api_endpoint(self.service_provider, self.use_http) self.api_endpoint = "https://api.exchangerate.host/convert"
self.append("result_key", {"key": "result"}) self.append("result_key", {"key": "result"})
self.append("req_params", {"key": "access_key", "value": self.access_key})
self.append("req_params", {"key": "amount", "value": "1"})
self.append("req_params", {"key": "date", "value": "{transaction_date}"}) self.append("req_params", {"key": "date", "value": "{transaction_date}"})
self.append("req_params", {"key": "from", "value": "{from_currency}"}) self.append("req_params", {"key": "from", "value": "{from_currency}"})
self.append("req_params", {"key": "to", "value": "{to_currency}"}) self.append("req_params", {"key": "to", "value": "{to_currency}"})
@@ -40,7 +30,7 @@ class CurrencyExchangeSettings(Document):
self.set("result_key", []) self.set("result_key", [])
self.set("req_params", []) self.set("req_params", [])
self.api_endpoint = get_api_endpoint(self.service_provider, self.use_http) self.api_endpoint = "https://frankfurter.app/{transaction_date}"
self.append("result_key", {"key": "rates"}) self.append("result_key", {"key": "rates"})
self.append("result_key", {"key": "{to_currency}"}) self.append("result_key", {"key": "{to_currency}"})
self.append("req_params", {"key": "base", "value": "{from_currency}"}) self.append("req_params", {"key": "base", "value": "{from_currency}"})
@@ -79,19 +69,3 @@ class CurrencyExchangeSettings(Document):
frappe.throw(_("Returned exchange rate is neither integer not float.")) frappe.throw(_("Returned exchange rate is neither integer not float."))
self.url = response.url self.url = response.url
@frappe.whitelist()
def get_api_endpoint(service_provider: str = None, use_http: bool = False):
if service_provider and service_provider in ["exchangerate.host", "frankfurter.app"]:
if service_provider == "exchangerate.host":
api = "api.exchangerate.host/convert"
elif service_provider == "frankfurter.app":
api = "frankfurter.app/{transaction_date}"
protocol = "https://"
if use_http:
protocol = "http://"
return protocol + api
return None

View File

@@ -9,7 +9,7 @@ frappe.ui.form.on("Dunning", {
docstatus: 1, docstatus: 1,
company: frm.doc.company, company: frm.doc.company,
outstanding_amount: [">", 0], outstanding_amount: [">", 0],
status: "Overdue", status: "Overdue"
}, },
}; };
}); });
@@ -18,14 +18,18 @@ frappe.ui.form.on("Dunning", {
filters: { filters: {
company: frm.doc.company, company: frm.doc.company,
root_type: "Income", root_type: "Income",
is_group: 0, is_group: 0
}, }
}; };
}); });
}, },
refresh: function (frm) { refresh: function (frm) {
frm.set_df_property("company", "read_only", frm.doc.__islocal ? 0 : 1); frm.set_df_property("company", "read_only", frm.doc.__islocal ? 0 : 1);
frm.set_df_property("sales_invoice", "read_only", frm.doc.__islocal ? 0 : 1); frm.set_df_property(
"sales_invoice",
"read_only",
frm.doc.__islocal ? 0 : 1
);
if (frm.doc.docstatus === 1 && frm.doc.status === "Unresolved") { if (frm.doc.docstatus === 1 && frm.doc.status === "Unresolved") {
frm.add_custom_button(__("Resolve"), () => { frm.add_custom_button(__("Resolve"), () => {
frm.set_value("status", "Resolved"); frm.set_value("status", "Resolved");
@@ -36,27 +40,22 @@ frappe.ui.form.on("Dunning", {
__("Payment"), __("Payment"),
function () { function () {
frm.events.make_payment_entry(frm); frm.events.make_payment_entry(frm);
}, },__("Create")
__("Create")
); );
frm.page.set_inner_btn_group_as_primary(__("Create")); frm.page.set_inner_btn_group_as_primary(__("Create"));
} }
if (frm.doc.docstatus > 0) { if(frm.doc.docstatus > 0) {
frm.add_custom_button( frm.add_custom_button(__('Ledger'), function() {
__("Ledger"), frappe.route_options = {
function () { "voucher_no": frm.doc.name,
frappe.route_options = { "from_date": frm.doc.posting_date,
voucher_no: frm.doc.name, "to_date": frm.doc.posting_date,
from_date: frm.doc.posting_date, "company": frm.doc.company,
to_date: frm.doc.posting_date, "show_cancelled_entries": frm.doc.docstatus === 2
company: frm.doc.company, };
show_cancelled_entries: frm.doc.docstatus === 2, frappe.set_route("query-report", "General Ledger");
}; }, __('View'));
frappe.set_route("query-report", "General Ledger");
},
__("View")
);
} }
}, },
overdue_days: function (frm) { overdue_days: function (frm) {
@@ -87,7 +86,8 @@ frappe.ui.form.on("Dunning", {
get_dunning_letter_text: function (frm) { get_dunning_letter_text: function (frm) {
if (frm.doc.dunning_type) { if (frm.doc.dunning_type) {
frappe.call({ frappe.call({
method: "erpnext.accounts.doctype.dunning.dunning.get_dunning_letter_text", method:
"erpnext.accounts.doctype.dunning.dunning.get_dunning_letter_text",
args: { args: {
dunning_type: frm.doc.dunning_type, dunning_type: frm.doc.dunning_type,
language: frm.doc.language, language: frm.doc.language,
@@ -129,25 +129,26 @@ frappe.ui.form.on("Dunning", {
}, },
calculate_overdue_days: function (frm) { calculate_overdue_days: function (frm) {
if (frm.doc.posting_date && frm.doc.due_date) { if (frm.doc.posting_date && frm.doc.due_date) {
const overdue_days = moment(frm.doc.posting_date).diff(frm.doc.due_date, "days"); const overdue_days = moment(frm.doc.posting_date).diff(
frm.doc.due_date,
"days"
);
frm.set_value("overdue_days", overdue_days); frm.set_value("overdue_days", overdue_days);
} }
}, },
calculate_interest_and_amount: function (frm) { calculate_interest_and_amount: function (frm) {
const interest_per_year = (frm.doc.outstanding_amount * frm.doc.rate_of_interest) / 100; const interest_per_year = frm.doc.outstanding_amount * frm.doc.rate_of_interest / 100;
const interest_amount = flt( const interest_amount = flt((interest_per_year * cint(frm.doc.overdue_days)) / 365 || 0, precision('interest_amount'));
(interest_per_year * cint(frm.doc.overdue_days)) / 365 || 0, const dunning_amount = flt(interest_amount + frm.doc.dunning_fee, precision('dunning_amount'));
precision("interest_amount") const grand_total = flt(frm.doc.outstanding_amount + dunning_amount, precision('grand_total'));
);
const dunning_amount = flt(interest_amount + frm.doc.dunning_fee, precision("dunning_amount"));
const grand_total = flt(frm.doc.outstanding_amount + dunning_amount, precision("grand_total"));
frm.set_value("interest_amount", interest_amount); frm.set_value("interest_amount", interest_amount);
frm.set_value("dunning_amount", dunning_amount); frm.set_value("dunning_amount", dunning_amount);
frm.set_value("grand_total", grand_total); frm.set_value("grand_total", grand_total);
}, },
make_payment_entry: function (frm) { make_payment_entry: function (frm) {
return frappe.call({ return frappe.call({
method: "erpnext.accounts.doctype.payment_entry.payment_entry.get_payment_entry", method:
"erpnext.accounts.doctype.payment_entry.payment_entry.get_payment_entry",
args: { args: {
dt: frm.doc.doctype, dt: frm.doc.doctype,
dn: frm.doc.name, dn: frm.doc.name,

View File

@@ -1,7 +1,8 @@
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors // Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Dunning Type", { frappe.ui.form.on('Dunning Type', {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -1,79 +1,75 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors // Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Exchange Rate Revaluation", { frappe.ui.form.on('Exchange Rate Revaluation', {
setup: function (frm) { setup: function(frm) {
frm.set_query("party_type", "accounts", function () { frm.set_query("party_type", "accounts", function() {
return { return {
filters: { "filters": {
name: ["in", Object.keys(frappe.boot.party_account_types)], "name": ["in", Object.keys(frappe.boot.party_account_types)],
}, }
}; };
}); });
frm.set_query("account", "accounts", function (doc) { frm.set_query("account", "accounts", function(doc) {
return { return {
filters: { "filters": {
company: doc.company, "company": doc.company
}, }
}; };
}); });
}, },
refresh: function (frm) { refresh: function(frm) {
if (frm.doc.docstatus == 1) { if(frm.doc.docstatus==1) {
frappe.call({ frappe.call({
method: "check_journal_entry_condition", method: 'check_journal_entry_condition',
doc: frm.doc, doc: frm.doc,
callback: function (r) { callback: function(r) {
if (r.message) { if (r.message) {
frm.add_custom_button( frm.add_custom_button(__('Journal Entries'), function() {
__("Journal Entries"), return frm.events.make_jv(frm);
function () { }, __('Create'));
return frm.events.make_jv(frm);
},
__("Create")
);
} }
}, }
}); });
} }
}, },
validate_rounding_loss: function (frm) { validate_rounding_loss: function(frm) {
let allowance = frm.doc.rounding_loss_allowance; let allowance = frm.doc.rounding_loss_allowance;
if (!(allowance >= 0 && allowance < 1)) { if (!(allowance >= 0 && allowance < 1)) {
frappe.throw(__("Rounding Loss Allowance should be between 0 and 1")); frappe.throw(__("Rounding Loss Allowance should be between 0 and 1"));
} }
}, },
rounding_loss_allowance: function (frm) { rounding_loss_allowance: function(frm) {
frm.events.validate_rounding_loss(frm); frm.events.validate_rounding_loss(frm);
}, },
validate: function (frm) { validate: function(frm) {
frm.events.validate_rounding_loss(frm); frm.events.validate_rounding_loss(frm);
}, },
get_entries: function (frm, account) { get_entries: function(frm, account) {
frappe.call({ frappe.call({
method: "get_accounts_data", method: "get_accounts_data",
doc: cur_frm.doc, doc: cur_frm.doc,
account: account, account: account,
callback: function (r) { callback: function(r){
frappe.model.clear_table(frm.doc, "accounts"); frappe.model.clear_table(frm.doc, "accounts");
if (r.message) { if(r.message) {
r.message.forEach((d) => { r.message.forEach((d) => {
cur_frm.add_child("accounts", d); cur_frm.add_child("accounts",d);
}); });
frm.events.get_total_gain_loss(frm); frm.events.get_total_gain_loss(frm);
refresh_field("accounts"); refresh_field("accounts");
} }
}, }
}); });
}, },
get_total_gain_loss: function (frm) { get_total_gain_loss: function(frm) {
if (!(frm.doc.accounts && frm.doc.accounts.length)) return; if(!(frm.doc.accounts && frm.doc.accounts.length)) return;
let total_gain_loss = 0; let total_gain_loss = 0;
frm.doc.accounts.forEach((d) => { frm.doc.accounts.forEach((d) => {
@@ -84,7 +80,7 @@ frappe.ui.form.on("Exchange Rate Revaluation", {
frm.refresh_fields(); frm.refresh_fields();
}, },
make_jv: function (frm) { make_jv : function(frm) {
let revaluation_journal = null; let revaluation_journal = null;
let zero_balance_journal = null; let zero_balance_journal = null;
frappe.call({ frappe.call({
@@ -92,68 +88,66 @@ frappe.ui.form.on("Exchange Rate Revaluation", {
doc: frm.doc, doc: frm.doc,
freeze: true, freeze: true,
freeze_message: "Making Journal Entries...", freeze_message: "Making Journal Entries...",
callback: function (r) { callback: function(r){
if (r.message) { if (r.message) {
let response = r.message; let response = r.message;
if (response["revaluation_jv"] || response["zero_balance_jv"]) { if(response['revaluation_jv'] || response['zero_balance_jv']) {
frappe.msgprint(__("Journals have been created")); frappe.msgprint(__("Journals have been created"));
} }
} }
}, }
}); });
}, }
}); });
frappe.ui.form.on("Exchange Rate Revaluation Account", { frappe.ui.form.on("Exchange Rate Revaluation Account", {
new_exchange_rate: function (frm, cdt, cdn) { new_exchange_rate: function(frm, cdt, cdn) {
var row = frappe.get_doc(cdt, cdn); var row = frappe.get_doc(cdt, cdn);
row.new_balance_in_base_currency = flt( row.new_balance_in_base_currency = flt(row.new_exchange_rate * flt(row.balance_in_account_currency),
row.new_exchange_rate * flt(row.balance_in_account_currency), precision("new_balance_in_base_currency", row));
precision("new_balance_in_base_currency", row)
);
row.gain_loss = row.new_balance_in_base_currency - flt(row.balance_in_base_currency); row.gain_loss = row.new_balance_in_base_currency - flt(row.balance_in_base_currency);
refresh_field("accounts"); refresh_field("accounts");
frm.events.get_total_gain_loss(frm); frm.events.get_total_gain_loss(frm);
}, },
account: function (frm, cdt, cdn) { account: function(frm, cdt, cdn) {
var row = locals[cdt][cdn]; var row = locals[cdt][cdn];
if (row.account) { if (row.account) {
get_account_details(frm, cdt, cdn); get_account_details(frm, cdt, cdn);
} }
}, },
party: function (frm, cdt, cdn) { party: function(frm, cdt, cdn) {
var row = locals[cdt][cdn]; var row = locals[cdt][cdn];
if (row.party && row.account) { if (row.party && row.account) {
get_account_details(frm, cdt, cdn); get_account_details(frm, cdt, cdn);
} }
}, },
accounts_remove: function (frm) { accounts_remove: function(frm) {
frm.events.get_total_gain_loss(frm); frm.events.get_total_gain_loss(frm);
}, }
}); });
var get_account_details = function (frm, cdt, cdn) { var get_account_details = function(frm, cdt, cdn) {
var row = frappe.get_doc(cdt, cdn); var row = frappe.get_doc(cdt, cdn);
if (!frm.doc.company || !frm.doc.posting_date) { if(!frm.doc.company || !frm.doc.posting_date) {
frappe.throw(__("Please select Company and Posting Date to getting entries")); frappe.throw(__("Please select Company and Posting Date to getting entries"));
} }
frappe.call({ frappe.call({
method: "erpnext.accounts.doctype.exchange_rate_revaluation.exchange_rate_revaluation.get_account_details", method: "erpnext.accounts.doctype.exchange_rate_revaluation.exchange_rate_revaluation.get_account_details",
args: { args:{
account: row.account, account: row.account,
company: frm.doc.company, company: frm.doc.company,
posting_date: frm.doc.posting_date, posting_date: frm.doc.posting_date,
party_type: row.party_type, party_type: row.party_type,
party: row.party, party: row.party,
rounding_loss_allowance: frm.doc.rounding_loss_allowance, rounding_loss_allowance: frm.doc.rounding_loss_allowance
}, },
callback: function (r) { callback: function(r){
$.extend(row, r.message); $.extend(row, r.message);
refresh_field("accounts"); refresh_field("accounts");
frm.events.get_total_gain_loss(frm); frm.events.get_total_gain_loss(frm);
}, }
}); });
}; };

View File

@@ -192,7 +192,7 @@ class ExchangeRateRevaluation(Document):
# round off balance based on currency precision # round off balance based on currency precision
# and consider debit-credit difference allowance # and consider debit-credit difference allowance
currency_precision = get_currency_precision() currency_precision = get_currency_precision()
rounding_loss_allowance = float(rounding_loss_allowance) rounding_loss_allowance = float(rounding_loss_allowance) or 0.05
for acc in account_details: for acc in account_details:
acc.balance_in_account_currency = flt(acc.balance_in_account_currency, currency_precision) acc.balance_in_account_currency = flt(acc.balance_in_account_currency, currency_precision)
if abs(acc.balance_in_account_currency) <= rounding_loss_allowance: if abs(acc.balance_in_account_currency) <= rounding_loss_allowance:
@@ -606,21 +606,21 @@ def get_account_details(
if account_balance and ( if account_balance and (
account_balance[0].balance or account_balance[0].balance_in_account_currency account_balance[0].balance or account_balance[0].balance_in_account_currency
): ):
if account_with_new_balance := ExchangeRateRevaluation.calculate_new_account_balance( account_with_new_balance = ExchangeRateRevaluation.calculate_new_account_balance(
company, posting_date, account_balance company, posting_date, account_balance
): )
row = account_with_new_balance[0] row = account_with_new_balance[0]
account_details.update( account_details.update(
{ {
"balance_in_base_currency": row["balance_in_base_currency"], "balance_in_base_currency": row["balance_in_base_currency"],
"balance_in_account_currency": row["balance_in_account_currency"], "balance_in_account_currency": row["balance_in_account_currency"],
"current_exchange_rate": row["current_exchange_rate"], "current_exchange_rate": row["current_exchange_rate"],
"new_exchange_rate": row["new_exchange_rate"], "new_exchange_rate": row["new_exchange_rate"],
"new_balance_in_base_currency": row["new_balance_in_base_currency"], "new_balance_in_base_currency": row["new_balance_in_base_currency"],
"new_balance_in_account_currency": row["new_balance_in_account_currency"], "new_balance_in_account_currency": row["new_balance_in_account_currency"],
"zero_balance": row["zero_balance"], "zero_balance": row["zero_balance"],
"gain_loss": row["gain_loss"], "gain_loss": row["gain_loss"],
} }
) )
return account_details return account_details

View File

@@ -1,6 +1,8 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors // Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Finance Book", { frappe.ui.form.on('Finance Book', {
refresh: function (frm) {}, refresh: function(frm) {
}
}); });

View File

@@ -1,21 +1,17 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt // License: GNU General Public License v3. See license.txt
frappe.ui.form.on("Fiscal Year", { frappe.ui.form.on('Fiscal Year', {
onload: function (frm) { onload: function(frm) {
if (frm.doc.__islocal) { if(frm.doc.__islocal) {
frm.set_value( frm.set_value("year_start_date",
"year_start_date", frappe.datetime.add_days(frappe.defaults.get_default("year_end_date"), 1));
frappe.datetime.add_days(frappe.defaults.get_default("year_end_date"), 1)
);
} }
}, },
year_start_date: function (frm) { year_start_date: function(frm) {
if (!frm.doc.is_short_year) { if (!frm.doc.is_short_year) {
let year_end_date = frappe.datetime.add_days( let year_end_date =
frappe.datetime.add_months(frm.doc.year_start_date, 12), frappe.datetime.add_days(frappe.datetime.add_months(frm.doc.year_start_date, 12), -1);
-1
);
frm.set_value("year_end_date", year_end_date); frm.set_value("year_end_date", year_end_date);
} }
}, },

View File

@@ -41,7 +41,7 @@ def test_record_generator():
] ]
start = 2012 start = 2012
end = now_datetime().year + 25 end = now_datetime().year + 5
for year in range(start, end): for year in range(start, end):
test_records.append( test_records.append(
{ {

View File

@@ -1,8 +1,8 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors // Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("GL Entry", { frappe.ui.form.on('GL Entry', {
refresh: function (frm) { refresh: function(frm) {
frm.page.btn_secondary.hide(); frm.page.btn_secondary.hide()
}, }
}); });

View File

@@ -138,7 +138,8 @@
"label": "Against Voucher Type", "label": "Against Voucher Type",
"oldfieldname": "against_voucher_type", "oldfieldname": "against_voucher_type",
"oldfieldtype": "Data", "oldfieldtype": "Data",
"options": "DocType" "options": "DocType",
"search_index": 1
}, },
{ {
"fieldname": "against_voucher", "fieldname": "against_voucher",
@@ -157,7 +158,8 @@
"label": "Voucher Type", "label": "Voucher Type",
"oldfieldname": "voucher_type", "oldfieldname": "voucher_type",
"oldfieldtype": "Select", "oldfieldtype": "Select",
"options": "DocType" "options": "DocType",
"search_index": 1
}, },
{ {
"fieldname": "voucher_no", "fieldname": "voucher_no",
@@ -174,8 +176,7 @@
"fieldname": "voucher_detail_no", "fieldname": "voucher_detail_no",
"fieldtype": "Data", "fieldtype": "Data",
"label": "Voucher Detail No", "label": "Voucher Detail No",
"read_only": 1, "read_only": 1
"search_index": 1
}, },
{ {
"fieldname": "project", "fieldname": "project",
@@ -257,8 +258,7 @@
"icon": "fa fa-list", "icon": "fa fa-list",
"idx": 1, "idx": 1,
"in_create": 1, "in_create": 1,
"links": [], "modified": "2020-04-07 16:22:33.766994",
"modified": "2024-03-19 18:30:49.613401",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "GL Entry", "name": "GL Entry",
@@ -290,6 +290,5 @@
"quick_entry": 1, "quick_entry": 1,
"search_fields": "voucher_no,account,posting_date,against_voucher", "search_fields": "voucher_no,account,posting_date,against_voucher",
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC"
"states": []
} }

View File

@@ -13,9 +13,16 @@ import erpnext
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
get_checks_for_pl_and_bs_accounts, get_checks_for_pl_and_bs_accounts,
) )
from erpnext.accounts.doctype.accounting_dimension_filter.accounting_dimension_filter import (
get_dimension_filter_map,
)
from erpnext.accounts.party import validate_party_frozen_disabled, validate_party_gle_currency from erpnext.accounts.party import validate_party_frozen_disabled, validate_party_gle_currency
from erpnext.accounts.utils import get_account_currency, get_fiscal_year from erpnext.accounts.utils import get_account_currency, get_fiscal_year
from erpnext.exceptions import InvalidAccountCurrency from erpnext.exceptions import (
InvalidAccountCurrency,
InvalidAccountDimensionError,
MandatoryAccountDimensionError,
)
exclude_from_linked_with = True exclude_from_linked_with = True
@@ -47,6 +54,7 @@ class GLEntry(Document):
if not self.flags.from_repost and self.voucher_type != "Period Closing Voucher": if not self.flags.from_repost and self.voucher_type != "Period Closing Voucher":
self.validate_account_details(adv_adj) self.validate_account_details(adv_adj)
self.validate_dimensions_for_pl_and_bs() self.validate_dimensions_for_pl_and_bs()
self.validate_allowed_dimensions()
validate_balance_type(self.account, adv_adj) validate_balance_type(self.account, adv_adj)
validate_frozen_account(self.account, adv_adj) validate_frozen_account(self.account, adv_adj)
@@ -127,7 +135,7 @@ class GLEntry(Document):
frappe.throw(msg, title=_("Missing Cost Center")) frappe.throw(msg, title=_("Missing Cost Center"))
def validate_dimensions_for_pl_and_bs(self): def validate_dimensions_for_pl_and_bs(self):
account_type = frappe.get_cached_value("Account", self.account, "report_type") account_type = frappe.db.get_value("Account", self.account, "report_type")
for dimension in get_checks_for_pl_and_bs_accounts(): for dimension in get_checks_for_pl_and_bs_accounts():
if ( if (
@@ -156,10 +164,46 @@ class GLEntry(Document):
) )
) )
def validate_allowed_dimensions(self):
dimension_filter_map = get_dimension_filter_map()
for key, value in dimension_filter_map.items():
dimension = key[0]
account = key[1]
if self.account == account:
if value["is_mandatory"] and not self.get(dimension):
frappe.throw(
_("{0} is mandatory for account {1}").format(
frappe.bold(frappe.unscrub(dimension)), frappe.bold(self.account)
),
MandatoryAccountDimensionError,
)
if value["allow_or_restrict"] == "Allow":
if self.get(dimension) and self.get(dimension) not in value["allowed_dimensions"]:
frappe.throw(
_("Invalid value {0} for {1} against account {2}").format(
frappe.bold(self.get(dimension)),
frappe.bold(frappe.unscrub(dimension)),
frappe.bold(self.account),
),
InvalidAccountDimensionError,
)
else:
if self.get(dimension) and self.get(dimension) in value["allowed_dimensions"]:
frappe.throw(
_("Invalid value {0} for {1} against account {2}").format(
frappe.bold(self.get(dimension)),
frappe.bold(frappe.unscrub(dimension)),
frappe.bold(self.account),
),
InvalidAccountDimensionError,
)
def check_pl_account(self): def check_pl_account(self):
if ( if (
self.is_opening == "Yes" self.is_opening == "Yes"
and frappe.get_cached_value("Account", self.account, "report_type") == "Profit and Loss" and frappe.db.get_value("Account", self.account, "report_type") == "Profit and Loss"
and not self.is_cancelled and not self.is_cancelled
): ):
frappe.throw( frappe.throw(
@@ -252,7 +296,7 @@ class GLEntry(Document):
def validate_balance_type(account, adv_adj=False): def validate_balance_type(account, adv_adj=False):
if not adv_adj and account: if not adv_adj and account:
balance_must_be = frappe.get_cached_value("Account", account, "balance_must_be") balance_must_be = frappe.db.get_value("Account", account, "balance_must_be")
if balance_must_be: if balance_must_be:
balance = frappe.db.sql( balance = frappe.db.sql(
"""select sum(debit) - sum(credit) """select sum(debit) - sum(credit)
@@ -279,7 +323,7 @@ def update_outstanding_amt(
party_condition = "" party_condition = ""
if against_voucher_type == "Sales Invoice": if against_voucher_type == "Sales Invoice":
party_account = frappe.get_cached_value(against_voucher_type, against_voucher, "debit_to") party_account = frappe.db.get_value(against_voucher_type, against_voucher, "debit_to")
account_condition = "and account in ({0}, {1})".format( account_condition = "and account in ({0}, {1})".format(
frappe.db.escape(account), frappe.db.escape(party_account) frappe.db.escape(account), frappe.db.escape(party_account)
) )
@@ -347,7 +391,7 @@ def update_outstanding_amt(
def validate_frozen_account(account, adv_adj=None): def validate_frozen_account(account, adv_adj=None):
frozen_account = frappe.get_cached_value("Account", account, "freeze_account") frozen_account = frappe.get_cached_value("Account", account, "freeze_account")
if frozen_account == "Yes" and not adv_adj: if frozen_account == "Yes" and not adv_adj:
frozen_accounts_modifier = frappe.get_cached_value( frozen_accounts_modifier = frappe.db.get_value(
"Accounts Settings", None, "frozen_accounts_modifier" "Accounts Settings", None, "frozen_accounts_modifier"
) )

View File

@@ -1,49 +1,47 @@
// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors // Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Invoice Discounting", { frappe.ui.form.on('Invoice Discounting', {
setup: (frm) => { setup: (frm) => {
frm.set_query("sales_invoice", "invoices", (doc) => { frm.set_query("sales_invoice", "invoices", (doc) => {
return { return {
filters: { "filters": {
docstatus: 1, "docstatus": 1,
company: doc.company, "company": doc.company,
outstanding_amount: [">", 0], "outstanding_amount": [">", 0]
}, },
}; };
}); });
frm.events.filter_accounts("bank_account", frm, [["account_type", "=", "Bank"]]); frm.events.filter_accounts("bank_account", frm, [["account_type", "=", "Bank"]]);
frm.events.filter_accounts("bank_charges_account", frm, [["root_type", "=", "Expense"]]); frm.events.filter_accounts("bank_charges_account", frm, [["root_type", "=", "Expense"]]);
frm.events.filter_accounts("short_term_loan", frm, [["root_type", "=", "Liability"]]); frm.events.filter_accounts("short_term_loan", frm, [["root_type", "=", "Liability"]]);
frm.events.filter_accounts("accounts_receivable_discounted", frm, [ frm.events.filter_accounts("accounts_receivable_discounted", frm, [["account_type", "=", "Receivable"]]);
["account_type", "=", "Receivable"],
]);
frm.events.filter_accounts("accounts_receivable_credit", frm, [["account_type", "=", "Receivable"]]); frm.events.filter_accounts("accounts_receivable_credit", frm, [["account_type", "=", "Receivable"]]);
frm.events.filter_accounts("accounts_receivable_unpaid", frm, [["account_type", "=", "Receivable"]]); frm.events.filter_accounts("accounts_receivable_unpaid", frm, [["account_type", "=", "Receivable"]]);
}, },
filter_accounts: (fieldname, frm, addl_filters) => { filter_accounts: (fieldname, frm, addl_filters) => {
let filters = [ let filters = [
["company", "=", frm.doc.company], ["company", "=", frm.doc.company],
["is_group", "=", 0], ["is_group", "=", 0]
]; ];
if (addl_filters) { if(addl_filters){
filters = $.merge(filters, addl_filters); filters = $.merge(filters , addl_filters);
} }
frm.set_query(fieldname, () => { frm.set_query(fieldname, () => { return { "filters": filters }; });
return { filters: filters };
});
}, },
refresh_filters: (frm) => { refresh_filters: (frm) =>{
let invoice_accounts = Object.keys(frm.doc.invoices).map(function (key) { let invoice_accounts = Object.keys(frm.doc.invoices).map(function(key) {
return frm.doc.invoices[key].debit_to; return frm.doc.invoices[key].debit_to;
}); });
let filters = [ let filters = [
["account_type", "=", "Receivable"], ["account_type", "=", "Receivable"],
["name", "not in", invoice_accounts], ["name", "not in", invoice_accounts]
]; ];
frm.events.filter_accounts("accounts_receivable_credit", frm, filters); frm.events.filter_accounts("accounts_receivable_credit", frm, filters);
frm.events.filter_accounts("accounts_receivable_discounted", frm, filters); frm.events.filter_accounts("accounts_receivable_discounted", frm, filters);
@@ -54,19 +52,19 @@ frappe.ui.form.on("Invoice Discounting", {
frm.events.show_general_ledger(frm); frm.events.show_general_ledger(frm);
if (frm.doc.docstatus === 0) { if (frm.doc.docstatus === 0) {
frm.add_custom_button(__("Get Invoices"), function () { frm.add_custom_button(__('Get Invoices'), function() {
frm.events.get_invoices(frm); frm.events.get_invoices(frm);
}); });
} }
if (frm.doc.docstatus === 1 && frm.doc.status !== "Settled") { if (frm.doc.docstatus === 1 && frm.doc.status !== "Settled") {
if (frm.doc.status == "Sanctioned") { if (frm.doc.status == "Sanctioned") {
frm.add_custom_button(__("Disburse Loan"), function () { frm.add_custom_button(__('Disburse Loan'), function() {
frm.events.create_disbursement_entry(frm); frm.events.create_disbursement_entry(frm);
}).addClass("btn-primary"); }).addClass("btn-primary");
} }
if (frm.doc.status == "Disbursed") { if (frm.doc.status == "Disbursed") {
frm.add_custom_button(__("Close Loan"), function () { frm.add_custom_button(__('Close Loan'), function() {
frm.events.close_loan(frm); frm.events.close_loan(frm);
}).addClass("btn-primary"); }).addClass("btn-primary");
} }
@@ -94,121 +92,119 @@ frappe.ui.form.on("Invoice Discounting", {
calculate_total_amount: (frm) => { calculate_total_amount: (frm) => {
let total_amount = 0.0; let total_amount = 0.0;
for (let row of frm.doc.invoices || []) { for (let row of (frm.doc.invoices || [])) {
total_amount += flt(row.outstanding_amount); total_amount += flt(row.outstanding_amount);
} }
frm.set_value("total_amount", total_amount); frm.set_value("total_amount", total_amount);
}, },
get_invoices: (frm) => { get_invoices: (frm) => {
var d = new frappe.ui.Dialog({ var d = new frappe.ui.Dialog({
title: __("Get Invoices based on Filters"), title: __('Get Invoices based on Filters'),
fields: [ fields: [
{ {
label: "Customer", "label": "Customer",
fieldname: "customer", "fieldname": "customer",
fieldtype: "Link", "fieldtype": "Link",
options: "Customer", "options": "Customer"
}, },
{ {
label: "From Date", "label": "From Date",
fieldname: "from_date", "fieldname": "from_date",
fieldtype: "Date", "fieldtype": "Date"
}, },
{ {
label: "To Date", "label": "To Date",
fieldname: "to_date", "fieldname": "to_date",
fieldtype: "Date", "fieldtype": "Date"
}, },
{ {
fieldname: "col_break", "fieldname": "col_break",
fieldtype: "Column Break", "fieldtype": "Column Break",
}, },
{ {
label: "Min Amount", "label": "Min Amount",
fieldname: "min_amount", "fieldname": "min_amount",
fieldtype: "Currency", "fieldtype": "Currency"
}, },
{ {
label: "Max Amount", "label": "Max Amount",
fieldname: "max_amount", "fieldname": "max_amount",
fieldtype: "Currency", "fieldtype": "Currency"
}, }
], ],
primary_action: function () { primary_action: function() {
var data = d.get_values(); var data = d.get_values();
frappe.call({ frappe.call({
method: "erpnext.accounts.doctype.invoice_discounting.invoice_discounting.get_invoices", method: "erpnext.accounts.doctype.invoice_discounting.invoice_discounting.get_invoices",
args: { args: {
filters: data, filters: data
}, },
callback: function (r) { callback: function(r) {
if (!r.exc) { if(!r.exc) {
d.hide(); d.hide();
$.each(r.message, function (i, v) { $.each(r.message, function(i, v) {
frm.doc.invoices = frm.doc.invoices.filter((row) => row.sales_invoice); frm.doc.invoices = frm.doc.invoices.filter(row => row.sales_invoice);
let row = frm.add_child("invoices"); let row = frm.add_child("invoices");
$.extend(row, v); $.extend(row, v);
frm.events.refresh_filters(frm); frm.events.refresh_filters(frm);
}); });
refresh_field("invoices"); refresh_field("invoices");
} }
}, }
}); });
}, },
primary_action_label: __("Get Invocies"), primary_action_label: __('Get Invocies')
}); });
d.show(); d.show();
}, },
create_disbursement_entry: (frm) => { create_disbursement_entry: (frm) => {
frappe.call({ frappe.call({
method: "create_disbursement_entry", method:"create_disbursement_entry",
doc: frm.doc, doc: frm.doc,
callback: function (r) { callback: function(r) {
if (!r.exc) { if(!r.exc){
var doclist = frappe.model.sync(r.message); var doclist = frappe.model.sync(r.message);
frappe.set_route("Form", doclist[0].doctype, doclist[0].name); frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
} }
}, }
}); });
}, },
close_loan: (frm) => { close_loan: (frm) => {
frappe.call({ frappe.call({
method: "close_loan", method:"close_loan",
doc: frm.doc, doc: frm.doc,
callback: function (r) { callback: function(r) {
if (!r.exc) { if(!r.exc){
var doclist = frappe.model.sync(r.message); var doclist = frappe.model.sync(r.message);
frappe.set_route("Form", doclist[0].doctype, doclist[0].name); frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
} }
}, }
}); });
}, },
show_general_ledger: (frm) => { show_general_ledger: (frm) => {
if (frm.doc.docstatus > 0) { if(frm.doc.docstatus > 0) {
cur_frm.add_custom_button( cur_frm.add_custom_button(__('Accounting Ledger'), function() {
__("Accounting Ledger"), frappe.route_options = {
function () { voucher_no: frm.doc.name,
frappe.route_options = { from_date: frm.doc.posting_date,
voucher_no: frm.doc.name, to_date: moment(frm.doc.modified).format('YYYY-MM-DD'),
from_date: frm.doc.posting_date, company: frm.doc.company,
to_date: moment(frm.doc.modified).format("YYYY-MM-DD"), group_by: "Group by Voucher (Consolidated)",
company: frm.doc.company, show_cancelled_entries: frm.doc.docstatus === 2
group_by: "Group by Voucher (Consolidated)", };
show_cancelled_entries: frm.doc.docstatus === 2, frappe.set_route("query-report", "General Ledger");
}; }, __("View"));
frappe.set_route("query-report", "General Ledger");
},
__("View")
);
} }
}, }
}); });
frappe.ui.form.on("Discounted Invoice", { frappe.ui.form.on('Discounted Invoice', {
sales_invoice: (frm) => { sales_invoice: (frm) => {
frm.events.calculate_total_amount(frm); frm.events.calculate_total_amount(frm);
frm.events.refresh_filters(frm); frm.events.refresh_filters(frm);
@@ -216,5 +212,5 @@ frappe.ui.form.on("Discounted Invoice", {
invoices_remove: (frm) => { invoices_remove: (frm) => {
frm.events.calculate_total_amount(frm); frm.events.calculate_total_amount(frm);
frm.events.refresh_filters(frm); frm.events.refresh_filters(frm);
}, }
}); });

View File

@@ -1,16 +1,21 @@
frappe.listview_settings["Invoice Discounting"] = { frappe.listview_settings['Invoice Discounting'] = {
add_fields: ["status"], add_fields: ["status"],
get_indicator: function (doc) { get_indicator: function(doc)
if (doc.status == "Draft") { {
if(doc.status == "Draft") {
return [__("Draft"), "red", "status,=,Draft"]; return [__("Draft"), "red", "status,=,Draft"];
} else if (doc.status == "Sanctioned") { }
else if(doc.status == "Sanctioned") {
return [__("Sanctioned"), "green", "status,=,Sanctioned"]; return [__("Sanctioned"), "green", "status,=,Sanctioned"];
} else if (doc.status == "Disbursed") { }
else if(doc.status == "Disbursed") {
return [__("Disbursed"), "blue", "status,=,Disbursed"]; return [__("Disbursed"), "blue", "status,=,Disbursed"];
} else if (doc.status == "Settled") { }
else if(doc.status == "Settled") {
return [__("Settled"), "orange", "status,=,Settled"]; return [__("Settled"), "orange", "status,=,Settled"];
} else if (doc.status == "Canceled") { }
else if(doc.status == "Canceled") {
return [__("Canceled"), "red", "status,=,Canceled"]; return [__("Canceled"), "red", "status,=,Canceled"];
} }
}, }
}; };

View File

@@ -1,49 +1,27 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors // Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Item Tax Template", { frappe.ui.form.on('Item Tax Template', {
setup: function (frm) { setup: function(frm) {
frm.set_query("tax_type", "taxes", function (doc) { frm.set_query("tax_type", "taxes", function(doc) {
return { return {
filters: [ filters: [
["Account", "company", "=", frm.doc.company], ['Account', 'company', '=', frm.doc.company],
["Account", "is_group", "=", 0], ['Account', 'is_group', '=', 0],
[ ['Account', 'account_type', 'in', ['Tax', 'Chargeable', 'Income Account', 'Expense Account', 'Expenses Included In Valuation']]
"Account", ]
"account_type", }
"in",
[
"Tax",
"Chargeable",
"Income Account",
"Expense Account",
"Expenses Included In Valuation",
],
],
],
};
}); });
}, },
company: function (frm) { company: function (frm) {
frm.set_query("tax_type", "taxes", function (doc) { frm.set_query("tax_type", "taxes", function(doc) {
return { return {
filters: [ filters: [
["Account", "company", "=", frm.doc.company], ['Account', 'company', '=', frm.doc.company],
["Account", "is_group", "=", 0], ['Account', 'is_group', '=', 0],
[ ['Account', 'account_type', 'in', ['Tax', 'Chargeable', 'Income Account', 'Expense Account', 'Expenses Included In Valuation']]
"Account", ]
"account_type", }
"in",
[
"Tax",
"Chargeable",
"Income Account",
"Expense Account",
"Expenses Included In Valuation",
],
],
],
};
}); });
}, }
}); });

View File

@@ -4,57 +4,39 @@
frappe.provide("erpnext.accounts"); frappe.provide("erpnext.accounts");
frappe.provide("erpnext.journal_entry"); frappe.provide("erpnext.journal_entry");
frappe.ui.form.on("Journal Entry", { frappe.ui.form.on("Journal Entry", {
setup: function (frm) { setup: function(frm) {
frm.add_fetch("bank_account", "account", "account"); frm.add_fetch("bank_account", "account", "account");
frm.ignore_doctypes_on_cancel_all = [ frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice', 'Journal Entry', 'Repost Payment Ledger', 'Asset', 'Asset Movement', 'Repost Accounting Ledger'];
"Sales Invoice",
"Purchase Invoice",
"Journal Entry",
"Repost Payment Ledger",
"Asset",
"Asset Movement",
"Repost Accounting Ledger",
"Unreconcile Payment",
"Unreconcile Payment Entries",
"Bank Transaction",
];
}, },
refresh: function (frm) { refresh: function(frm) {
erpnext.toggle_naming_series(); erpnext.toggle_naming_series();
if (frm.doc.docstatus > 0) { if(frm.doc.docstatus > 0) {
frm.add_custom_button( frm.add_custom_button(__('Ledger'), function() {
__("Ledger"), frappe.route_options = {
function () { "voucher_no": frm.doc.name,
frappe.route_options = { "from_date": frm.doc.posting_date,
voucher_no: frm.doc.name, "to_date": moment(frm.doc.modified).format('YYYY-MM-DD'),
from_date: frm.doc.posting_date, "company": frm.doc.company,
to_date: moment(frm.doc.modified).format("YYYY-MM-DD"), "finance_book": frm.doc.finance_book,
company: frm.doc.company, "group_by": '',
finance_book: frm.doc.finance_book, "show_cancelled_entries": frm.doc.docstatus === 2
group_by: "", };
show_cancelled_entries: frm.doc.docstatus === 2, frappe.set_route("query-report", "General Ledger");
}; }, __('View'));
frappe.set_route("query-report", "General Ledger");
},
__("View")
);
} }
if (frm.doc.docstatus == 1) { if(frm.doc.docstatus==1) {
frm.add_custom_button( frm.add_custom_button(__('Reverse Journal Entry'), function() {
__("Reverse Journal Entry"), return erpnext.journal_entry.reverse_journal_entry(frm);
function () { }, __('Actions'));
return erpnext.journal_entry.reverse_journal_entry(frm);
},
__("Actions")
);
} }
if (frm.doc.__islocal) { if (frm.doc.__islocal) {
frm.add_custom_button(__("Quick Entry"), function () { frm.add_custom_button(__('Quick Entry'), function() {
return erpnext.journal_entry.quick_entry(frm); return erpnext.journal_entry.quick_entry(frm);
}); });
} }
@@ -62,63 +44,42 @@ frappe.ui.form.on("Journal Entry", {
// hide /unhide fields based on currency // hide /unhide fields based on currency
erpnext.journal_entry.toggle_fields_based_on_currency(frm); erpnext.journal_entry.toggle_fields_based_on_currency(frm);
if ( if ((frm.doc.voucher_type == "Inter Company Journal Entry") && (frm.doc.docstatus == 1) && (!frm.doc.inter_company_journal_entry_reference)) {
frm.doc.voucher_type == "Inter Company Journal Entry" && frm.add_custom_button(__("Create Inter Company Journal Entry"),
frm.doc.docstatus == 1 && function() {
!frm.doc.inter_company_journal_entry_reference
) {
frm.add_custom_button(
__("Create Inter Company Journal Entry"),
function () {
frm.trigger("make_inter_company_journal_entry"); frm.trigger("make_inter_company_journal_entry");
}, }, __('Make'));
__("Make")
);
} }
},
erpnext.accounts.unreconcile_payment.add_unreconcile_btn(frm); make_inter_company_journal_entry: function(frm) {
},
before_save: function (frm) {
if (frm.doc.docstatus == 0 && !frm.doc.is_system_generated) {
let payment_entry_references = frm.doc.accounts.filter(
(elem) => elem.reference_type == "Payment Entry"
);
if (payment_entry_references.length > 0) {
let rows = payment_entry_references.map((x) => "#" + x.idx);
frappe.throw(
__("Rows: {0} have 'Payment Entry' as reference_type. This should not be set manually.", [
frappe.utils.comma_and(rows),
])
);
}
}
},
make_inter_company_journal_entry: function (frm) {
var d = new frappe.ui.Dialog({ var d = new frappe.ui.Dialog({
title: __("Select Company"), title: __("Select Company"),
fields: [ fields: [
{ {
fieldname: "company", 'fieldname': 'company',
fieldtype: "Link", 'fieldtype': 'Link',
label: __("Company"), 'label': __('Company'),
options: "Company", 'options': 'Company',
get_query: function () { "get_query": function () {
return { return {
filters: [["Company", "name", "!=", frm.doc.company]], filters: [
["Company", "name", "!=", frm.doc.company]
]
}; };
}, },
reqd: 1, 'reqd': 1
}, }
], ],
}); });
d.set_primary_action(__("Create"), function () { d.set_primary_action(__('Create'), function() {
d.hide(); d.hide();
var args = d.get_values(); var args = d.get_values();
frappe.call({ frappe.call({
args: { args: {
name: frm.doc.name, "name": frm.doc.name,
voucher_type: frm.doc.voucher_type, "voucher_type": frm.doc.voucher_type,
company: args.company, "company": args.company
}, },
method: "erpnext.accounts.doctype.journal_entry.journal_entry.make_inter_company_journal_entry", method: "erpnext.accounts.doctype.journal_entry.journal_entry.make_inter_company_journal_entry",
callback: function (r) { callback: function (r) {
@@ -126,106 +87,103 @@ frappe.ui.form.on("Journal Entry", {
var doc = frappe.model.sync(r.message)[0]; var doc = frappe.model.sync(r.message)[0];
frappe.set_route("Form", doc.doctype, doc.name); frappe.set_route("Form", doc.doctype, doc.name);
} }
}, }
}); });
}); });
d.show(); d.show();
}, },
multi_currency: function (frm) { multi_currency: function(frm) {
erpnext.journal_entry.toggle_fields_based_on_currency(frm); erpnext.journal_entry.toggle_fields_based_on_currency(frm);
}, },
posting_date: function (frm) { posting_date: function(frm) {
if (!frm.doc.multi_currency || !frm.doc.posting_date) return; if(!frm.doc.multi_currency || !frm.doc.posting_date) return;
$.each(frm.doc.accounts || [], function (i, row) { $.each(frm.doc.accounts || [], function(i, row) {
erpnext.journal_entry.set_exchange_rate(frm, row.doctype, row.name); erpnext.journal_entry.set_exchange_rate(frm, row.doctype, row.name);
}); })
}, },
company: function (frm) { company: function(frm) {
frappe.call({ frappe.call({
method: "frappe.client.get_value", method: "frappe.client.get_value",
args: { args: {
doctype: "Company", doctype: "Company",
filters: { name: frm.doc.company }, filters: {"name": frm.doc.company},
fieldname: "cost_center", fieldname: "cost_center"
}, },
callback: function (r) { callback: function(r){
if (r.message) { if(r.message){
$.each(frm.doc.accounts || [], function (i, jvd) { $.each(frm.doc.accounts || [], function(i, jvd) {
frappe.model.set_value(jvd.doctype, jvd.name, "cost_center", r.message.cost_center); frappe.model.set_value(jvd.doctype, jvd.name, "cost_center", r.message.cost_center);
}); });
} }
}, }
}); });
erpnext.accounts.dimensions.update_dimension(frm, frm.doctype); erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
}, },
voucher_type: function (frm) { voucher_type: function(frm){
if (!frm.doc.company) return null;
if ( if(!frm.doc.company) return null;
!(frm.doc.accounts || []).length ||
((frm.doc.accounts || []).length === 1 && !frm.doc.accounts[0].account) if((!(frm.doc.accounts || []).length) || ((frm.doc.accounts || []).length === 1 && !frm.doc.accounts[0].account)) {
) { if(in_list(["Bank Entry", "Cash Entry"], frm.doc.voucher_type)) {
if (in_list(["Bank Entry", "Cash Entry"], frm.doc.voucher_type)) {
return frappe.call({ return frappe.call({
type: "GET", type: "GET",
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_default_bank_cash_account", method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_default_bank_cash_account",
args: { args: {
account_type: "account_type": (frm.doc.voucher_type=="Bank Entry" ?
frm.doc.voucher_type == "Bank Entry" "Bank" : (frm.doc.voucher_type=="Cash Entry" ? "Cash" : null)),
? "Bank" "company": frm.doc.company
: frm.doc.voucher_type == "Cash Entry"
? "Cash"
: null,
company: frm.doc.company,
}, },
callback: function (r) { callback: function(r) {
if (r.message) { if(r.message) {
// If default company bank account not set // If default company bank account not set
if (!$.isEmptyObject(r.message)) { if(!$.isEmptyObject(r.message)){
update_jv_details(frm.doc, [r.message]); update_jv_details(frm.doc, [r.message]);
} }
} }
}, }
}); });
} }
} }
}, },
from_template: function (frm) { from_template: function(frm){
if (frm.doc.from_template) { if (frm.doc.from_template){
frappe.db.get_doc("Journal Entry Template", frm.doc.from_template).then((doc) => { frappe.db.get_doc("Journal Entry Template", frm.doc.from_template)
frappe.model.clear_table(frm.doc, "accounts"); .then((doc) => {
frm.set_value({ frappe.model.clear_table(frm.doc, "accounts");
company: doc.company, frm.set_value({
voucher_type: doc.voucher_type, "company": doc.company,
naming_series: doc.naming_series, "voucher_type": doc.voucher_type,
is_opening: doc.is_opening, "naming_series": doc.naming_series,
multi_currency: doc.multi_currency, "is_opening": doc.is_opening,
"multi_currency": doc.multi_currency
})
update_jv_details(frm.doc, doc.accounts);
}); });
update_jv_details(frm.doc, doc.accounts);
});
} }
}, }
}); });
var update_jv_details = function (doc, r) { var update_jv_details = function(doc, r) {
$.each(r, function (i, d) { $.each(r, function(i, d) {
var row = frappe.model.add_child(doc, "Journal Entry Account", "accounts"); var row = frappe.model.add_child(doc, "Journal Entry Account", "accounts");
frappe.model.set_value(row.doctype, row.name, "account", d.account); frappe.model.set_value(row.doctype, row.name, "account", d.account)
frappe.model.set_value(row.doctype, row.name, "balance", d.balance)
}); });
refresh_field("accounts"); refresh_field("accounts");
}; }
erpnext.accounts.JournalEntry = class JournalEntry extends frappe.ui.form.Controller { erpnext.accounts.JournalEntry = class JournalEntry extends frappe.ui.form.Controller {
onload() { onload() {
this.load_defaults(); this.load_defaults();
this.setup_queries(); this.setup_queries();
this.setup_balance_formatter();
erpnext.accounts.dimensions.setup_dimension_filters(this.frm, this.frm.doctype); erpnext.accounts.dimensions.setup_dimension_filters(this.frm, this.frm.doctype);
} }
@@ -235,67 +193,69 @@ erpnext.accounts.JournalEntry = class JournalEntry extends frappe.ui.form.Contro
load_defaults() { load_defaults() {
//this.frm.show_print_first = true; //this.frm.show_print_first = true;
if (this.frm.doc.__islocal && this.frm.doc.company) { if(this.frm.doc.__islocal && this.frm.doc.company) {
frappe.model.set_default_values(this.frm.doc); frappe.model.set_default_values(this.frm.doc);
$.each(this.frm.doc.accounts || [], function (i, jvd) { $.each(this.frm.doc.accounts || [], function(i, jvd) {
frappe.model.set_default_values(jvd); frappe.model.set_default_values(jvd);
}); });
var posting_date = this.frm.doc.posting_date; var posting_date = this.frm.doc.posting_date;
if (!this.frm.doc.amended_from) if(!this.frm.doc.amended_from) this.frm.set_value('posting_date', posting_date || frappe.datetime.get_today());
this.frm.set_value("posting_date", posting_date || frappe.datetime.get_today());
} }
} }
setup_queries() { setup_queries() {
var me = this; var me = this;
me.frm.set_query("account", "accounts", function (doc, cdt, cdn) { me.frm.set_query("account", "accounts", function(doc, cdt, cdn) {
return erpnext.journal_entry.account_query(me.frm); return erpnext.journal_entry.account_query(me.frm);
}); });
me.frm.set_query("party_type", "accounts", function (doc, cdt, cdn) { me.frm.set_query("party_type", "accounts", function(doc, cdt, cdn) {
const row = locals[cdt][cdn]; const row = locals[cdt][cdn];
return { return {
query: "erpnext.setup.doctype.party_type.party_type.get_party_type", query: "erpnext.setup.doctype.party_type.party_type.get_party_type",
filters: { filters: {
account: row.account, 'account': row.account
}, }
}; }
}); });
me.frm.set_query("reference_name", "accounts", function (doc, cdt, cdn) { me.frm.set_query("reference_name", "accounts", function(doc, cdt, cdn) {
var jvd = frappe.get_doc(cdt, cdn); var jvd = frappe.get_doc(cdt, cdn);
// journal entry // journal entry
if (jvd.reference_type === "Journal Entry") { if(jvd.reference_type==="Journal Entry") {
frappe.model.validate_missing(jvd, "account"); frappe.model.validate_missing(jvd, "account");
return { return {
query: "erpnext.accounts.doctype.journal_entry.journal_entry.get_against_jv", query: "erpnext.accounts.doctype.journal_entry.journal_entry.get_against_jv",
filters: { filters: {
account: jvd.account, account: jvd.account,
party: jvd.party, party: jvd.party
}, }
}; };
} }
var out = { var out = {
filters: [[jvd.reference_type, "docstatus", "=", 1]], filters: [
[jvd.reference_type, "docstatus", "=", 1]
]
}; };
if (in_list(["Sales Invoice", "Purchase Invoice"], jvd.reference_type)) { if(in_list(["Sales Invoice", "Purchase Invoice"], jvd.reference_type)) {
out.filters.push([jvd.reference_type, "outstanding_amount", "!=", 0]); out.filters.push([jvd.reference_type, "outstanding_amount", "!=", 0]);
// Filter by cost center // Filter by cost center
if (jvd.cost_center) { if(jvd.cost_center) {
out.filters.push([jvd.reference_type, "cost_center", "in", ["", jvd.cost_center]]); out.filters.push([jvd.reference_type, "cost_center", "in", ["", jvd.cost_center]]);
} }
// account filter // account filter
frappe.model.validate_missing(jvd, "account"); frappe.model.validate_missing(jvd, "account");
var party_account_field = jvd.reference_type === "Sales Invoice" ? "debit_to" : "credit_to"; var party_account_field = jvd.reference_type==="Sales Invoice" ? "debit_to": "credit_to";
out.filters.push([jvd.reference_type, party_account_field, "=", jvd.account]); out.filters.push([jvd.reference_type, party_account_field, "=", jvd.account]);
} }
if (in_list(["Sales Order", "Purchase Order"], jvd.reference_type)) { if(in_list(["Sales Order", "Purchase Order"], jvd.reference_type)) {
// party_type and party mandatory // party_type and party mandatory
frappe.model.validate_missing(jvd, "party_type"); frappe.model.validate_missing(jvd, "party_type");
frappe.model.validate_missing(jvd, "party"); frappe.model.validate_missing(jvd, "party");
@@ -303,11 +263,11 @@ erpnext.accounts.JournalEntry = class JournalEntry extends frappe.ui.form.Contro
out.filters.push([jvd.reference_type, "per_billed", "<", 100]); out.filters.push([jvd.reference_type, "per_billed", "<", 100]);
} }
if (jvd.party_type && jvd.party) { if(jvd.party_type && jvd.party) {
var party_field = ""; var party_field = "";
if (jvd.reference_type.indexOf("Sales") === 0) { if(jvd.reference_type.indexOf("Sales")===0) {
var party_field = "customer"; var party_field = "customer";
} else if (jvd.reference_type.indexOf("Purchase") === 0) { } else if (jvd.reference_type.indexOf("Purchase")===0) {
var party_field = "supplier"; var party_field = "supplier";
} }
@@ -318,49 +278,64 @@ erpnext.accounts.JournalEntry = class JournalEntry extends frappe.ui.form.Contro
return out; return out;
}); });
}
setup_balance_formatter() {
const formatter = function(value, df, options, doc) {
var currency = frappe.meta.get_field_currency(df, doc);
var dr_or_cr = value ? ('<label>' + (value > 0.0 ? __("Dr") : __("Cr")) + '</label>') : "";
return "<div style='text-align: right'>"
+ ((value==null || value==="") ? "" : format_currency(Math.abs(value), currency))
+ " " + dr_or_cr
+ "</div>";
};
this.frm.fields_dict.accounts.grid.update_docfield_property('balance', 'formatter', formatter);
this.frm.fields_dict.accounts.grid.update_docfield_property('party_balance', 'formatter', formatter);
} }
reference_name(doc, cdt, cdn) { reference_name(doc, cdt, cdn) {
var d = frappe.get_doc(cdt, cdn); var d = frappe.get_doc(cdt, cdn);
if (d.reference_name) { if(d.reference_name) {
if (d.reference_type === "Purchase Invoice" && !flt(d.debit)) { if (d.reference_type==="Purchase Invoice" && !flt(d.debit)) {
this.get_outstanding("Purchase Invoice", d.reference_name, doc.company, d); this.get_outstanding('Purchase Invoice', d.reference_name, doc.company, d);
} else if (d.reference_type === "Sales Invoice" && !flt(d.credit)) { } else if (d.reference_type==="Sales Invoice" && !flt(d.credit)) {
this.get_outstanding("Sales Invoice", d.reference_name, doc.company, d); this.get_outstanding('Sales Invoice', d.reference_name, doc.company, d);
} else if (d.reference_type === "Journal Entry" && !flt(d.credit) && !flt(d.debit)) { } else if (d.reference_type==="Journal Entry" && !flt(d.credit) && !flt(d.debit)) {
this.get_outstanding("Journal Entry", d.reference_name, doc.company, d); this.get_outstanding('Journal Entry', d.reference_name, doc.company, d);
} }
} }
} }
get_outstanding(doctype, docname, company, child) { get_outstanding(doctype, docname, company, child) {
var args = { var args = {
doctype: doctype, "doctype": doctype,
docname: docname, "docname": docname,
party: child.party, "party": child.party,
account: child.account, "account": child.account,
account_currency: child.account_currency, "account_currency": child.account_currency,
company: company, "company": company
}; }
return frappe.call({ return frappe.call({
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_outstanding", method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_outstanding",
args: { args: args }, args: { args: args},
callback: function (r) { callback: function(r) {
if (r.message) { if(r.message) {
$.each(r.message, function (field, value) { $.each(r.message, function(field, value) {
frappe.model.set_value(child.doctype, child.name, field, value); frappe.model.set_value(child.doctype, child.name, field, value);
}); })
} }
}, }
}); });
} }
accounts_add(doc, cdt, cdn) { accounts_add(doc, cdt, cdn) {
var row = frappe.get_doc(cdt, cdn); var row = frappe.get_doc(cdt, cdn);
$.each(doc.accounts, function (i, d) { $.each(doc.accounts, function(i, d) {
if (d.account && d.party && d.party_type) { if(d.account && d.party && d.party_type) {
row.account = d.account; row.account = d.account;
row.party = d.party; row.party = d.party;
row.party_type = d.party_type; row.party_type = d.party_type;
@@ -368,8 +343,8 @@ erpnext.accounts.JournalEntry = class JournalEntry extends frappe.ui.form.Contro
}); });
// set difference // set difference
if (doc.difference) { if(doc.difference) {
if (doc.difference > 0) { if(doc.difference > 0) {
row.credit_in_account_currency = doc.difference; row.credit_in_account_currency = doc.difference;
row.credit = doc.difference; row.credit = doc.difference;
} else { } else {
@@ -379,141 +354,132 @@ erpnext.accounts.JournalEntry = class JournalEntry extends frappe.ui.form.Contro
} }
cur_frm.cscript.update_totals(doc); cur_frm.cscript.update_totals(doc);
erpnext.accounts.dimensions.copy_dimension_from_first_row(this.frm, cdt, cdn, "accounts"); erpnext.accounts.dimensions.copy_dimension_from_first_row(this.frm, cdt, cdn, 'accounts');
} }
}; };
cur_frm.script_manager.make(erpnext.accounts.JournalEntry); cur_frm.script_manager.make(erpnext.accounts.JournalEntry);
cur_frm.cscript.update_totals = function (doc) { cur_frm.cscript.update_totals = function(doc) {
var td = 0.0; var td=0.0; var tc =0.0;
var tc = 0.0;
var accounts = doc.accounts || []; var accounts = doc.accounts || [];
for (var i in accounts) { for(var i in accounts) {
td += flt(accounts[i].debit, precision("debit", accounts[i])); td += flt(accounts[i].debit, precision("debit", accounts[i]));
tc += flt(accounts[i].credit, precision("credit", accounts[i])); tc += flt(accounts[i].credit, precision("credit", accounts[i]));
} }
var doc = locals[doc.doctype][doc.name]; var doc = locals[doc.doctype][doc.name];
doc.total_debit = td; doc.total_debit = td;
doc.total_credit = tc; doc.total_credit = tc;
doc.difference = flt(td - tc, precision("difference")); doc.difference = flt((td - tc), precision("difference"));
refresh_many(["total_debit", "total_credit", "difference"]); refresh_many(['total_debit','total_credit','difference']);
}; }
cur_frm.cscript.get_balance = function (doc, dt, dn) { cur_frm.cscript.get_balance = function(doc,dt,dn) {
cur_frm.cscript.update_totals(doc); cur_frm.cscript.update_totals(doc);
cur_frm.call("get_balance", null, () => { cur_frm.call('get_balance', null, () => { cur_frm.refresh(); });
cur_frm.refresh(); }
});
};
cur_frm.cscript.validate = function (doc, cdt, cdn) { cur_frm.cscript.validate = function(doc,cdt,cdn) {
cur_frm.cscript.update_totals(doc); cur_frm.cscript.update_totals(doc);
}; }
frappe.ui.form.on("Journal Entry Account", { frappe.ui.form.on("Journal Entry Account", {
party: function (frm, cdt, cdn) { party: function(frm, cdt, cdn) {
var d = frappe.get_doc(cdt, cdn); var d = frappe.get_doc(cdt, cdn);
if (!d.account && d.party_type && d.party) { if(!d.account && d.party_type && d.party) {
if (!frm.doc.company) frappe.throw(__("Please select Company")); if(!frm.doc.company) frappe.throw(__("Please select Company"));
return frm.call({ return frm.call({
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_party_account_and_currency", method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_party_account_and_balance",
child: d, child: d,
args: { args: {
company: frm.doc.company, company: frm.doc.company,
party_type: d.party_type, party_type: d.party_type,
party: d.party, party: d.party,
}, cost_center: d.cost_center
}
}); });
} }
}, },
cost_center: function (frm, dt, dn) { cost_center: function(frm, dt, dn) {
erpnext.journal_entry.set_account_details(frm, dt, dn); erpnext.journal_entry.set_account_balance(frm, dt, dn);
}, },
account: function (frm, dt, dn) { account: function(frm, dt, dn) {
erpnext.journal_entry.set_account_details(frm, dt, dn); erpnext.journal_entry.set_account_balance(frm, dt, dn);
}, },
debit_in_account_currency: function (frm, cdt, cdn) { debit_in_account_currency: function(frm, cdt, cdn) {
erpnext.journal_entry.set_exchange_rate(frm, cdt, cdn); erpnext.journal_entry.set_exchange_rate(frm, cdt, cdn);
}, },
credit_in_account_currency: function (frm, cdt, cdn) { credit_in_account_currency: function(frm, cdt, cdn) {
erpnext.journal_entry.set_exchange_rate(frm, cdt, cdn); erpnext.journal_entry.set_exchange_rate(frm, cdt, cdn);
}, },
debit: function (frm, dt, dn) { debit: function(frm, dt, dn) {
cur_frm.cscript.update_totals(frm.doc); cur_frm.cscript.update_totals(frm.doc);
}, },
credit: function (frm, dt, dn) { credit: function(frm, dt, dn) {
cur_frm.cscript.update_totals(frm.doc); cur_frm.cscript.update_totals(frm.doc);
}, },
exchange_rate: function (frm, cdt, cdn) { exchange_rate: function(frm, cdt, cdn) {
var company_currency = frappe.get_doc(":Company", frm.doc.company).default_currency; var company_currency = frappe.get_doc(":Company", frm.doc.company).default_currency;
var row = locals[cdt][cdn]; var row = locals[cdt][cdn];
if (row.account_currency == company_currency || !frm.doc.multi_currency) { if(row.account_currency == company_currency || !frm.doc.multi_currency) {
frappe.model.set_value(cdt, cdn, "exchange_rate", 1); frappe.model.set_value(cdt, cdn, "exchange_rate", 1);
} }
erpnext.journal_entry.set_debit_credit_in_company_currency(frm, cdt, cdn); erpnext.journal_entry.set_debit_credit_in_company_currency(frm, cdt, cdn);
}, }
}); })
frappe.ui.form.on("Journal Entry Account", "accounts_remove", function (frm) { frappe.ui.form.on("Journal Entry Account", "accounts_remove", function(frm) {
cur_frm.cscript.update_totals(frm.doc); cur_frm.cscript.update_totals(frm.doc);
}); });
$.extend(erpnext.journal_entry, { $.extend(erpnext.journal_entry, {
toggle_fields_based_on_currency: function (frm) { toggle_fields_based_on_currency: function(frm) {
var fields = ["currency_section", "account_currency", "exchange_rate", "debit", "credit"]; var fields = ["currency_section", "account_currency", "exchange_rate", "debit", "credit"];
var grid = frm.get_field("accounts").grid; var grid = frm.get_field("accounts").grid;
if (grid) grid.set_column_disp(fields, frm.doc.multi_currency); if(grid) grid.set_column_disp(fields, frm.doc.multi_currency);
// dynamic label // dynamic label
var field_label_map = { var field_label_map = {
debit_in_account_currency: "Debit", "debit_in_account_currency": "Debit",
credit_in_account_currency: "Credit", "credit_in_account_currency": "Credit"
}; };
$.each(field_label_map, function (fieldname, label) { $.each(field_label_map, function (fieldname, label) {
frm.fields_dict.accounts.grid.update_docfield_property( frm.fields_dict.accounts.grid.update_docfield_property(
fieldname, fieldname,
"label", 'label',
frm.doc.multi_currency ? label + " in Account Currency" : label frm.doc.multi_currency ? (label + " in Account Currency") : label
); );
}); })
}, },
set_debit_credit_in_company_currency: function (frm, cdt, cdn) { set_debit_credit_in_company_currency: function(frm, cdt, cdn) {
var row = locals[cdt][cdn]; var row = locals[cdt][cdn];
frappe.model.set_value( frappe.model.set_value(cdt, cdn, "debit",
cdt, flt(flt(row.debit_in_account_currency)*row.exchange_rate, precision("debit", row)));
cdn,
"debit",
flt(flt(row.debit_in_account_currency) * row.exchange_rate, precision("debit", row))
);
frappe.model.set_value( frappe.model.set_value(cdt, cdn, "credit",
cdt, flt(flt(row.credit_in_account_currency)*row.exchange_rate, precision("credit", row)));
cdn,
"credit",
flt(flt(row.credit_in_account_currency) * row.exchange_rate, precision("credit", row))
);
cur_frm.cscript.update_totals(frm.doc); cur_frm.cscript.update_totals(frm.doc);
}, },
set_exchange_rate: function (frm, cdt, cdn) { set_exchange_rate: function(frm, cdt, cdn) {
var company_currency = frappe.get_doc(":Company", frm.doc.company).default_currency; var company_currency = frappe.get_doc(":Company", frm.doc.company).default_currency;
var row = locals[cdt][cdn]; var row = locals[cdt][cdn];
if (row.account_currency == company_currency || !frm.doc.multi_currency) { if(row.account_currency == company_currency || !frm.doc.multi_currency) {
row.exchange_rate = 1; row.exchange_rate = 1;
erpnext.journal_entry.set_debit_credit_in_company_currency(frm, cdt, cdn); erpnext.journal_entry.set_debit_credit_in_company_currency(frm, cdt, cdn);
} else if (!row.exchange_rate || row.exchange_rate == 1 || row.account_type == "Bank") { } else if (!row.exchange_rate || row.exchange_rate == 1 || row.account_type == "Bank") {
@@ -528,70 +494,50 @@ $.extend(erpnext.journal_entry, {
reference_name: cstr(row.reference_name), reference_name: cstr(row.reference_name),
debit: flt(row.debit_in_account_currency), debit: flt(row.debit_in_account_currency),
credit: flt(row.credit_in_account_currency), credit: flt(row.credit_in_account_currency),
exchange_rate: row.exchange_rate, exchange_rate: row.exchange_rate
}, },
callback: function (r) { callback: function(r) {
if (r.message) { if(r.message) {
row.exchange_rate = r.message; row.exchange_rate = r.message;
erpnext.journal_entry.set_debit_credit_in_company_currency(frm, cdt, cdn); erpnext.journal_entry.set_debit_credit_in_company_currency(frm, cdt, cdn);
} }
}, }
}); })
} else { } else {
erpnext.journal_entry.set_debit_credit_in_company_currency(frm, cdt, cdn); erpnext.journal_entry.set_debit_credit_in_company_currency(frm, cdt, cdn);
} }
refresh_field("exchange_rate", cdn, "accounts"); refresh_field("exchange_rate", cdn, "accounts");
}, },
quick_entry: function (frm) { quick_entry: function(frm) {
var naming_series_options = frm.fields_dict.naming_series.df.options; var naming_series_options = frm.fields_dict.naming_series.df.options;
var naming_series_default = var naming_series_default = frm.fields_dict.naming_series.df.default || naming_series_options.split("\n")[0];
frm.fields_dict.naming_series.df.default || naming_series_options.split("\n")[0];
var dialog = new frappe.ui.Dialog({ var dialog = new frappe.ui.Dialog({
title: __("Quick Journal Entry"), title: __("Quick Journal Entry"),
fields: [ fields: [
{ fieldtype: "Currency", fieldname: "debit", label: __("Amount"), reqd: 1 }, {fieldtype: "Currency", fieldname: "debit", label: __("Amount"), reqd: 1},
{ {fieldtype: "Link", fieldname: "debit_account", label: __("Debit Account"), reqd: 1,
fieldtype: "Link",
fieldname: "debit_account",
label: __("Debit Account"),
reqd: 1,
options: "Account", options: "Account",
get_query: function () { get_query: function() {
return erpnext.journal_entry.account_query(frm); return erpnext.journal_entry.account_query(frm);
}, }
}, },
{ {fieldtype: "Link", fieldname: "credit_account", label: __("Credit Account"), reqd: 1,
fieldtype: "Link",
fieldname: "credit_account",
label: __("Credit Account"),
reqd: 1,
options: "Account", options: "Account",
get_query: function () { get_query: function() {
return erpnext.journal_entry.account_query(frm); return erpnext.journal_entry.account_query(frm);
}, }
}, },
{ {fieldtype: "Date", fieldname: "posting_date", label: __("Date"), reqd: 1,
fieldtype: "Date", default: frm.doc.posting_date},
fieldname: "posting_date", {fieldtype: "Small Text", fieldname: "user_remark", label: __("User Remark")},
label: __("Date"), {fieldtype: "Select", fieldname: "naming_series", label: __("Series"), reqd: 1,
reqd: 1, options: naming_series_options, default: naming_series_default},
default: frm.doc.posting_date, ]
},
{ fieldtype: "Small Text", fieldname: "user_remark", label: __("User Remark") },
{
fieldtype: "Select",
fieldname: "naming_series",
label: __("Series"),
reqd: 1,
options: naming_series_options,
default: naming_series_default,
},
],
}); });
dialog.set_primary_action(__("Save"), function () { dialog.set_primary_action(__("Save"), function() {
var btn = this; var btn = this;
var values = dialog.get_values(); var values = dialog.get_values();
@@ -608,21 +554,11 @@ $.extend(erpnext.journal_entry, {
var debit_row = frm.fields_dict.accounts.grid.add_new_row(); var debit_row = frm.fields_dict.accounts.grid.add_new_row();
frappe.model.set_value(debit_row.doctype, debit_row.name, "account", values.debit_account); frappe.model.set_value(debit_row.doctype, debit_row.name, "account", values.debit_account);
frappe.model.set_value( frappe.model.set_value(debit_row.doctype, debit_row.name, "debit_in_account_currency", values.debit);
debit_row.doctype,
debit_row.name,
"debit_in_account_currency",
values.debit
);
var credit_row = frm.fields_dict.accounts.grid.add_new_row(); var credit_row = frm.fields_dict.accounts.grid.add_new_row();
frappe.model.set_value(credit_row.doctype, credit_row.name, "account", values.credit_account); frappe.model.set_value(credit_row.doctype, credit_row.name, "account", values.credit_account);
frappe.model.set_value( frappe.model.set_value(credit_row.doctype, credit_row.name, "credit_in_account_currency", values.debit);
credit_row.doctype,
credit_row.name,
"credit_in_account_currency",
values.debit
);
frm.save(); frm.save();
@@ -632,36 +568,36 @@ $.extend(erpnext.journal_entry, {
dialog.show(); dialog.show();
}, },
account_query: function (frm) { account_query: function(frm) {
var filters = { var filters = {
company: frm.doc.company, company: frm.doc.company,
is_group: 0, is_group: 0
}; };
if (!frm.doc.multi_currency) { if(!frm.doc.multi_currency) {
$.extend(filters, { $.extend(filters, {
account_currency: frappe.get_doc(":Company", frm.doc.company).default_currency, account_currency: frappe.get_doc(":Company", frm.doc.company).default_currency
}); });
} }
return { filters: filters }; return { filters: filters };
}, },
reverse_journal_entry: function () { reverse_journal_entry: function() {
frappe.model.open_mapped_doc({ frappe.model.open_mapped_doc({
method: "erpnext.accounts.doctype.journal_entry.journal_entry.make_reverse_journal_entry", method: "erpnext.accounts.doctype.journal_entry.journal_entry.make_reverse_journal_entry",
frm: cur_frm, frm: cur_frm
}); })
}, },
}); });
$.extend(erpnext.journal_entry, { $.extend(erpnext.journal_entry, {
set_account_details: function (frm, dt, dn) { set_account_balance: function(frm, dt, dn) {
var d = locals[dt][dn]; var d = locals[dt][dn];
if (d.account) { if(d.account) {
if (!frm.doc.company) frappe.throw(__("Please select Company first")); if(!frm.doc.company) frappe.throw(__("Please select Company first"));
if (!frm.doc.posting_date) frappe.throw(__("Please select Posting Date first")); if(!frm.doc.posting_date) frappe.throw(__("Please select Posting Date first"));
return frappe.call({ return frappe.call({
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_account_details_and_party_type", method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_account_balance_and_party_type",
args: { args: {
account: d.account, account: d.account,
date: frm.doc.posting_date, date: frm.doc.posting_date,
@@ -669,14 +605,15 @@ $.extend(erpnext.journal_entry, {
debit: flt(d.debit_in_account_currency), debit: flt(d.debit_in_account_currency),
credit: flt(d.credit_in_account_currency), credit: flt(d.credit_in_account_currency),
exchange_rate: d.exchange_rate, exchange_rate: d.exchange_rate,
cost_center: d.cost_center
}, },
callback: function (r) { callback: function(r) {
if (r.message) { if(r.message) {
$.extend(d, r.message); $.extend(d, r.message);
erpnext.journal_entry.set_debit_credit_in_company_currency(frm, dt, dn); erpnext.journal_entry.set_debit_credit_in_company_currency(frm, dt, dn);
refresh_field("accounts"); refresh_field('accounts');
} }
}, }
}); });
} }
}, },

View File

@@ -548,16 +548,8 @@
"icon": "fa fa-file-text", "icon": "fa fa-file-text",
"idx": 176, "idx": 176,
"is_submittable": 1, "is_submittable": 1,
"links": [ "links": [],
{ "modified": "2023-08-10 14:32:22.366895",
"is_child_table": 1,
"link_doctype": "Bank Transaction Payments",
"link_fieldname": "payment_entry",
"parent_doctype": "Bank Transaction",
"table_fieldname": "payment_entries"
}
],
"modified": "2023-11-23 12:11:04.128015",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Journal Entry", "name": "Journal Entry",

View File

@@ -68,6 +68,7 @@ class JournalEntry(AccountsController):
self.set_print_format_fields() self.set_print_format_fields()
self.validate_credit_debit_note() self.validate_credit_debit_note()
self.validate_empty_accounts_table() self.validate_empty_accounts_table()
self.set_account_and_party_balance()
self.validate_inter_company_accounts() self.validate_inter_company_accounts()
self.validate_depr_entry_voucher_type() self.validate_depr_entry_voucher_type()
@@ -77,20 +78,6 @@ class JournalEntry(AccountsController):
if not self.title: if not self.title:
self.title = self.get_title() self.title = self.get_title()
def submit(self):
if len(self.accounts) > 100:
msgprint(_("The task has been enqueued as a background job."), alert=True)
self.queue_action("submit", timeout=4600)
else:
return self._submit()
def cancel(self):
if len(self.accounts) > 100:
msgprint(_("The task has been enqueued as a background job."), alert=True)
self.queue_action("cancel", timeout=4600)
else:
return self._cancel()
def on_submit(self): def on_submit(self):
self.validate_cheque_info() self.validate_cheque_info()
self.check_credit_limit() self.check_credit_limit()
@@ -111,8 +98,6 @@ class JournalEntry(AccountsController):
"Repost Payment Ledger Items", "Repost Payment Ledger Items",
"Repost Accounting Ledger", "Repost Accounting Ledger",
"Repost Accounting Ledger Items", "Repost Accounting Ledger Items",
"Unreconcile Payment",
"Unreconcile Payment Entries",
) )
self.make_gl_entries(1) self.make_gl_entries(1)
self.update_advance_paid() self.update_advance_paid()
@@ -474,28 +459,17 @@ class JournalEntry(AccountsController):
elif d.party_type == "Supplier" and flt(d.credit) > 0: elif d.party_type == "Supplier" and flt(d.credit) > 0:
frappe.throw(_("Row {0}: Advance against Supplier must be debit").format(d.idx)) frappe.throw(_("Row {0}: Advance against Supplier must be debit").format(d.idx))
def system_generated_gain_loss(self):
return (
self.voucher_type == "Exchange Gain Or Loss"
and self.multi_currency
and self.is_system_generated
)
def validate_against_jv(self): def validate_against_jv(self):
for d in self.get("accounts"): for d in self.get("accounts"):
if d.reference_type == "Journal Entry": if d.reference_type == "Journal Entry":
account_root_type = frappe.get_cached_value("Account", d.account, "root_type") account_root_type = frappe.db.get_value("Account", d.account, "root_type")
if account_root_type == "Asset" and flt(d.debit) > 0 and not self.system_generated_gain_loss(): if account_root_type == "Asset" and flt(d.debit) > 0:
frappe.throw( frappe.throw(
_( _(
"Row #{0}: For {1}, you can select reference document only if account gets credited" "Row #{0}: For {1}, you can select reference document only if account gets credited"
).format(d.idx, d.account) ).format(d.idx, d.account)
) )
elif ( elif account_root_type == "Liability" and flt(d.credit) > 0:
account_root_type == "Liability"
and flt(d.credit) > 0
and not self.system_generated_gain_loss()
):
frappe.throw( frappe.throw(
_( _(
"Row #{0}: For {1}, you can select reference document only if account gets debited" "Row #{0}: For {1}, you can select reference document only if account gets debited"
@@ -522,12 +496,12 @@ class JournalEntry(AccountsController):
).format(d.reference_name, d.account) ).format(d.reference_name, d.account)
) )
else: else:
dr_or_cr = "debit" if flt(d.credit) > 0 else "credit" dr_or_cr = "debit" if d.credit > 0 else "credit"
valid = False valid = False
for jvd in against_entries: for jvd in against_entries:
if flt(jvd[dr_or_cr]) > 0: if flt(jvd[dr_or_cr]) > 0:
valid = True valid = True
if not valid and not self.system_generated_gain_loss(): if not valid:
frappe.throw( frappe.throw(
_("Against Journal Entry {0} does not have any unmatched {1} entry").format( _("Against Journal Entry {0} does not have any unmatched {1} entry").format(
d.reference_name, dr_or_cr d.reference_name, dr_or_cr
@@ -1075,6 +1049,21 @@ class JournalEntry(AccountsController):
if not self.get("accounts"): if not self.get("accounts"):
frappe.throw(_("Accounts table cannot be blank.")) frappe.throw(_("Accounts table cannot be blank."))
def set_account_and_party_balance(self):
account_balance = {}
party_balance = {}
for d in self.get("accounts"):
if d.account not in account_balance:
account_balance[d.account] = get_balance_on(account=d.account, date=self.posting_date)
if (d.party_type, d.party) not in party_balance:
party_balance[(d.party_type, d.party)] = get_balance_on(
party_type=d.party_type, party=d.party, date=self.posting_date, company=self.company
)
d.account_balance = account_balance[d.account]
d.party_balance = party_balance[(d.party_type, d.party)]
@frappe.whitelist() @frappe.whitelist()
def get_default_bank_cash_account(company, account_type=None, mode_of_payment=None, account=None): def get_default_bank_cash_account(company, account_type=None, mode_of_payment=None, account=None):
@@ -1240,6 +1229,8 @@ def get_payment_entry(ref_doc, args):
"account_type": frappe.db.get_value("Account", args.get("party_account"), "account_type"), "account_type": frappe.db.get_value("Account", args.get("party_account"), "account_type"),
"account_currency": args.get("party_account_currency") "account_currency": args.get("party_account_currency")
or get_account_currency(args.get("party_account")), or get_account_currency(args.get("party_account")),
"balance": get_balance_on(args.get("party_account")),
"party_balance": get_balance_on(party=args.get("party"), party_type=args.get("party_type")),
"exchange_rate": exchange_rate, "exchange_rate": exchange_rate,
args.get("amount_field_party"): args.get("amount"), args.get("amount_field_party"): args.get("amount"),
"is_advance": args.get("is_advance"), "is_advance": args.get("is_advance"),
@@ -1387,23 +1378,30 @@ def get_outstanding(args):
@frappe.whitelist() @frappe.whitelist()
def get_party_account_and_currency(company, party_type, party): def get_party_account_and_balance(company, party_type, party, cost_center=None):
if not frappe.has_permission("Account"): if not frappe.has_permission("Account"):
frappe.msgprint(_("No Permission"), raise_exception=1) frappe.msgprint(_("No Permission"), raise_exception=1)
account = get_party_account(party_type, party, company) account = get_party_account(party_type, party, company)
account_balance = get_balance_on(account=account, cost_center=cost_center)
party_balance = get_balance_on(
party_type=party_type, party=party, company=company, cost_center=cost_center
)
return { return {
"account": account, "account": account,
"account_currency": frappe.get_cached_value("Account", account, "account_currency"), "balance": account_balance,
"party_balance": party_balance,
"account_currency": frappe.db.get_value("Account", account, "account_currency"),
} }
@frappe.whitelist() @frappe.whitelist()
def get_account_details_and_party_type( def get_account_balance_and_party_type(
account, date, company, debit=None, credit=None, exchange_rate=None account, date, company, debit=None, credit=None, exchange_rate=None, cost_center=None
): ):
"""Returns dict of account details and party type to be set in Journal Entry on selection of account.""" """Returns dict of account balance and party type to be set in Journal Entry on selection of account."""
if not frappe.has_permission("Account"): if not frappe.has_permission("Account"):
frappe.msgprint(_("No Permission"), raise_exception=1) frappe.msgprint(_("No Permission"), raise_exception=1)
@@ -1423,6 +1421,7 @@ def get_account_details_and_party_type(
party_type = "" party_type = ""
grid_values = { grid_values = {
"balance": get_balance_on(account, date, cost_center=cost_center),
"party_type": party_type, "party_type": party_type,
"account_type": account_details.account_type, "account_type": account_details.account_type,
"account_currency": account_details.account_currency or company_currency, "account_currency": account_details.account_currency or company_currency,

View File

@@ -1,12 +1,12 @@
frappe.listview_settings["Journal Entry"] = { frappe.listview_settings['Journal Entry'] = {
add_fields: ["voucher_type", "posting_date", "total_debit", "company", "user_remark"], add_fields: ["voucher_type", "posting_date", "total_debit", "company", "user_remark"],
get_indicator: function (doc) { get_indicator: function(doc) {
if (doc.docstatus == 0) { if(doc.docstatus==0) {
return [__("Draft", "red", "docstatus,=,0")]; return [__("Draft", "red", "docstatus,=,0")]
} else if (doc.docstatus == 2) { } else if(doc.docstatus==2) {
return [__("Cancelled", "grey", "docstatus,=,2")]; return [__("Cancelled", "grey", "docstatus,=,2")]
} else { } else {
return [__(doc.voucher_type), "blue", "voucher_type,=," + doc.voucher_type]; return [__(doc.voucher_type), "blue", "voucher_type,=," + doc.voucher_type]
} }
}, }
}; };

View File

@@ -81,6 +81,7 @@
}, },
{ {
"account": "Sales - _TC", "account": "Sales - _TC",
"cost_center": "_Test Cost Center - _TC",
"credit_in_account_currency": 400.0, "credit_in_account_currency": 400.0,
"debit_in_account_currency": 0.0, "debit_in_account_currency": 0.0,
"doctype": "Journal Entry Account", "doctype": "Journal Entry Account",

View File

@@ -9,10 +9,12 @@
"field_order": [ "field_order": [
"account", "account",
"account_type", "account_type",
"balance",
"col_break1", "col_break1",
"bank_account", "bank_account",
"party_type", "party_type",
"party", "party",
"party_balance",
"accounting_dimensions_section", "accounting_dimensions_section",
"cost_center", "cost_center",
"dimension_col_break", "dimension_col_break",
@@ -61,6 +63,17 @@
"label": "Account Type", "label": "Account Type",
"print_hide": 1 "print_hide": 1
}, },
{
"fieldname": "balance",
"fieldtype": "Currency",
"label": "Account Balance",
"no_copy": 1,
"oldfieldname": "balance",
"oldfieldtype": "Data",
"options": "account_currency",
"print_hide": 1,
"read_only": 1
},
{ {
"default": ":Company", "default": ":Company",
"description": "If Income or Expense", "description": "If Income or Expense",
@@ -94,6 +107,14 @@
"label": "Party", "label": "Party",
"options": "party_type" "options": "party_type"
}, },
{
"fieldname": "party_balance",
"fieldtype": "Currency",
"label": "Party Balance",
"options": "account_currency",
"print_hide": 1,
"read_only": 1
},
{ {
"fieldname": "currency_section", "fieldname": "currency_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
@@ -182,8 +203,7 @@
"fieldtype": "Select", "fieldtype": "Select",
"label": "Reference Type", "label": "Reference Type",
"no_copy": 1, "no_copy": 1,
"options": "\nSales Invoice\nPurchase Invoice\nJournal Entry\nSales Order\nPurchase Order\nExpense Claim\nAsset\nLoan\nPayroll Entry\nEmployee Advance\nExchange Rate Revaluation\nInvoice Discounting\nFees\nFull and Final Statement\nPayment Entry", "options": "\nSales Invoice\nPurchase Invoice\nJournal Entry\nSales Order\nPurchase Order\nExpense Claim\nAsset\nLoan\nPayroll Entry\nEmployee Advance\nExchange Rate Revaluation\nInvoice Discounting\nFees\nFull and Final Statement\nPayment Entry"
"search_index": 1
}, },
{ {
"fieldname": "reference_name", "fieldname": "reference_name",
@@ -191,8 +211,7 @@
"in_list_view": 1, "in_list_view": 1,
"label": "Reference Name", "label": "Reference Name",
"no_copy": 1, "no_copy": 1,
"options": "reference_type", "options": "reference_type"
"search_index": 1
}, },
{ {
"depends_on": "eval:doc.reference_type&&!in_list(doc.reference_type, ['Expense Claim', 'Asset', 'Employee Loan', 'Employee Advance'])", "depends_on": "eval:doc.reference_type&&!in_list(doc.reference_type, ['Expense Claim', 'Asset', 'Employee Loan', 'Employee Advance'])",
@@ -259,14 +278,13 @@
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 1, "hidden": 1,
"label": "Reference Detail No", "label": "Reference Detail No",
"no_copy": 1, "no_copy": 1
"search_index": 1
} }
], ],
"idx": 1, "idx": 1,
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2023-11-23 11:44:25.841187", "modified": "2023-06-16 14:11:13.507807",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Journal Entry Account", "name": "Journal Entry Account",

View File

@@ -2,82 +2,78 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Journal Entry Template", { frappe.ui.form.on("Journal Entry Template", {
onload: function (frm) { onload: function(frm) {
if (frm.is_new()) { if(frm.is_new()) {
frappe.call({ frappe.call({
type: "GET", type: "GET",
method: "erpnext.accounts.doctype.journal_entry_template.journal_entry_template.get_naming_series", method: "erpnext.accounts.doctype.journal_entry_template.journal_entry_template.get_naming_series",
callback: function (r) { callback: function(r){
if (r.message) { if(r.message) {
frm.set_df_property("naming_series", "options", r.message.split("\n")); frm.set_df_property("naming_series", "options", r.message.split("\n"));
frm.set_value("naming_series", r.message.split("\n")[0]); frm.set_value("naming_series", r.message.split("\n")[0]);
frm.refresh_field("naming_series"); frm.refresh_field("naming_series");
} }
}, }
}); });
} }
}, },
refresh: function (frm) { refresh: function(frm) {
frappe.model.set_default_values(frm.doc); frappe.model.set_default_values(frm.doc);
frm.set_query("account", "accounts", function () { frm.set_query("account" ,"accounts", function(){
var filters = { var filters = {
company: frm.doc.company, company: frm.doc.company,
is_group: 0, is_group: 0
}; };
if (!frm.doc.multi_currency) { if(!frm.doc.multi_currency) {
$.extend(filters, { $.extend(filters, {
account_currency: frappe.get_doc(":Company", frm.doc.company).default_currency, account_currency: frappe.get_doc(":Company", frm.doc.company).default_currency
}); });
} }
return { filters: filters }; return { filters: filters };
}); });
}, },
voucher_type: function (frm) { voucher_type: function(frm) {
var add_accounts = function (doc, r) { var add_accounts = function(doc, r) {
$.each(r, function (i, d) { $.each(r, function(i, d) {
var row = frappe.model.add_child(doc, "Journal Entry Template Account", "accounts"); var row = frappe.model.add_child(doc, "Journal Entry Template Account", "accounts");
row.account = d.account; row.account = d.account;
}); });
refresh_field("accounts"); refresh_field("accounts");
}; };
if (!frm.doc.company) return; if(!frm.doc.company) return;
frm.trigger("clear_child"); frm.trigger("clear_child");
switch (frm.doc.voucher_type) { switch(frm.doc.voucher_type){
case "Bank Entry": case "Bank Entry":
case "Cash Entry": case "Cash Entry":
frappe.call({ frappe.call({
type: "GET", type: "GET",
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_default_bank_cash_account", method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_default_bank_cash_account",
args: { args: {
account_type: "account_type": (frm.doc.voucher_type=="Bank Entry" ?
frm.doc.voucher_type == "Bank Entry" "Bank" : (frm.doc.voucher_type=="Cash Entry" ? "Cash" : null)),
? "Bank" "company": frm.doc.company
: frm.doc.voucher_type == "Cash Entry"
? "Cash"
: null,
company: frm.doc.company,
}, },
callback: function (r) { callback: function(r) {
if (r.message) { if(r.message) {
// If default company bank account not set // If default company bank account not set
if (!$.isEmptyObject(r.message)) { if(!$.isEmptyObject(r.message)){
add_accounts(frm.doc, [r.message]); add_accounts(frm.doc, [r.message]);
} }
} }
}, }
}); });
break; break;
default: default:
frm.trigger("clear_child"); frm.trigger("clear_child");
} }
}, },
clear_child: function (frm) { clear_child: function(frm){
frappe.model.clear_table(frm.doc, "accounts"); frappe.model.clear_table(frm.doc, "accounts");
frm.refresh_field("accounts"); frm.refresh_field("accounts");
}, }
}); });

View File

@@ -1,9 +1,9 @@
// Copyright (c) 2021, Wahni Green Technologies Pvt. Ltd. and contributors // Copyright (c) 2021, Wahni Green Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Ledger Merge", { frappe.ui.form.on('Ledger Merge', {
setup: function (frm) { setup: function(frm) {
frappe.realtime.on("ledger_merge_refresh", ({ ledger_merge }) => { frappe.realtime.on('ledger_merge_refresh', ({ ledger_merge }) => {
if (ledger_merge !== frm.doc.name) return; if (ledger_merge !== frm.doc.name) return;
frappe.model.clear_doc(frm.doc.doctype, frm.doc.name); frappe.model.clear_doc(frm.doc.doctype, frm.doc.name);
frappe.model.with_doc(frm.doc.doctype, frm.doc.name).then(() => { frappe.model.with_doc(frm.doc.doctype, frm.doc.name).then(() => {
@@ -11,29 +11,29 @@ frappe.ui.form.on("Ledger Merge", {
}); });
}); });
frappe.realtime.on("ledger_merge_progress", (data) => { frappe.realtime.on('ledger_merge_progress', data => {
if (data.ledger_merge !== frm.doc.name) return; if (data.ledger_merge !== frm.doc.name) return;
let message = __("Merging {0} of {1}", [data.current, data.total]); let message = __('Merging {0} of {1}', [data.current, data.total]);
let percent = Math.floor((data.current * 100) / data.total); let percent = Math.floor((data.current * 100) / data.total);
frm.dashboard.show_progress(__("Merge Progress"), percent, message); frm.dashboard.show_progress(__('Merge Progress'), percent, message);
frm.page.set_indicator(__("In Progress"), "orange"); frm.page.set_indicator(__('In Progress'), 'orange');
}); });
frm.set_query("account", function (doc) { frm.set_query("account", function(doc) {
if (!doc.company) frappe.throw(__("Please set Company")); if (!doc.company) frappe.throw(__('Please set Company'));
if (!doc.root_type) frappe.throw(__("Please set Root Type")); if (!doc.root_type) frappe.throw(__('Please set Root Type'));
return { return {
filters: { filters: {
root_type: doc.root_type, root_type: doc.root_type,
company: doc.company, company: doc.company
}, }
}; };
}); });
frm.set_query("account", "merge_accounts", function (doc) { frm.set_query('account', 'merge_accounts', function(doc) {
if (!doc.company) frappe.throw(__("Please set Company")); if (!doc.company) frappe.throw(__('Please set Company'));
if (!doc.root_type) frappe.throw(__("Please set Root Type")); if (!doc.root_type) frappe.throw(__('Please set Root Type'));
if (!doc.account) frappe.throw(__("Please set Account")); if (!doc.account) frappe.throw(__('Please set Account'));
let acc = [doc.account]; let acc = [doc.account];
frm.doc.merge_accounts.forEach((row) => { frm.doc.merge_accounts.forEach((row) => {
acc.push(row.account); acc.push(row.account);
@@ -43,86 +43,86 @@ frappe.ui.form.on("Ledger Merge", {
is_group: doc.is_group, is_group: doc.is_group,
root_type: doc.root_type, root_type: doc.root_type,
name: ["not in", acc], name: ["not in", acc],
company: doc.company, company: doc.company
}, }
}; };
}); });
}, },
refresh: function (frm) { refresh: function(frm) {
frm.page.hide_icon_group(); frm.page.hide_icon_group();
frm.trigger("set_merge_status"); frm.trigger('set_merge_status');
frm.trigger("update_primary_action"); frm.trigger('update_primary_action');
}, },
after_save: function (frm) { after_save: function(frm) {
setTimeout(() => { setTimeout(() => {
frm.trigger("update_primary_action"); frm.trigger('update_primary_action');
}, 500); }, 500);
}, },
update_primary_action: function (frm) { update_primary_action: function(frm) {
if (frm.is_dirty()) { if (frm.is_dirty()) {
frm.enable_save(); frm.enable_save();
return; return;
} }
frm.disable_save(); frm.disable_save();
if (frm.doc.status !== "Success") { if (frm.doc.status !== 'Success') {
if (!frm.is_new()) { if (!frm.is_new()) {
let label = frm.doc.status === "Pending" ? __("Start Merge") : __("Retry"); let label = frm.doc.status === 'Pending' ? __('Start Merge') : __('Retry');
frm.page.set_primary_action(label, () => frm.events.start_merge(frm)); frm.page.set_primary_action(label, () => frm.events.start_merge(frm));
} else { } else {
frm.page.set_primary_action(__("Save"), () => frm.save()); frm.page.set_primary_action(__('Save'), () => frm.save());
} }
} }
}, },
start_merge: function (frm) { start_merge: function(frm) {
frm.call({ frm.call({
method: "form_start_merge", method: 'form_start_merge',
args: { docname: frm.doc.name }, args: { docname: frm.doc.name },
btn: frm.page.btn_primary, btn: frm.page.btn_primary
}).then((r) => { }).then(r => {
if (r.message === true) { if (r.message === true) {
frm.disable_save(); frm.disable_save();
} }
}); });
}, },
set_merge_status: function (frm) { set_merge_status: function(frm) {
if (frm.doc.status == "Pending") return; if (frm.doc.status == "Pending") return;
let successful_records = 0; let successful_records = 0;
frm.doc.merge_accounts.forEach((row) => { frm.doc.merge_accounts.forEach((row) => {
if (row.merged) successful_records += 1; if (row.merged) successful_records += 1;
}); });
let message_args = [successful_records, frm.doc.merge_accounts.length]; let message_args = [successful_records, frm.doc.merge_accounts.length];
frm.dashboard.set_headline(__("Successfully merged {0} out of {1}.", message_args)); frm.dashboard.set_headline(__('Successfully merged {0} out of {1}.', message_args));
}, },
root_type: function (frm) { root_type: function(frm) {
frm.set_value("account", ""); frm.set_value('account', '');
frm.set_value("merge_accounts", []); frm.set_value('merge_accounts', []);
}, },
company: function (frm) { company: function(frm) {
frm.set_value("account", ""); frm.set_value('account', '');
frm.set_value("merge_accounts", []); frm.set_value('merge_accounts', []);
}, }
}); });
frappe.ui.form.on("Ledger Merge Accounts", { frappe.ui.form.on('Ledger Merge Accounts', {
merge_accounts_add: function (frm) { merge_accounts_add: function(frm) {
frm.trigger("update_primary_action"); frm.trigger('update_primary_action');
}, },
merge_accounts_remove: function (frm) { merge_accounts_remove: function(frm) {
frm.trigger("update_primary_action"); frm.trigger('update_primary_action');
}, },
account: function (frm, cdt, cdn) { account: function(frm, cdt, cdn) {
let row = frappe.get_doc(cdt, cdn); let row = frappe.get_doc(cdt, cdn);
row.account_name = row.account; row.account_name = row.account;
frm.refresh_field("merge_accounts"); frm.refresh_field('merge_accounts');
frm.trigger("update_primary_action"); frm.trigger('update_primary_action');
}, }
}); });

View File

@@ -1,6 +1,8 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors // Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Loyalty Point Entry", { frappe.ui.form.on('Loyalty Point Entry', {
refresh: function (frm) {}, refresh: function(frm) {
}
}); });

View File

@@ -3,37 +3,30 @@
frappe.provide("erpnext.accounts.dimensions"); frappe.provide("erpnext.accounts.dimensions");
frappe.ui.form.on("Loyalty Program", { frappe.ui.form.on('Loyalty Program', {
setup: function (frm) { setup: function(frm) {
var help_content = `<table class="table table-bordered" style="background-color: var(--scrollbar-track-color);"> var help_content =
`<table class="table table-bordered" style="background-color: var(--scrollbar-track-color);">
<tr><td> <tr><td>
<h4> <h4>
<i class="fa fa-hand-right"></i> <i class="fa fa-hand-right"></i>
${__("Notes")} ${__('Notes')}
</h4> </h4>
<ul> <ul>
<li> <li>
${__( ${__("Loyalty Points will be calculated from the spent done (via the Sales Invoice), based on collection factor mentioned.")}
"Loyalty Points will be calculated from the spent done (via the Sales Invoice), based on collection factor mentioned."
)}
</li> </li>
<li> <li>
${__( ${__("There can be multiple tiered collection factor based on the total spent. But the conversion factor for redemption will always be same for all the tier.")}
"There can be multiple tiered collection factor based on the total spent. But the conversion factor for redemption will always be same for all the tier."
)}
</li> </li>
<li> <li>
${__( ${__("In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent")}
"In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent"
)}
</li> </li>
<li> <li>
${__("If unlimited expiry for the Loyalty Points, keep the Expiry Duration empty or 0.")} ${__("If unlimited expiry for the Loyalty Points, keep the Expiry Duration empty or 0.")}
</li> </li>
<li> <li>
${__( ${__("If Auto Opt In is checked, then the customers will be automatically linked with the concerned Loyalty Program (on save)")}
"If Auto Opt In is checked, then the customers will be automatically linked with the concerned Loyalty Program (on save)"
)}
</li> </li>
<li> <li>
${__("One customer can be part of only single Loyalty Program.")} ${__("One customer can be part of only single Loyalty Program.")}
@@ -44,14 +37,14 @@ frappe.ui.form.on("Loyalty Program", {
set_field_options("loyalty_program_help", help_content); set_field_options("loyalty_program_help", help_content);
}, },
onload: function (frm) { onload: function(frm) {
frm.set_query("expense_account", function (doc) { frm.set_query("expense_account", function(doc) {
return { return {
filters: { filters: {
root_type: "Expense", "root_type": "Expense",
is_group: 0, 'is_group': 0,
company: doc.company, 'company': doc.company
}, }
}; };
}); });
@@ -59,15 +52,13 @@ frappe.ui.form.on("Loyalty Program", {
erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype); erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
}, },
refresh: function (frm) { refresh: function(frm) {
if (frm.doc.loyalty_program_type === "Single Tier Program" && frm.doc.collection_rules.length > 1) { if (frm.doc.loyalty_program_type === "Single Tier Program" && frm.doc.collection_rules.length > 1) {
frappe.throw( frappe.throw(__("Please select the Multiple Tier Program type for more than one collection rules."));
__("Please select the Multiple Tier Program type for more than one collection rules.")
);
} }
}, },
company: function (frm) { company: function(frm) {
erpnext.accounts.dimensions.update_dimension(frm, frm.doctype); erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
}, }
}); });

View File

@@ -1,16 +1,16 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt // License: GNU General Public License v3. See license.txt
frappe.ui.form.on("Mode of Payment", { frappe.ui.form.on('Mode of Payment', {
setup: function (frm) { setup: function(frm) {
frm.set_query("default_account", "accounts", function (doc, cdt, cdn) { frm.set_query("default_account", "accounts", function(doc, cdt, cdn) {
let d = locals[cdt][cdn]; let d = locals[cdt][cdn];
return { return {
filters: [ filters: [
["Account", "account_type", "in", "Bank, Cash, Receivable"], ['Account', 'account_type', 'in', 'Bank, Cash, Receivable'],
["Account", "is_group", "=", 0], ['Account', 'is_group', '=', 0],
["Account", "company", "=", d.company], ['Account', 'company', '=', d.company]
], ]
}; };
}); });
}, },

View File

@@ -1,16 +1,16 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt // License: GNU General Public License v3. See license.txt
frappe.ui.form.on("Monthly Distribution", { frappe.ui.form.on('Monthly Distribution', {
onload(frm) { onload(frm) {
if (frm.doc.__islocal) { if(frm.doc.__islocal) {
return frm.call("get_months").then(() => { return frm.call('get_months').then(() => {
frm.refresh_field("percentages"); frm.refresh_field('percentages');
}); });
} }
}, },
refresh(frm) { refresh(frm) {
frm.toggle_display("distribution_id", frm.doc.__islocal); frm.toggle_display('distribution_id', frm.doc.__islocal);
}, }
}); });

View File

@@ -1,52 +1,48 @@
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors // Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Opening Invoice Creation Tool", { frappe.ui.form.on('Opening Invoice Creation Tool', {
setup: function (frm) { setup: function(frm) {
frm.set_query("party_type", "invoices", function (doc, cdt, cdn) { frm.set_query('party_type', 'invoices', function(doc, cdt, cdn) {
return { return {
filters: { filters: {
name: ["in", "Customer, Supplier"], 'name': ['in', 'Customer, Supplier']
}, }
}; };
}); });
if (frm.doc.company) { if (frm.doc.company) {
frm.trigger("setup_company_filters"); frm.trigger('setup_company_filters');
} }
frappe.realtime.on("opening_invoice_creation_progress", (data) => { frappe.realtime.on('opening_invoice_creation_progress', data => {
if (!frm.doc.import_in_progress) { if (!frm.doc.import_in_progress) {
frm.dashboard.reset(); frm.dashboard.reset();
frm.doc.import_in_progress = true; frm.doc.import_in_progress = true;
} }
if (data.count == data.total) { if (data.count == data.total) {
setTimeout( setTimeout(() => {
() => { frm.doc.import_in_progress = false;
frm.doc.import_in_progress = false; frm.clear_table("invoices");
frm.clear_table("invoices"); frm.refresh_fields();
frm.refresh_fields(); frm.page.clear_indicator();
frm.page.clear_indicator(); frm.dashboard.hide_progress();
frm.dashboard.hide_progress(); frappe.msgprint(__("Opening {0} Invoices created", [frm.doc.invoice_type]));
frappe.msgprint(__("Opening {0} Invoices created", [frm.doc.invoice_type])); }, 1500, data.title);
},
1500,
data.title
);
return; return;
} }
frm.dashboard.show_progress(data.title, (data.count / data.total) * 100, data.message); frm.dashboard.show_progress(data.title, (data.count / data.total) * 100, data.message);
frm.page.set_indicator(__("In Progress"), "orange"); frm.page.set_indicator(__('In Progress'), 'orange');
}); });
erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype); erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
}, },
refresh: function (frm) { refresh: function(frm) {
frm.disable_save(); frm.disable_save();
!frm.doc.import_in_progress && frm.trigger("make_dashboard"); !frm.doc.import_in_progress && frm.trigger("make_dashboard");
frm.page.set_primary_action(__("Create Invoices"), () => { frm.page.set_primary_action(__('Create Invoices'), () => {
let btn_primary = frm.page.btn_primary.get(0); let btn_primary = frm.page.btn_primary.get(0);
return frm.call({ return frm.call({
doc: frm.doc, doc: frm.doc,
@@ -62,98 +58,100 @@ frappe.ui.form.on("Opening Invoice Creation Tool", {
} }
}, },
setup_company_filters: function (frm) { setup_company_filters: function(frm) {
frm.set_query("cost_center", "invoices", function (doc, cdt, cdn) { frm.set_query('cost_center', 'invoices', function(doc, cdt, cdn) {
return { return {
filters: { filters: {
company: doc.company, 'company': doc.company
}, }
}; };
}); });
frm.set_query("cost_center", function (doc) { frm.set_query('cost_center', function(doc) {
return { return {
filters: { filters: {
company: doc.company, 'company': doc.company
}, }
}; };
}); });
frm.set_query("temporary_opening_account", "invoices", function (doc, cdt, cdn) { frm.set_query('temporary_opening_account', 'invoices', function(doc, cdt, cdn) {
return { return {
filters: { filters: {
company: doc.company, 'company': doc.company
}, }
}; }
}); });
}, },
company: function (frm) { company: function(frm) {
if (frm.doc.company) { if (frm.doc.company) {
frm.trigger("setup_company_filters");
frm.trigger('setup_company_filters');
frappe.call({ frappe.call({
method: "erpnext.accounts.doctype.opening_invoice_creation_tool.opening_invoice_creation_tool.get_temporary_opening_account", method: 'erpnext.accounts.doctype.opening_invoice_creation_tool.opening_invoice_creation_tool.get_temporary_opening_account',
args: { args: {
company: frm.doc.company, company: frm.doc.company
}, },
callback: (r) => { callback: (r) => {
if (r.message) { if (r.message) {
frm.doc.__onload.temporary_opening_account = r.message; frm.doc.__onload.temporary_opening_account = r.message;
frm.trigger("update_invoice_table"); frm.trigger('update_invoice_table');
} }
}, }
}); })
} }
erpnext.accounts.dimensions.update_dimension(frm, frm.doctype); erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
}, },
invoice_type: function (frm) { invoice_type: function(frm) {
$.each(frm.doc.invoices, (idx, row) => { $.each(frm.doc.invoices, (idx, row) => {
row.party_type = frm.doc.invoice_type == "Sales" ? "Customer" : "Supplier"; row.party_type = frm.doc.invoice_type == "Sales"? "Customer": "Supplier";
row.party = ""; row.party = "";
}); });
frm.refresh_fields(); frm.refresh_fields();
}, },
make_dashboard: function (frm) { make_dashboard: function(frm) {
let max_count = frm.doc.__onload.max_count; let max_count = frm.doc.__onload.max_count;
let opening_invoices_summary = frm.doc.__onload.opening_invoices_summary; let opening_invoices_summary = frm.doc.__onload.opening_invoices_summary;
if (!$.isEmptyObject(opening_invoices_summary)) { if(!$.isEmptyObject(opening_invoices_summary)) {
let section = frm.dashboard.add_section( let section = frm.dashboard.add_section(
frappe.render_template("opening_invoice_creation_tool_dashboard", { frappe.render_template('opening_invoice_creation_tool_dashboard', {
data: opening_invoices_summary, data: opening_invoices_summary,
max_count: max_count, max_count: max_count
}), }),
__("Opening Invoices Summary") __("Opening Invoices Summary")
); );
section.on("click", ".invoice-link", function () { section.on('click', '.invoice-link', function() {
let doctype = $(this).attr("data-type"); let doctype = $(this).attr('data-type');
let company = $(this).attr("data-company"); let company = $(this).attr('data-company');
frappe.set_route("List", doctype, { is_opening: "Yes", company: company, docstatus: 1 }); frappe.set_route('List', doctype,
{'is_opening': 'Yes', 'company': company, 'docstatus': 1});
}); });
frm.dashboard.show(); frm.dashboard.show();
} }
}, },
update_invoice_table: function (frm) { update_invoice_table: function(frm) {
$.each(frm.doc.invoices, (idx, row) => { $.each(frm.doc.invoices, (idx, row) => {
if (!row.temporary_opening_account) { if (!row.temporary_opening_account) {
row.temporary_opening_account = frm.doc.__onload.temporary_opening_account; row.temporary_opening_account = frm.doc.__onload.temporary_opening_account;
} }
if (!row.cost_center) { if(!row.cost_center) {
row.cost_center = frm.doc.cost_center; row.cost_center = frm.doc.cost_center;
} }
row.party_type = frm.doc.invoice_type == "Sales" ? "Customer" : "Supplier"; row.party_type = frm.doc.invoice_type == "Sales"? "Customer": "Supplier";
}); });
}, }
}); });
frappe.ui.form.on("Opening Invoice Creation Tool Item", { frappe.ui.form.on('Opening Invoice Creation Tool Item', {
invoices_add: (frm) => { invoices_add: (frm) => {
frm.trigger("update_invoice_table"); frm.trigger('update_invoice_table');
}, }
}); });

View File

@@ -1,34 +1,33 @@
// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors // Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Party Link", { frappe.ui.form.on('Party Link', {
refresh: function (frm) { refresh: function(frm) {
frm.set_query("primary_role", () => { frm.set_query('primary_role', () => {
return { return {
filters: { filters: {
name: ["in", ["Customer", "Supplier"]], name: ['in', ['Customer', 'Supplier']]
}, }
}; };
}); });
frm.set_query("secondary_role", () => { frm.set_query('secondary_role', () => {
let party_types = Object.keys(frappe.boot.party_account_types).filter( let party_types = Object.keys(frappe.boot.party_account_types)
(p) => p != frm.doc.primary_role .filter(p => p != frm.doc.primary_role);
);
return { return {
filters: { filters: {
name: ["in", party_types], name: ['in', party_types]
}, }
}; };
}); });
}, },
primary_role(frm) { primary_role(frm) {
frm.set_value("primary_party", ""); frm.set_value('primary_party', '');
frm.set_value("secondary_role", ""); frm.set_value('secondary_role', '');
}, },
secondary_role(frm) { secondary_role(frm) {
frm.set_value("secondary_party", ""); frm.set_value('secondary_party', '');
}, }
}); });

View File

@@ -7,7 +7,7 @@ cur_frm.cscript.tax_table = "Advance Taxes and Charges";
frappe.ui.form.on('Payment Entry', { frappe.ui.form.on('Payment Entry', {
onload: function(frm) { onload: function(frm) {
frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice', 'Journal Entry', 'Repost Payment Ledger', 'Repost Accounting Ledger', 'Unreconcile Payment', 'Unreconcile Payment Entries', 'Bank Transaction']; frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice', 'Journal Entry', 'Repost Payment Ledger','Repost Accounting Ledger'];
if(frm.doc.__islocal) { if(frm.doc.__islocal) {
if (!frm.doc.paid_from) frm.set_value("paid_from_account_currency", null); if (!frm.doc.paid_from) frm.set_value("paid_from_account_currency", null);
@@ -152,13 +152,6 @@ frappe.ui.form.on('Payment Entry', {
frm.events.hide_unhide_fields(frm); frm.events.hide_unhide_fields(frm);
frm.events.set_dynamic_labels(frm); frm.events.set_dynamic_labels(frm);
frm.events.show_general_ledger(frm); frm.events.show_general_ledger(frm);
if((frm.doc.references) && (frm.doc.references.find((elem) => {return elem.exchange_gain_loss != 0}))) {
frm.add_custom_button(__("View Exchange Gain/Loss Journals"), function() {
frappe.set_route("List", "Journal Entry", {"voucher_type": "Exchange Gain Or Loss", "reference_name": frm.doc.name});
}, __('Actions'));
}
erpnext.accounts.unreconcile_payment.add_unreconcile_btn(frm);
}, },
validate_company: (frm) => { validate_company: (frm) => {
@@ -631,7 +624,7 @@ frappe.ui.form.on('Payment Entry', {
get_outstanding_invoices_or_orders: function(frm, get_outstanding_invoices, get_orders_to_be_billed) { get_outstanding_invoices_or_orders: function(frm, get_outstanding_invoices, get_orders_to_be_billed) {
const today = frappe.datetime.get_today(); const today = frappe.datetime.get_today();
let fields = [ const fields = [
{fieldtype:"Section Break", label: __("Posting Date")}, {fieldtype:"Section Break", label: __("Posting Date")},
{fieldtype:"Date", label: __("From Date"), {fieldtype:"Date", label: __("From Date"),
fieldname:"from_posting_date", default:frappe.datetime.add_days(today, -30)}, fieldname:"from_posting_date", default:frappe.datetime.add_days(today, -30)},
@@ -646,29 +639,18 @@ frappe.ui.form.on('Payment Entry', {
fieldname:"outstanding_amt_greater_than", default: 0}, fieldname:"outstanding_amt_greater_than", default: 0},
{fieldtype:"Column Break"}, {fieldtype:"Column Break"},
{fieldtype:"Float", label: __("Less Than Amount"), fieldname:"outstanding_amt_less_than"}, {fieldtype:"Float", label: __("Less Than Amount"), fieldname:"outstanding_amt_less_than"},
]; {fieldtype:"Section Break"},
{fieldtype:"Link", label:__("Cost Center"), fieldname:"cost_center", options:"Cost Center",
if (frm.dimension_filters) { "get_query": function() {
let column_break_insertion_point = Math.ceil((frm.dimension_filters.length)/2); return {
"filters": {"company": frm.doc.company}
fields.push({fieldtype:"Section Break"}); }
frm.dimension_filters.map((elem, idx)=>{
fields.push({
fieldtype: "Link",
label: elem.document_type == "Cost Center" ? "Cost Center" : elem.label,
options: elem.document_type,
fieldname: elem.fieldname || elem.document_type
});
if(idx+1 == column_break_insertion_point) {
fields.push({fieldtype:"Column Break"});
} }
}); },
} {fieldtype:"Column Break"},
fields = fields.concat([
{fieldtype:"Section Break"}, {fieldtype:"Section Break"},
{fieldtype:"Check", label: __("Allocate Payment Amount"), fieldname:"allocate_payment_amount", default:1}, {fieldtype:"Check", label: __("Allocate Payment Amount"), fieldname:"allocate_payment_amount", default:1},
]); ];
let btn_text = ""; let btn_text = "";
@@ -840,6 +822,7 @@ frappe.ui.form.on('Payment Entry', {
else else
total_negative_outstanding += Math.abs(flt(row.outstanding_amount)); total_negative_outstanding += Math.abs(flt(row.outstanding_amount));
}) })
var allocated_negative_outstanding = 0; var allocated_negative_outstanding = 0;
if ( if (
(frm.doc.payment_type=="Receive" && frm.doc.party_type=="Customer") || (frm.doc.payment_type=="Receive" && frm.doc.party_type=="Customer") ||
@@ -854,7 +837,6 @@ frappe.ui.form.on('Payment Entry', {
var allocated_positive_outstanding = paid_amount + allocated_negative_outstanding; var allocated_positive_outstanding = paid_amount + allocated_negative_outstanding;
} else if (in_list(["Customer", "Supplier"], frm.doc.party_type)) { } else if (in_list(["Customer", "Supplier"], frm.doc.party_type)) {
total_negative_outstanding = flt(total_negative_outstanding, precision("outstanding_amount"))
if(paid_amount > total_negative_outstanding) { if(paid_amount > total_negative_outstanding) {
if(total_negative_outstanding == 0) { if(total_negative_outstanding == 0) {
frappe.msgprint( frappe.msgprint(
@@ -930,7 +912,7 @@ frappe.ui.form.on('Payment Entry', {
if(frm.doc.payment_type == "Receive" if(frm.doc.payment_type == "Receive"
&& frm.doc.base_total_allocated_amount < frm.doc.base_received_amount + total_deductions && frm.doc.base_total_allocated_amount < frm.doc.base_received_amount + total_deductions
&& frm.doc.total_allocated_amount < frm.doc.paid_amount + (total_deductions / frm.doc.source_exchange_rate)) { && frm.doc.total_allocated_amount < frm.doc.paid_amount + (total_deductions / frm.doc.source_exchange_rate)) {
unallocated_amount = (frm.doc.base_received_amount + total_deductions - flt(frm.doc.base_total_taxes_and_charges) unallocated_amount = (frm.doc.base_received_amount + total_deductions + flt(frm.doc.base_total_taxes_and_charges)
- frm.doc.base_total_allocated_amount) / frm.doc.source_exchange_rate; - frm.doc.base_total_allocated_amount) / frm.doc.source_exchange_rate;
} else if (frm.doc.payment_type == "Pay" } else if (frm.doc.payment_type == "Pay"
&& frm.doc.base_total_allocated_amount < frm.doc.base_paid_amount - total_deductions && frm.doc.base_total_allocated_amount < frm.doc.base_paid_amount - total_deductions

Some files were not shown because too many files have changed in this diff Show More