Resolve merge conflicts from enterprise_sprint branch

This commit is contained in:
Saurabh 2018-05-14 21:15:46 +05:30
commit 2ca83d61ea
463 changed files with 35469 additions and 5844 deletions

View File

@ -296,6 +296,38 @@
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0",
"fieldname": "inter_company_account",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Inter Company Account",
"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_on_submit": 0,
@ -380,7 +412,7 @@
"no_copy": 0,
"oldfieldname": "account_type",
"oldfieldtype": "Select",
"options": "\nAccumulated Depreciation\nBank\nCash\nChargeable\nCost of Goods Sold\nDepreciation\nEquity\nExpense Account\nExpenses Included In Valuation\nFixed Asset\nIncome Account\nPayable\nReceivable\nRound Off\nStock\nStock Adjustment\nStock Received But Not Billed\nTax\nTemporary",
"options": "\nAccumulated Depreciation\nAsset Received But Not Billed\nBank\nCash\nChargeable\nCapital Work in Progress\nCost of Goods Sold\nDepreciation\nEquity\nExpense Account\nExpenses Included In Asset Valuation\nExpenses Included In Valuation\nFixed Asset\nIncome Account\nPayable\nReceivable\nRound Off\nStock\nStock Adjustment\nStock Received But Not Billed\nTax\nTemporary",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
@ -593,7 +625,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-04-04 03:23:20.011949",
"modified": "2018-05-07 15:37:25.962506",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Account",
@ -601,7 +633,6 @@
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@ -621,7 +652,6 @@
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
@ -641,7 +671,6 @@
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
@ -661,7 +690,6 @@
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
@ -681,7 +709,6 @@
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,

View File

@ -147,8 +147,9 @@
}
},
"Duties and Taxes": {
"account_type": "Tax",
"is_group": 1
"TDS": {
"account_type": "Tax"
}
},
"Loans (Liabilities)": {
"Secured Loans": {},

View File

@ -64,6 +64,9 @@ def get():
},
_("Accumulated Depreciation"): {
"account_type": "Accumulated Depreciation"
},
_("CWIP Account"): {
"account_type": "Capital Work in Progress",
}
},
_("Investments"): {
@ -82,6 +85,9 @@ def get():
_("Cost of Goods Sold"): {
"account_type": "Cost of Goods Sold"
},
_("Expenses Included In Asset Valuation"): {
"account_type": "Expenses Included In Asset Valuation"
},
_("Expenses Included In Valuation"): {
"account_type": "Expenses Included In Valuation"
},
@ -147,6 +153,9 @@ def get():
_("Stock Received But Not Billed"): {
"account_type": "Stock Received But Not Billed"
},
_("Asset Received But Not Billed"): {
"account_type": "Asset Received But Not Billed"
}
},
_("Duties and Taxes"): {
"account_type": "Tax",

View File

@ -87,6 +87,10 @@ def get():
"account_type": "Accumulated Depreciation",
"account_number": "1780"
},
_("CWIP Account"): {
"account_type": "Capital Work in Progress",
"account_number": "1790"
},
"account_number": "1700"
},
_("Investments"): {
@ -110,6 +114,10 @@ def get():
"account_type": "Cost of Goods Sold",
"account_number": "5111"
},
_("Expenses Included In Asset Valuation"): {
"account_type": "Expenses Included In Asset Valuation",
"account_number": "5112"
},
_("Expenses Included In Valuation"): {
"account_type": "Expenses Included In Valuation",
"account_number": "5118"
@ -230,6 +238,10 @@ def get():
"account_type": "Stock Received But Not Billed",
"account_number": "2210"
},
_("Asset Received But Not Billed"): {
"account_type": "Asset Received But Not Billed",
"account_number": "2211"
},
"account_number": "2200"
},
_("Duties and Taxes"): {

View File

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

View File

@ -0,0 +1,349 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "field:period_name",
"beta": 0,
"creation": "2018-04-13 18:50:14.672323",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "period_name",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Period Name",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "start_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Start Date",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "end_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "End Date",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_4",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "company",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Company",
"length": 0,
"no_copy": 0,
"options": "Company",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "status",
"fieldtype": "Select",
"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": "Status",
"length": 0,
"no_copy": 0,
"options": "Open\nClosed",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_7",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "closed_documents",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Closed Documents",
"length": 0,
"no_copy": 0,
"options": "Closed Document",
"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
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-04-13 19:14:47.593753",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounting Period",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
}

View File

@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
class AccountingPeriod(Document):
def validate(self):
self.validate_overlap()
def before_insert(self):
self.bootstrap_doctypes_for_closing()
def autoname(self):
company_abbr = frappe.db.get_value("Company", self.company, "abbr")
self.name = " - ".join([self.period_name, company_abbr])
def validate_overlap(self):
existing_accounting_period = frappe.db.sql("""select name from `tabAccounting Period`
where (
(%(start_date)s between start_date and end_date)
or (%(end_date)s between start_date and end_date)
or (start_date between %(start_date)s and %(end_date)s)
or (end_date between %(start_date)s and %(end_date)s)
) and name!=%(name)s and company=%(company)s""",
{
"start_date": self.start_date,
"end_date": self.end_date,
"name": self.name,
"company": self.company
}, as_dict=True)
if len(existing_accounting_period) > 0:
frappe.throw("Accounting Period overlaps with {0}".format(existing_accounting_period[0].get("name")))
def get_doctypes_for_closing(self):
docs_for_closing = []
#if not self.closed_documents or len(self.closed_documents) == 0:
doctypes = ["Sales Invoice", "Purchase Invoice", "Journal Entry", "Payroll Entry", "Bank Reconciliation", "Asset", "Purchase Order", "Sales Order", "Leave Application", "Leave Allocation", "Stock Entry"]
closed_doctypes = [{"document_type": doctype, "closed": 1} for doctype in doctypes]
for closed_doctype in closed_doctypes:
docs_for_closing.append(closed_doctype)
return docs_for_closing
def bootstrap_doctypes_for_closing(self):
if len(self.closed_documents) == 0:
for doctype_for_closing in self.get_doctypes_for_closing():
self.append('closed_documents', {
"document_type": doctype_for_closing.document_type,
"closed": doctype_for_closing.closed
})

View File

@ -0,0 +1,23 @@
/* eslint-disable */
// rename this file from _test_[name] to test_[name] to activate
// and remove above this line
QUnit.test("test: Accounting Period", function (assert) {
let done = assert.async();
// number of asserts
assert.expect(1);
frappe.run_serially([
// insert a new Accounting Period
() => frappe.tests.make('Accounting Period', [
// values to be set
{key: 'value'}
]),
() => {
assert.equal(cur_frm.doc.key, 'value');
},
() => done()
]);
});

View File

@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
import frappe
import unittest
class TestAccountingPeriod(unittest.TestCase):
def test_overlap(self):
ap1 = create_accounting_period({"start_date":"2018-04-01", "end_date":"2018-06-30", "company":"Wind Power LLC"})
ap1.save()
ap2 = create_accounting_period({"start_date":"2018-06-30", "end_date":"2018-07-10", "company":"Wind Power LLC"})
self.assertRaises(frappe.OverlapError, accounting_period_2.save())
def tearDown(self):
pass
def create_accounting_period(**args):
accounting_period = frappe.new_doc("Accounting Period")
accounting_period.start_date = args.start_date or frappe.utils.datetime.date(2018, 4, 1)
accounting_period.end_date = args.end_date or frappe.utils.datetime.date(2018, 6, 30)
accounting_period.company = args.company
accounting_period.period_name = "_Test_Period_Name_1"
return accounting_period

View File

@ -0,0 +1,74 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2018-04-16 21:50:05.860195",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "",
"fieldname": "company",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Company",
"length": 0,
"no_copy": 0,
"options": "Company",
"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
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2018-04-20 14:00:46.014502",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Allowed To Transact With",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
}

View File

@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
from frappe.model.document import Document
class AllowedToTransactWith(Document):
pass

View File

@ -0,0 +1,104 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2018-04-13 18:51:29.720606",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "document_type",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Document Type",
"length": 0,
"no_copy": 0,
"options": "DocType",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "closed",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Closed",
"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
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2018-04-13 18:51:41.118025",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Closed Document",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
}

View File

@ -6,5 +6,5 @@ from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
class HealthInsurance(Document):
class ClosedDocument(Document):
pass

View File

@ -15,8 +15,57 @@ frappe.ui.form.on('Cost Center', {
}
}
})
},
refresh: function(frm) {
if (!frm.is_new()) {
frm.add_custom_button(__('Update Cost Center Number'), function () {
frm.trigger("update_cost_center_number");
});
}
})
},
update_cost_center_number: function(frm) {
var d = new frappe.ui.Dialog({
title: __('Update Cost Center Number'),
fields: [
{
"label": 'Cost Center Number',
"fieldname": "cost_center_number",
"fieldtype": "Data",
"reqd": 1
}
],
primary_action: function() {
var data = d.get_values();
if(data.cost_center_number === frm.doc.cost_center_number) {
d.hide();
return;
}
frappe.call({
method: "erpnext.accounts.doctype.cost_center.cost_center.update_number_field",
args: {
doctype_name: frm.doc.doctype,
name: frm.doc.name,
field_name: d.fields[0].fieldname,
field_value: data.cost_center_number,
company: frm.doc.company
},
callback: function(r) {
if(!r.exc) {
if(r.message) {
frappe.set_route("Form", "Cost Center", r.message);
} else {
me.set_value("cost_center_number", data.cost_center_number);
}
d.hide();
}
}
});
},
primary_action_label: __('Update')
});
d.show();
}
});
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
var intro_txt = '';

View File

@ -1,5 +1,6 @@
{
"allow_copy": 1,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:cost_center_name",
@ -13,6 +14,7 @@
"editable_grid": 0,
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -38,9 +40,11 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -68,9 +72,42 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "cost_center_number",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Cost Center Number",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -99,9 +136,11 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -130,9 +169,11 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -157,10 +198,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0,
"width": "50%"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -188,9 +231,11 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -218,9 +263,11 @@
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -248,9 +295,11 @@
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -279,22 +328,23 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "fa fa-money",
"idx": 1,
"image_view": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2017-02-17 16:22:27.129572",
"modified": "2018-04-26 15:26:25.325778",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Cost Center",
@ -302,7 +352,6 @@
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@ -322,7 +371,6 @@
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
@ -342,7 +390,6 @@
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
@ -362,7 +409,6 @@
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
@ -382,7 +428,6 @@
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,

View File

@ -4,6 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import cint, cstr
from frappe.utils.nestedset import NestedSet
class CostCenter(NestedSet):
@ -62,8 +63,68 @@ class CostCenter(NestedSet):
super(CostCenter, self).after_rename(olddn, newdn, merge)
if not merge:
frappe.db.set_value("Cost Center", newdn, "cost_center_name",
" - ".join(newdn.split(" - ")[:-1]))
new_cost_center = frappe.db.get_value("Cost Center", newdn, ["cost_center_name", "cost_center_number"], as_dict=1)
# exclude company abbr
new_parts = newdn.split(" - ")[:-1]
# update cost center number and remove from parts
if new_parts[0][0].isdigit():
if len(new_parts) == 1:
new_parts = newdn.split(" ")
if new_cost_center.cost_center_number != new_parts[0]:
validate_field_number("Cost Center", self.name, new_parts[0], self.company, "cost_center_number")
self.cost_center_number = new_parts[0]
self.db_set("cost_center_number", new_parts[0])
new_parts = new_parts[1:]
# update cost center name
cost_center_name = " - ".join(new_parts)
if new_cost_center.cost_center_name != cost_center_name:
self.cost_center_name = cost_center_name
self.db_set("cost_center_name", cost_center_name)
def on_doctype_update():
frappe.db.add_index("Cost Center", ["lft", "rgt"])
def get_doc_name_autoname(field_value, doc_title, name, company):
if company:
name_split=name.split("-")
parts = [doc_title.strip(), name_split[len(name_split)-1].strip()]
else:
parts = [doc_title.strip()]
if cstr(field_value).strip():
parts.insert(0, cstr(field_value).strip())
return ' - '.join(parts)
def validate_field_number(doctype_name, name, field_value, company, field_name):
if field_value:
if company:
doctype_with_same_number = frappe.db.get_value(doctype_name,
{field_name: field_value, "company": company, "name": ["!=", name]})
else:
doctype_with_same_number = frappe.db.get_value(doctype_name,
{field_name: field_value, "name": ["!=", name]})
if doctype_with_same_number:
frappe.throw(_("{0} Number {1} already used in account {2}")
.format(doctype_name, field_value, doctype_with_same_number))
@frappe.whitelist()
def update_number_field(doctype_name, name, field_name, field_value, company):
doc_title = frappe.db.get_value(doctype_name, name, frappe.scrub(doctype_name)+"_name")
validate_field_number(doctype_name, name, field_value, company, field_name)
frappe.db.set_value(doctype_name, name, field_name, field_value)
if doc_title[0].isdigit():
separator = " - " if " - " in doc_title else " "
doc_title = doc_title.split(separator, 1)[1]
frappe.db.set_value(doctype_name, name, frappe.scrub(doctype_name)+"_name", doc_title)
new_name = get_doc_name_autoname(field_value, doc_title, name, company)
if name != new_name:
frappe.rename_doc(doctype_name, name, new_name)
return new_name

View File

@ -0,0 +1,99 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Exchange Rate Revaluation', {
refresh: function(frm) {
if(frm.doc.docstatus==1) {
frm.add_custom_button(__('Make Journal Entry'), function() {
return frm.events.make_jv(frm);
});
}
},
get_entries: function(frm) {
frappe.call({
method: "get_accounts_data",
doc: cur_frm.doc,
callback: function(r){
frappe.model.clear_table(frm.doc, "accounts");
if(r.message) {
r.message.forEach((d) => {
cur_frm.add_child("accounts",d);
});
frm.events.get_total_gain_loss(frm);
refresh_field("accounts");
}
}
});
},
get_total_gain_loss: function(frm) {
if(!(frm.doc.accounts && frm.doc.accounts.length)) return;
let total_gain_loss = 0;
frm.doc.accounts.forEach((d) => {
d.gain_loss = flt(d.new_balance_in_base_currency, precision("new_balance_in_base_currency", d)) - flt(d.balance_in_base_currency, precision("balance_in_base_currency", d));
total_gain_loss += flt(d.gain_loss, precision("gain_loss", d));
});
frm.set_value("total_gain_loss", flt(total_gain_loss, precision("total_gain_loss")));
frm.refresh_fields();
},
make_jv : function(frm) {
frappe.call({
method: "make_jv_entry",
doc: frm.doc,
callback: function(r){
if (r.message)
var doc = frappe.model.sync(r.message)[0];
frappe.set_route("Form", doc.doctype, doc.name);
}
});
}
});
frappe.ui.form.on("Exchange Rate Revaluation Account", {
new_exchange_rate: function(frm, cdt, cdn) {
var row = frappe.get_doc(cdt, cdn);
row.new_balance_in_base_currency = flt(row.new_exchange_rate * flt(row.balance_in_account_currency),
precision("new_balance_in_base_currency", row));
row.gain_loss = row.new_balance_in_base_currency - flt(row.balance_in_base_currency);
refresh_field("accounts");
frm.events.get_total_gain_loss(frm);
},
account: function(frm, cdt, cdn) {
get_account_details(frm, cdt, cdn);
},
party: function(frm, cdt, cdn) {
get_account_details(frm, cdt, cdn);
},
accounts_remove: function(frm) {
frm.events.get_total_gain_loss(frm);
}
});
var get_account_details = function(frm, cdt, cdn) {
var row = frappe.get_doc(cdt, cdn);
if(!frm.doc.company || !frm.doc.posting_date) {
frappe.throw(__("Please select Company and Posting Date to getting entries"));
}
frappe.call({
method: "erpnext.accounts.doctype.exchange_rate_revaluation.exchange_rate_revaluation.get_account_details",
args:{
account: row.account,
company: frm.doc.company,
posting_date: frm.doc.posting_date,
party_type: row.party_type,
party: row.party
},
callback: function(r){
$.extend(row, r.message);
refresh_field("accounts");
frm.events.get_total_gain_loss(frm);
}
});
};

View File

@ -0,0 +1,379 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 0,
"autoname": "ERV.####",
"beta": 0,
"creation": "2018-04-13 18:25:55.943587",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "Today",
"fieldname": "posting_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Posting Date",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_2",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "company",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Company",
"length": 0,
"no_copy": 0,
"options": "Company",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_4",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "get_entries",
"fieldtype": "Button",
"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": "Get Entries",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "accounts",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Exchange Rate Revaluation Account",
"length": 0,
"no_copy": 1,
"options": "Exchange Rate Revaluation 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,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_6",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "total_gain_loss",
"fieldtype": "Currency",
"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": "Total Gain/Loss",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "amended_from",
"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",
"length": 0,
"no_copy": 1,
"options": "Exchange Rate Revaluation",
"permlevel": 0,
"print_hide": 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,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-05-05 17:50:56.352167",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Exchange Rate Revaluation",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 1,
"cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 1,
"write": 1
},
{
"amend": 1,
"cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 1,
"write": 1
},
{
"amend": 1,
"cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User",
"set_user_permissions": 0,
"share": 1,
"submit": 1,
"write": 1
}
],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
}

View File

@ -0,0 +1,170 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe, erpnext
from frappe import _
from frappe.utils import flt
from frappe.model.document import Document
from frappe.model.meta import get_field_precision
from erpnext.setup.utils import get_exchange_rate
from erpnext.accounts.doctype.journal_entry.journal_entry import get_balance_on
class ExchangeRateRevaluation(Document):
def validate(self):
self.set_total_gain_loss()
def set_total_gain_loss(self):
total_gain_loss = 0
for d in self.accounts:
d.gain_loss = flt(d.new_balance_in_base_currency, d.precision("new_balance_in_base_currency")) \
- flt(d.balance_in_base_currency, d.precision("balance_in_base_currency"))
total_gain_loss += flt(d.gain_loss, d.precision("gain_loss"))
self.total_gain_loss = flt(total_gain_loss, self.precision("total_gain_loss"))
def validate_mandatory(self):
if not (self.company and self.posting_date):
frappe.throw(_("Please select Company and Posting Date to getting entries"))
def get_accounts_data(self, account=None):
accounts = []
self.validate_mandatory()
company_currency = erpnext.get_company_currency(self.company)
precision = get_field_precision(frappe.get_meta("Exchange Rate Revaluation Account")
.get_field("new_balance_in_base_currency"), company_currency)
for d in self.get_accounts_from_gle():
current_exchange_rate = d.balance / d.balance_in_account_currency \
if d.balance_in_account_currency else 0
new_exchange_rate = get_exchange_rate(d.account_currency, company_currency, self.posting_date)
new_balance_in_base_currency = flt(d.balance_in_account_currency * new_exchange_rate)
gain_loss = flt(new_balance_in_base_currency, precision) - flt(d.balance, precision)
if gain_loss:
accounts.append({
"account": d.account,
"party_type": d.party_type,
"party": d.party,
"account_currency": d.account_currency,
"balance_in_base_currency": d.balance,
"balance_in_account_currency": d.balance_in_account_currency,
"current_exchange_rate": current_exchange_rate,
"new_exchange_rate": new_exchange_rate,
"new_balance_in_base_currency": new_balance_in_base_currency
})
return accounts
def get_accounts_from_gle(self):
company_currency = erpnext.get_company_currency(self.company)
accounts = frappe.db.sql_list("""
select name
from tabAccount
where is_group = 0
and report_type = 'Balance Sheet'
and root_type in ('Asset', 'Liability', 'Equity')
and account_type != 'Stock'
and company=%s
and account_currency != %s
order by name""",(self.company, company_currency))
account_details = frappe.db.sql("""
select
account, party_type, party, account_currency,
sum(debit_in_account_currency) - sum(credit_in_account_currency) as balance_in_account_currency,
sum(debit) - sum(credit) as balance
from `tabGL Entry`
where account in (%s)
group by account, party_type, party
having sum(debit) != sum(credit)
order by account
""" % ', '.join(['%s']*len(accounts)), tuple(accounts), as_dict=1)
return account_details
def make_jv_entry(self):
if self.total_gain_loss == 0:
return
unrealized_exchange_gain_loss_account = frappe.db.get_value("Company", self.company,
"unrealized_exchange_gain_loss_account")
if not unrealized_exchange_gain_loss_account:
frappe.throw(_("Please set Unrealized Exchange Gain/Loss Account in Company {0}")
.format(self.company))
journal_entry = frappe.new_doc('Journal Entry')
journal_entry.voucher_type = 'Exchange Rate Revaluation'
journal_entry.company = self.company
journal_entry.posting_date = self.posting_date
journal_entry.multi_currency = 1
journal_entry_accounts = []
for d in self.accounts:
dr_or_cr = "debit_in_account_currency" \
if d.get("balance_in_account_currency") > 0 else "credit_in_account_currency"
reverse_dr_or_cr = "debit_in_account_currency" \
if dr_or_cr=="credit_in_account_currency" else "credit_in_account_currency"
journal_entry_accounts.append({
"account": d.get("account"),
"party_type": d.get("party_type"),
"party": d.get("party"),
"account_currency": d.get("account_currency"),
"balance": d.get("balance_in_account_currency"),
dr_or_cr: abs(d.get("balance_in_account_currency")),
"exchange_rate":d.get("new_exchange_rate"),
"reference_type": "Exchange Rate Revaluation",
"reference_name": self.name,
})
journal_entry_accounts.append({
"account": d.get("account"),
"party_type": d.get("party_type"),
"party": d.get("party"),
"account_currency": d.get("account_currency"),
"balance": d.get("balance_in_account_currency"),
reverse_dr_or_cr: abs(d.get("balance_in_account_currency")),
"exchange_rate": d.get("current_exchange_rate"),
"reference_type": "Exchange Rate Revaluation",
"reference_name": self.name
})
journal_entry_accounts.append({
"account": unrealized_exchange_gain_loss_account,
"balance": get_balance_on(unrealized_exchange_gain_loss_account),
"debit_in_account_currency": abs(self.total_gain_loss) if self.total_gain_loss < 0 else 0,
"credit_in_account_currency": self.total_gain_loss if self.total_gain_loss > 0 else 0,
"exchange_rate": 1,
"reference_type": "Exchange Rate Revaluation",
"reference_name": self.name,
})
journal_entry.set("accounts", journal_entry_accounts)
journal_entry.set_amounts_in_company_currency()
journal_entry.set_total_debit_credit()
return journal_entry.as_dict()
@frappe.whitelist()
def get_account_details(account, company, posting_date, party_type=None, party=None):
account_currency, account_type = frappe.db.get_value("Account", account,
["account_currency", "account_type"])
if account_type in ["Receivable", "Payable"] and not (party_type and party):
frappe.throw(_("Party Type and Party is mandatory for {0} account").format(account_type))
account_details = {}
company_currency = erpnext.get_company_currency(company)
balance = get_balance_on(account, party_type=party_type, party=party, in_account_currency=False)
if balance:
balance_in_account_currency = get_balance_on(account, party_type=party_type, party=party)
current_exchange_rate = balance / balance_in_account_currency if balance_in_account_currency else 0
new_exchange_rate = get_exchange_rate(account_currency, company_currency, posting_date)
new_balance_in_base_currency = balance_in_account_currency * new_exchange_rate
account_details = {
"account_currency": account_currency,
"balance_in_base_currency": balance,
"balance_in_account_currency": balance_in_account_currency,
"current_exchange_rate": current_exchange_rate,
"new_exchange_rate": new_exchange_rate,
"new_balance_in_base_currency": new_balance_in_base_currency
}
return account_details

View File

@ -0,0 +1,23 @@
/* eslint-disable */
// rename this file from _test_[name] to test_[name] to activate
// and remove above this line
QUnit.test("test: Exchange Rate Revaluation", function (assert) {
let done = assert.async();
// number of asserts
assert.expect(1);
frappe.run_serially([
// insert a new Exchange Rate Revaluation
() => frappe.tests.make('Exchange Rate Revaluation', [
// values to be set
{key: 'value'}
]),
() => {
assert.equal(cur_frm.doc.key, 'value');
},
() => done()
]);
});

View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
import frappe
import unittest
class TestExchangeRateRevaluation(unittest.TestCase):
pass

View File

@ -0,0 +1,446 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2018-04-13 18:30:06.110433",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Account",
"length": 0,
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "party_type",
"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": "Party Type",
"length": 0,
"no_copy": 0,
"options": "DocType",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "party",
"fieldtype": "Dynamic 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": "Party",
"length": 0,
"no_copy": 0,
"options": "party_type",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_2",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "account_currency",
"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": "Account Currency",
"length": 0,
"no_copy": 0,
"options": "Currency",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "balance_in_account_currency",
"fieldtype": "Currency",
"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": "Balance In Account Currency",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "balances",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "current_exchange_rate",
"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": "Current Exchange Rate",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "balance_in_base_currency",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Balance In Base Currency",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_9",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "new_exchange_rate",
"fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "New Exchange Rate",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "new_balance_in_base_currency",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "New Balance In Base Currency",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "gain_loss",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Gain/Loss",
"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
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2018-05-05 17:03:03.512559",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Exchange Rate Revaluation Account",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
}

View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
class ExchangeRateRevaluationAccount(Document):
pass

View File

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

View File

@ -0,0 +1,133 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 0,
"autoname": "field:finance_book_name",
"beta": 0,
"creation": "2018-04-13 17:42:43.252224",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "Document",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "finance_book_name",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Name",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "fa fa-book",
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-05-09 14:55:01.394387",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Finance Book",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 0
},
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Auditor",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 0
}
],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"search_fields": "finance_book_name",
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 1
}

View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
class FinanceBook(Document):
pass

View File

@ -2,15 +2,15 @@
// rename this file from _test_[name] to test_[name] to activate
// and remove above this line
QUnit.test("test: Supplier Type", function (assert) {
QUnit.test("test: Finance Book", function (assert) {
let done = assert.async();
// number of asserts
assert.expect(1);
frappe.run_serially([
// insert a new Supplier Type
() => frappe.tests.make('Supplier Type', [
// insert a new Finance Book
() => frappe.tests.make('Finance Book', [
// values to be set
{key: 'value'}
]),

View File

@ -6,5 +6,5 @@ from __future__ import unicode_literals
import frappe
import unittest
class TestHealthInsurance(unittest.TestCase):
class TestFinanceBook(unittest.TestCase):
pass

View File

@ -41,6 +41,7 @@
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -72,6 +73,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -104,6 +106,7 @@
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -134,6 +137,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -164,6 +168,7 @@
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -196,6 +201,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -229,6 +235,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -262,6 +269,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -293,6 +301,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -324,6 +333,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -355,6 +365,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -386,6 +397,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -418,6 +430,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -450,6 +463,7 @@
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -482,6 +496,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -514,6 +529,7 @@
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -545,6 +561,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -576,6 +593,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -608,6 +626,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -640,6 +659,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -672,6 +692,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -704,6 +725,39 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "finance_book",
"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": "Finance Book",
"length": 0,
"no_copy": 0,
"options": "Finance Book",
"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
}
],
@ -718,7 +772,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-12-20 12:40:09.611951",
"modified": "2018-04-23 02:15:22.297509",
"modified_by": "Administrator",
"module": "Accounts",
"name": "GL Entry",
@ -726,7 +780,6 @@
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
@ -746,7 +799,6 @@
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
@ -766,7 +818,6 @@
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,

View File

@ -37,6 +37,55 @@ frappe.ui.form.on("Journal Entry", {
// hide /unhide fields based on currency
erpnext.journal_entry.toggle_fields_based_on_currency(frm);
if ((frm.doc.voucher_type == "Inter Company Journal Entry") && (frm.doc.docstatus == 1) && (!frm.doc.inter_company_journal_entry_reference)) {
frm.add_custom_button(__("Make Inter Company Journal Entry"),
function() {
frm.trigger("make_inter_company_journal_entry");
}
);
}
},
make_inter_company_journal_entry: function(frm) {
var d = new frappe.ui.Dialog({
title: __("Select Company"),
fields: [
{
'fieldname': 'company',
'fieldtype': 'Link',
'label': __('Company'),
'options': 'Company',
"get_query": function () {
return {
filters: [
["Company", "name", "!=", frm.doc.company]
]
};
},
'reqd': 1
}
],
});
d.set_primary_action(__("Make"), function() {
d.hide();
var args = d.get_values();
frappe.call({
args: {
"name": frm.doc.name,
"voucher_type": frm.doc.voucher_type,
"company": args.company
},
method: "erpnext.accounts.doctype.journal_entry.journal_entry.make_inter_company_journal_entry",
callback: function (r) {
if (r.message) {
var doc = frappe.model.sync(r.message)[0];
frappe.set_route("Form", doc.doctype, doc.name);
}
}
});
});
d.show();
},
multi_currency: function(frm) {
@ -549,9 +598,15 @@ $.extend(erpnext.journal_entry, {
},
account_query: function(frm) {
var inter_company = 0;
if (frm.doc.voucher_type == "Inter Company Journal Entry") {
inter_company = 1;
}
var filters = {
company: frm.doc.company,
is_group: 0
is_group: 0,
inter_company_account: inter_company
};
if(!frm.doc.multi_currency) {
$.extend(filters, {

View File

@ -96,7 +96,7 @@
"no_copy": 0,
"oldfieldname": "voucher_type",
"oldfieldtype": "Select",
"options": "Journal Entry\nBank Entry\nCash Entry\nCredit Card Entry\nDebit Note\nCredit Note\nContra Entry\nExcise Entry\nWrite Off Entry\nOpening Entry\nDepreciation Entry",
"options": "Journal Entry\nInter Company Journal Entry\nBank Entry\nCash Entry\nCredit Card Entry\nDebit Note\nCredit Note\nContra Entry\nExcise Entry\nWrite Off Entry\nOpening Entry\nDepreciation Entry\nExchange Rate Revaluation",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
@ -238,6 +238,38 @@
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "finance_book",
"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": "Finance Book",
"length": 0,
"no_copy": 0,
"options": "Finance Book",
"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_on_submit": 0,
@ -830,7 +862,7 @@
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
@ -841,6 +873,39 @@
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.voucher_type== \"Inter Company Journal Entry\"",
"fieldname": "inter_company_journal_entry_reference",
"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": "Inter Company Journal Entry Reference",
"length": 0,
"no_copy": 0,
"options": "Journal Entry",
"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_on_submit": 0,
@ -1520,7 +1585,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2018-04-30 17:34:38.429196",
"modified": "2018-05-09 14:56:08.687994",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry",

View File

@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe, erpnext, json
from frappe.utils import cstr, flt, fmt_money, formatdate, getdate
from frappe.utils import cstr, flt, fmt_money, formatdate, getdate, nowdate, cint
from frappe import msgprint, _, scrub
from erpnext.controllers.accounts_controller import AccountsController
from erpnext.accounts.utils import get_balance_on, get_account_currency
@ -40,15 +40,17 @@ class JournalEntry(AccountsController):
self.validate_credit_debit_note()
self.validate_empty_accounts_table()
self.set_account_and_party_balance()
self.validate_inter_company_accounts()
if not self.title:
self.title = self.get_title()
def on_submit(self):
self.check_credit_limit()
self.make_gl_entries()
self.update_loan()
self.update_advance_paid()
self.update_expense_claim()
self.update_loan()
self.update_inter_company_jv()
def get_title(self):
return self.pay_to_recd_from or self.accounts[0].account
@ -64,6 +66,20 @@ class JournalEntry(AccountsController):
for voucher_no in list(set(order_list)):
frappe.get_doc(voucher_type, voucher_no).set_total_advance_paid()
def validate_inter_company_accounts(self):
if self.voucher_type == "Inter Company Journal Entry" and self.inter_company_journal_entry_reference:
doc = frappe.get_doc("Journal Entry", self.inter_company_journal_entry_reference)
account_currency = frappe.db.get_value("Company", self.company, "default_currency")
previous_account_currency = frappe.db.get_value("Company", doc.company, "default_currency")
if account_currency == previous_account_currency:
if self.total_credit != doc.total_debit or self.total_debit != doc.total_credit:
frappe.throw(_("Total Credit/ Debit Amount should be same as linked Journal Entry"))
def update_inter_company_jv(self):
if self.voucher_type == "Inter Company Journal Entry" and self.inter_company_journal_entry_reference:
frappe.db.set_value("Journal Entry", self.inter_company_journal_entry_reference,\
"inter_company_journal_entry_reference", self.name)
def on_cancel(self):
from erpnext.accounts.utils import unlink_ref_doc_from_payment_entries
from erpnext.hr.doctype.salary_slip.salary_slip import unlink_ref_doc_from_salary_slip
@ -75,6 +91,8 @@ class JournalEntry(AccountsController):
self.update_loan()
self.unlink_advance_entry_reference()
self.unlink_asset_reference()
self.unlink_inter_company_jv()
self.unlink_asset_adjustment_entry()
def unlink_advance_entry_reference(self):
for d in self.get("accounts"):
@ -92,11 +110,25 @@ class JournalEntry(AccountsController):
for s in asset.get("schedules"):
if s.journal_entry == self.name:
s.db_set("journal_entry", None)
asset.value_after_depreciation += s.depreciation_amount
asset.db_set("value_after_depreciation", asset.value_after_depreciation)
idx = cint(s.finance_book_id) or 1
finance_books = asset.get('finance_books')[idx - 1]
finance_books.value_after_depreciation += s.depreciation_amount
finance_books.db_update()
asset.set_status()
def unlink_inter_company_jv(self):
if self.voucher_type == "Inter Company Journal Entry" and self.inter_company_journal_entry_reference:
frappe.db.set_value("Journal Entry", self.inter_company_journal_entry_reference,\
"inter_company_journal_entry_reference", "")
frappe.db.set_value("Journal Entry", self.name,\
"inter_company_journal_entry_reference", "")
def unlink_asset_adjustment_entry(self):
frappe.db.sql(""" update `tabAsset Adjustment`
set journal_entry = null where journal_entry = %s""", self.name)
def validate_party(self):
for d in self.get("accounts"):
account_type = frappe.db.get_value("Account", d.account, "account_type")
@ -127,7 +159,7 @@ class JournalEntry(AccountsController):
if (d.party_type == 'Customer' and flt(d.credit) > 0) or \
(d.party_type == 'Supplier' and flt(d.debit) > 0):
if d.is_advance=="No":
msgprint(_("Row {0}: Please check 'Is Advance' against Account {1} if this is an advance entry.").format(d.idx, d.account), alert=1)
msgprint(_("Row {0}: Please check 'Is Advance' against Account {1} if this is an advance entry.").format(d.idx, d.account), alert=True)
elif d.reference_type in ("Sales Order", "Purchase Order") and d.is_advance != "Yes":
frappe.throw(_("Row {0}: Payment against Sales/Purchase Order should always be marked as advance").format(d.idx))
@ -436,7 +468,8 @@ class JournalEntry(AccountsController):
"against_voucher": d.reference_name,
"remarks": self.remark,
"cost_center": d.cost_center,
"project": d.project
"project": d.project,
"finance_book": self.finance_book
})
)
@ -908,3 +941,12 @@ def get_average_exchange_rate(account):
exchange_rate = bank_balance_in_company_currency / bank_balance_in_account_currency
return exchange_rate
@frappe.whitelist()
def make_inter_company_journal_entry(name, voucher_type, company):
journal_entry = frappe.new_doc('Journal Entry')
journal_entry.voucher_type = voucher_type
journal_entry.company = company
journal_entry.posting_date = nowdate()
journal_entry.inter_company_journal_entry_reference = name
return journal_entry.as_dict()

View File

@ -44,6 +44,7 @@
"reqd": 1,
"search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0,
"width": "250px"
},
@ -75,6 +76,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -107,6 +109,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -142,6 +145,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0,
"width": "180px"
},
@ -171,6 +175,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -201,6 +206,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -231,6 +237,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -262,6 +269,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -294,6 +302,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -325,6 +334,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -354,6 +364,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -384,6 +395,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -413,6 +425,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -444,6 +457,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -477,6 +491,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -505,6 +520,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -536,6 +552,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -569,6 +586,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -598,6 +616,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -618,7 +637,7 @@
"label": "Reference Type",
"length": 0,
"no_copy": 0,
"options": "\nSales Invoice\nPurchase Invoice\nJournal Entry\nSales Order\nPurchase Order\nExpense Claim\nAsset\nLoan\nPayroll Entry\nEmployee Advance",
"options": "\nSales Invoice\nPurchase Invoice\nJournal Entry\nSales Order\nPurchase Order\nExpense Claim\nAsset\nLoan\nPayroll Entry\nEmployee Advance\nExchange Rate Revaluation",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@ -629,6 +648,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -660,6 +680,40 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.reference_type&&!in_list(doc.reference_type, ['Expense Claim', 'Asset', 'Employee Loan', 'Employee Advance'])",
"fieldname": "reference_due_date",
"fieldtype": "Select",
"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": "Reference Due Date",
"length": 0,
"no_copy": 0,
"options": "",
"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
},
{
@ -691,6 +745,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -719,6 +774,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -751,6 +807,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -782,6 +839,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}
],
@ -795,7 +853,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2017-12-07 19:54:19.851534",
"modified": "2018-05-05 17:50:25.961397",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry Account",

View File

@ -120,12 +120,12 @@ class OpeningInvoiceCreationTool(Document):
if party_type == "Customer":
party_doc.customer_name = party
else:
supplier_type = frappe.db.get_single_value("Buying Settings", "supplier_type")
if not supplier_type:
frappe.throw(_("Please Set Supplier Type in Buying Settings."))
supplier_group = frappe.db.get_single_value("Buying Settings", "supplier_group")
if not supplier_group:
frappe.throw(_("Please Set Supplier Group in Buying Settings."))
party_doc.supplier_name = party
party_doc.supplier_type = supplier_type
party_doc.supplier_group = supplier_group
party_doc.flags.ignore_mandatory = True
party_doc.save(ignore_permissions=True)

View File

@ -7,7 +7,7 @@ import frappe, erpnext, json
from frappe import _, scrub, ValidationError
from frappe.utils import flt, comma_or, nowdate
from erpnext.accounts.utils import get_outstanding_invoices, get_account_currency, get_balance_on
from erpnext.accounts.party import get_party_account
from erpnext.accounts.party import get_party_account, get_patry_tax_withholding_details
from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account
from erpnext.setup.utils import get_exchange_rate
from erpnext.accounts.general_ledger import make_gl_entries
@ -43,6 +43,7 @@ class PaymentEntry(AccountsController):
def validate(self):
self.setup_party_account_field()
self.set_tax_withholding()
self.set_missing_values()
self.validate_payment_type()
self.validate_party_details()
@ -511,6 +512,27 @@ class PaymentEntry(AccountsController):
self.reference_no = reference_doc.name
self.reference_date = nowdate()
def set_tax_withholding(self):
if self.party_type != 'Supplier':
return
self.supplier = self.party
tax_withholding_details = get_patry_tax_withholding_details(self)
for tax_details in tax_withholding_details:
if self.deductions:
if tax_details['tax']['account_head'] not in [deduction.account for deduction in self.deductions]:
self.append('deductions', self.calculate_deductions(tax_details))
else:
self.append('deductions', self.calculate_deductions(tax_details))
def calculate_deductions(self, tax_details):
return {
"account": tax_details['tax']['account_head'],
"cost_center": frappe.db.get_value("Company", self.company, "cost_center"),
"amount": self.total_allocated_amount * (tax_details['tax']['rate'] / 100)
}
@frappe.whitelist()
def get_outstanding_reference_documents(args):
if isinstance(args, string_types):

View File

@ -33,7 +33,7 @@ frappe.ui.form.on("Pricing Rule", "refresh", function(frm) {
${__("Pricing Rule is first selected based on 'Apply On' field, which can be Item, Item Group or Brand.")}
</li>
<li>
${__("Then Pricing Rules are filtered out based on Customer, Customer Group, Territory, Supplier, Supplier Type, Campaign, Sales Partner etc.")}
${__("Then Pricing Rules are filtered out based on Customer, Customer Group, Territory, Supplier, Supplier Group, Campaign, Sales Partner etc.")}
</li>
<li>
${__('Pricing Rules are further filtered based on quantity.')}
@ -51,7 +51,7 @@ frappe.ui.form.on("Pricing Rule", "refresh", function(frm) {
${__('Customer > Customer Group > Territory')}
</li>
<li>
${__('Supplier > Supplier Type')}
${__('Supplier > Supplier Group')}
</li>
</ul>
</li>
@ -75,7 +75,7 @@ cur_frm.cscript.set_options_for_applicable_for = function() {
options = $.merge(options, ["Customer", "Customer Group", "Territory", "Sales Partner", "Campaign"]);
}
if(cur_frm.doc.buying) {
$.merge(options, ["Supplier", "Supplier Type"]);
$.merge(options, ["Supplier", "Supplier Group"]);
}
set_field_options("applicable_for", options.join("\n"));

View File

@ -39,6 +39,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -69,6 +70,7 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -100,6 +102,7 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -131,6 +134,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -162,6 +166,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -193,6 +198,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -222,6 +228,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -253,6 +260,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -282,6 +290,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -311,6 +320,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -340,6 +350,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -369,6 +380,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -398,6 +410,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -419,7 +432,7 @@
"label": "Applicable For",
"length": 0,
"no_copy": 0,
"options": "\nCustomer\nCustomer Group\nTerritory\nSales Partner\nCampaign\nSupplier\nSupplier Type",
"options": "\nCustomer\nCustomer Group\nTerritory\nSales Partner\nCampaign\nSupplier\nSupplier Group",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
@ -429,6 +442,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -460,6 +474,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -491,6 +506,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -522,6 +538,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -553,6 +570,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -584,6 +602,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -615,6 +634,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -623,8 +643,8 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.applicable_for==\"Supplier Type\"",
"fieldname": "supplier_type",
"depends_on": "eval:doc.applicable_for==\"Supplier Group\"",
"fieldname": "supplier_group",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
@ -633,10 +653,10 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Supplier Type",
"label": "Supplier Group",
"length": 0,
"no_copy": 0,
"options": "Supplier Type",
"options": "Supplier Group",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
@ -646,6 +666,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -675,6 +696,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -704,6 +726,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -733,6 +756,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -762,6 +786,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -791,6 +816,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -821,6 +847,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -850,6 +877,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -878,6 +906,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -908,6 +937,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -940,6 +970,7 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -971,6 +1002,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -1003,6 +1035,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -1032,6 +1065,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -1064,6 +1098,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -1093,6 +1128,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -1124,6 +1160,7 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -1152,6 +1189,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -1182,6 +1220,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -1212,6 +1251,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -1243,6 +1283,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -1273,6 +1314,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -1302,6 +1344,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}
],
@ -1316,7 +1359,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-02-12 17:21:22.559996",
"modified": "2018-04-19 07:52:41.024618",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Pricing Rule",
@ -1324,7 +1367,6 @@
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@ -1344,7 +1386,6 @@
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@ -1364,7 +1405,6 @@
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@ -1384,7 +1424,6 @@
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@ -1404,7 +1443,6 @@
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,

View File

@ -41,7 +41,7 @@ class PricingRule(Document):
throw(_("Selling must be checked, if Applicable For is selected as {0}"
.format(self.applicable_for)))
if not self.buying and self.applicable_for in ["Supplier", "Supplier Type"]:
if not self.buying and self.applicable_for in ["Supplier", "Supplier Group"]:
throw(_("Buying must be checked, if Applicable For is selected as {0}"
.format(self.applicable_for)))
@ -85,7 +85,7 @@ def apply_pricing_rule(args):
"customer_group": "something",
"territory": "something",
"supplier": "something",
"supplier_type": "something",
"supplier_group": "something",
"currency": "something",
"conversion_rate": "something",
"price_list": "something",
@ -165,10 +165,10 @@ def get_pricing_rule_for_item(args):
if customer:
args.customer_group, args.territory = customer
args.supplier = args.supplier_type = None
args.supplier = args.supplier_group = None
elif args.supplier and not args.supplier_type:
args.supplier_type = frappe.db.get_value("Supplier", args.supplier, "supplier_type")
elif args.supplier and not args.supplier_group:
args.supplier_group = frappe.db.get_value("Supplier", args.supplier, "supplier_group")
args.customer = args.customer_group = args.territory = None
pricing_rules = get_pricing_rules(args)
@ -258,7 +258,7 @@ def get_pricing_rules(args):
conditions = item_variant_condition = ""
values = {"item_code": args.get("item_code"), "brand": args.get("brand")}
for field in ["company", "customer", "supplier", "supplier_type", "campaign", "sales_partner"]:
for field in ["company", "customer", "supplier", "supplier_group", "campaign", "sales_partner"]:
if args.get(field):
conditions += " and ifnull("+field+", '') in (%("+field+")s, '')"
values[field] = args.get(field)
@ -324,11 +324,11 @@ def filter_pricing_rules(args, pricing_rules):
# apply internal priority
all_fields = ["item_code", "item_group", "brand", "customer", "customer_group", "territory",
"supplier", "supplier_type", "campaign", "sales_partner", "variant_of"]
"supplier", "supplier_group", "campaign", "sales_partner", "variant_of"]
if len(pricing_rules) > 1:
for field_set in [["item_code", "variant_of", "item_group", "brand"],
["customer", "customer_group", "territory"], ["supplier", "supplier_type"]]:
["customer", "customer_group", "territory"], ["supplier", "supplier_group"]]:
remaining_fields = list(set(all_fields) - set(field_set))
if if_all_rules_same(pricing_rules, remaining_fields):
pricing_rules = apply_internal_priority(pricing_rules, field_set, args)

View File

@ -92,8 +92,21 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
})
}, __("Get items from"));
}
this.frm.toggle_reqd("supplier_warehouse", this.frm.doc.is_subcontracted==="Yes");
var me = this;
if (doc.docstatus == 1 && !doc.inter_company_invoice_reference) {
frappe.model.with_doc("Supplier", me.frm.doc.supplier, function() {
var supplier = frappe.model.get_doc("Supplier", me.frm.doc.supplier);
var internal = supplier.is_internal_supplier;
var disabled = supplier.disabled;
if (internal == 1 && disabled == 0) {
me.frm.add_custom_button("Inter Company Invoice", function() {
me.make_inter_company_invoice(me.frm);
}, __("Make"));
}
});
}
},
supplier: function() {
@ -133,6 +146,13 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
}
},
make_inter_company_invoice: function(frm) {
frappe.model.open_mapped_doc({
method: "erpnext.accounts.doctype.purchase_invoice.purchase_invoice.make_inter_company_sales_invoice",
frm: frm
});
},
is_paid: function() {
hide_fields(this.frm.doc);
if(cint(this.frm.doc.is_paid)) {
@ -185,9 +205,10 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
var row = locals[cdt][cdn];
if(row.asset) {
frappe.call({
method: "erpnext.accounts.doctype.purchase_invoice.purchase_invoice.get_fixed_asset_account",
method: "erpnext.assets.doctype.asset_category.asset_category.get_asset_category_account",
args: {
"asset": row.asset,
"fieldname": "fixed_asset_account",
"account": row.expense_account
},
callback: function(r, rt) {

View File

@ -3805,6 +3805,38 @@
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "inter_company_invoice_reference",
"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": "Inter Company Invoice Reference",
"length": 0,
"no_copy": 0,
"options": "Sales Invoice",
"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_on_submit": 0,
@ -4040,7 +4072,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2018-03-10 07:33:12.760250",
"modified": "2018-04-19 15:48:29.457594",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",
@ -4049,7 +4081,6 @@
"permissions": [
{
"amend": 1,
"apply_user_permissions": 0,
"cancel": 1,
"create": 1,
"delete": 0,
@ -4069,7 +4100,6 @@
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
@ -4089,7 +4119,6 @@
},
{
"amend": 1,
"apply_user_permissions": 0,
"cancel": 1,
"create": 1,
"delete": 1,
@ -4109,7 +4138,6 @@
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
@ -4129,7 +4157,6 @@
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,

View File

@ -8,7 +8,7 @@ from frappe import _, throw
import frappe.defaults
from erpnext.controllers.buying_controller import BuyingController
from erpnext.accounts.party import get_party_account, get_due_date
from erpnext.accounts.party import get_party_account, get_due_date, get_patry_tax_withholding_details
from erpnext.accounts.utils import get_account_currency, get_fiscal_year
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import update_billed_amount_based_on_po
from erpnext.stock import get_warehouse_account_map
@ -17,6 +17,9 @@ from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt
from erpnext.buying.utils import check_for_closed_status
from erpnext.accounts.general_ledger import get_round_off_account_and_cost_center
from frappe.model.mapper import get_mapped_doc
from erpnext.accounts.doctype.sales_invoice.sales_invoice import validate_inter_company_party, update_linked_invoice,\
unlink_inter_company_invoice
from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account
form_grid_templates = {
"items": "templates/form_grid/item_grid.html"
@ -43,6 +46,7 @@ class PurchaseInvoice(BuyingController):
self.is_opening = 'No'
self.validate_posting_time()
self.set_tax_withholding()
super(PurchaseInvoice, self).validate()
if not self.is_return:
@ -50,7 +54,6 @@ class PurchaseInvoice(BuyingController):
self.pr_required()
self.validate_supplier_invoice()
# validate cash purchase
if (self.is_paid == 1):
self.validate_cash()
@ -73,6 +76,7 @@ class PurchaseInvoice(BuyingController):
self.validate_fixed_asset_account()
self.create_remarks()
self.set_status()
validate_inter_company_party(self.doctype, self.supplier, self.company, self.inter_company_invoice_reference)
def validate_cash(self):
if not self.cash_bank_account and flt(self.paid_amount):
@ -164,7 +168,6 @@ class PurchaseInvoice(BuyingController):
super(PurchaseInvoice, self).validate_warehouse()
def validate_item_code(self):
for d in self.get('items'):
if not d.item_code:
@ -302,22 +305,7 @@ class PurchaseInvoice(BuyingController):
self.make_gl_entries()
self.update_project()
self.update_fixed_asset()
def update_fixed_asset(self):
for d in self.get("items"):
if d.is_fixed_asset:
asset = frappe.get_doc("Asset", d.asset)
if self.docstatus==1:
asset.purchase_invoice = self.name
asset.purchase_date = self.posting_date
asset.supplier = self.supplier
else:
asset.purchase_invoice = None
asset.supplier = None
asset.flags.ignore_validate_update_after_submit = True
asset.save()
update_linked_invoice(self.doctype, self.name, self.inter_company_invoice_reference)
def make_gl_entries(self, gl_entries=None, repost_future_gle=True, from_repost=False):
if not self.grand_total:
@ -434,6 +422,50 @@ class PurchaseInvoice(BuyingController):
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
"credit": flt(item.rm_supp_cost)
}, warehouse_account[self.supplier_warehouse]["account_currency"]))
elif item.is_fixed_asset:
asset_accounts = self.get_company_default(["asset_received_but_not_billed",
"expenses_included_in_asset_valuation", "capital_work_in_progress_account"])
asset_amount = flt(item.net_amount) + flt(item.item_tax_amount/self.conversion_rate)
base_asset_amount = flt(item.base_net_amount + item.item_tax_amount)
if not self.update_stock:
asset_rbnb_currency = get_account_currency(asset_accounts[0])
gl_entries.append(self.get_gl_dict({
"account": asset_accounts[0],
"against": self.supplier,
"remarks": self.get("remarks") or _("Accounting Entry for Asset"),
"debit": base_asset_amount,
"debit_in_account_currency": (base_asset_amount
if asset_rbnb_currency == self.company_currency else asset_amount)
}))
else:
cwip_account = get_asset_category_account(item.asset,
'capital_work_in_progress_account') or asset_accounts[2]
cwip_account_currency = get_account_currency(cwip_account)
gl_entries.append(self.get_gl_dict({
"account": cwip_account,
"against": self.supplier,
"remarks": self.get("remarks") or _("Accounting Entry for Asset"),
"debit": base_asset_amount,
"debit_in_account_currency": (base_asset_amount
if cwip_account_currency == self.company_currency else asset_amount)
}))
if item.item_tax_amount:
asset_eiiav_currency = get_account_currency(asset_accounts[0])
gl_entries.append(self.get_gl_dict({
"account": asset_accounts[1],
"against": self.supplier,
"remarks": self.get("remarks") or _("Accounting Entry for Asset"),
"cost_center": item.cost_center,
"credit": item.item_tax_amount,
"credit_in_account_currency": (item.item_tax_amount
if asset_eiiav_currency == self.company_currency else
item.item_tax_amount / self.conversion_rate)
}))
else:
gl_entries.append(
self.get_gl_dict({
@ -632,9 +664,10 @@ class PurchaseInvoice(BuyingController):
self.make_gl_entries_on_cancel()
self.update_project()
self.update_fixed_asset()
frappe.db.set(self, 'status', 'Cancelled')
unlink_inter_company_invoice(self.doctype, self.name, self.inter_company_invoice_reference)
def update_project(self):
project_list = []
for d in self.items:
@ -697,25 +730,25 @@ class PurchaseInvoice(BuyingController):
def on_recurring(self, reference_doc, auto_repeat_doc):
self.due_date = None
def set_tax_withholding(self):
"""
1. Get TDS Configurations against Supplier
"""
tax_withholding_details = get_patry_tax_withholding_details(self)
for tax_details in tax_withholding_details:
if flt(self.get("rounded_total") or self.grand_total) >= flt(tax_details['threshold']):
if self.taxes:
if tax_details['tax']['description'] not in [tax.description for tax in self.taxes]:
self.append('taxes', tax_details['tax'])
else:
self.append('taxes', tax_details['tax'])
@frappe.whitelist()
def make_debit_note(source_name, target_doc=None):
from erpnext.controllers.sales_and_purchase_return import make_return_doc
return make_return_doc("Purchase Invoice", source_name, target_doc)
@frappe.whitelist()
def get_fixed_asset_account(asset, account=None):
if account:
if frappe.db.get_value("Account", account, "account_type") != "Fixed Asset":
account=None
if not account:
asset_category, company = frappe.db.get_value("Asset", asset, ["asset_category", "company"])
account = frappe.db.get_value("Asset Category Account",
filters={"parent": asset_category, "company_name": company}, fieldname="fixed_asset_account")
return account
@frappe.whitelist()
def make_stock_entry(source_name, target_doc=None):
doc = get_mapped_doc("Purchase Invoice", source_name, {
@ -734,3 +767,8 @@ def make_stock_entry(source_name, target_doc=None):
}, target_doc)
return doc
@frappe.whitelist()
def make_inter_company_sales_invoice(source_name, target_doc=None):
from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_inter_company_invoice
return make_inter_company_invoice("Purchase Invoice", source_name, target_doc)

View File

@ -2258,7 +2258,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2018-02-22 15:15:25.297672",
"modified": "2018-04-23 14:07:33.576495",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice Item",

View File

@ -101,6 +101,19 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
}
this.set_default_print_format();
var me = this;
if (doc.docstatus == 1 && !doc.inter_company_invoice_reference) {
frappe.model.with_doc("Customer", me.frm.doc.customer, function() {
var customer = frappe.model.get_doc("Customer", me.frm.doc.customer);
var internal = customer.is_internal_customer;
var disabled = customer.disabled;
if (internal == 1 && disabled == 0) {
me.frm.add_custom_button("Inter Company Invoice", function() {
me.make_inter_company_invoice();
}, __("Make"));
}
});
}
},
on_submit: function(doc, dt, dn) {
@ -201,11 +214,9 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
tc_name: function() {
this.get_terms();
},
customer: function() {
var me = this;
if(this.frm.updating_party_details) return;
erpnext.utils.get_party_details(this.frm,
"erpnext.accounts.party.get_party_details", {
posting_date: this.frm.doc.posting_date,
@ -218,6 +229,13 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
})
},
make_inter_company_invoice: function() {
frappe.model.open_mapped_doc({
method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.make_inter_company_purchase_invoice",
frm: me.frm
});
},
debit_to: function() {
var me = this;
if(this.frm.doc.debit_to) {
@ -621,4 +639,3 @@ var calculate_total_billing_amount = function(frm) {
refresh_field('total_billing_amount')
}

View File

@ -42,6 +42,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -73,6 +74,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -105,6 +107,7 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 1,
"translatable": 0,
"unique": 0
},
{
@ -137,6 +140,7 @@
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -170,6 +174,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -200,6 +205,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -232,6 +238,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -263,6 +270,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -295,6 +303,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -325,6 +334,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -354,6 +364,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -386,6 +397,7 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -418,6 +430,7 @@
"reqd": 1,
"search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -449,6 +462,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -480,6 +494,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -511,6 +526,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -543,6 +559,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -574,6 +591,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -605,6 +623,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -637,6 +656,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -668,6 +688,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -698,6 +719,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -727,6 +749,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -757,6 +780,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -788,6 +812,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -818,6 +843,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -847,6 +873,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -877,6 +904,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -906,6 +934,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -935,6 +964,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -965,6 +995,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -996,6 +1027,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -1025,6 +1057,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -1056,6 +1089,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -1086,6 +1120,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -1117,6 +1152,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -1147,6 +1183,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -1178,6 +1215,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -1210,6 +1248,7 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -1243,6 +1282,7 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -1271,6 +1311,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0,
"width": "50%"
},
@ -3946,6 +3987,38 @@
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "inter_company_invoice_reference",
"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": "Inter Company Invoice Reference",
"length": 0,
"no_copy": 0,
"options": "Purchase Invoice",
"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_on_submit": 0,
@ -4833,7 +4906,6 @@
"permissions": [
{
"amend": 1,
"apply_user_permissions": 0,
"cancel": 1,
"create": 1,
"delete": 1,
@ -4853,7 +4925,6 @@
},
{
"amend": 1,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 0,
@ -4873,7 +4944,6 @@
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
@ -4893,7 +4963,6 @@
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,

View File

@ -73,6 +73,7 @@ class SalesInvoice(SellingController):
self.validate_account_for_change_amount()
self.validate_fixed_asset()
self.set_income_account_for_fixed_assets()
validate_inter_company_party(self.doctype, self.customer, self.company, self.inter_company_invoice_reference)
if cint(self.is_pos):
self.validate_pos()
@ -146,6 +147,7 @@ class SalesInvoice(SellingController):
update_company_current_month_sales(self.company)
self.update_project()
update_linked_invoice(self.doctype, self.name, self.inter_company_invoice_reference)
def validate_pos_paid_amount(self):
if len(self.payments) == 0 and self.is_pos:
@ -186,6 +188,8 @@ class SalesInvoice(SellingController):
update_company_current_month_sales(self.company)
self.update_project()
unlink_inter_company_invoice(self.doctype, self.name, self.inter_company_invoice_reference)
def update_status_updater_args(self):
if cint(self.update_stock):
self.status_updater.extend([{
@ -336,7 +340,7 @@ class SalesInvoice(SellingController):
for item in self.get("items"):
if item.get('item_code'):
for fname, val in get_pos_profile_item_details(pos,
frappe._dict(item.as_dict()), pos, True).items():
frappe._dict(item.as_dict()), pos).items():
if (not for_validate) or (for_validate and not item.get(fname)):
item.set(fname, val)
@ -907,11 +911,48 @@ class SalesInvoice(SellingController):
project.update_billed_amount()
project.save()
def verify_payment_amount_is_positive(self):
for entry in self.payments:
if entry.amount < 0:
frappe.throw(_("Row #{0} (Payment Table): Amount must be positive").format(entry.idx))
def validate_inter_company_party(doctype, party, company, inter_company_invoice_reference):
if doctype == "Sales Invoice":
partytype, ref_partytype, internal = "Customer", "Supplier", "is_internal_customer"
ref_doc = "Purchase Invoice"
else:
partytype, ref_partytype, internal = "Supplier", "Customer", "is_internal_supplier"
ref_doc = "Sales Invoice"
if inter_company_invoice_reference:
doc = frappe.get_doc(ref_doc, inter_company_invoice_reference)
ref_party = doc.supplier if doctype == "Sales Invoice" else doc.customer
if not frappe.db.get_value(partytype, {"represents_company": doc.company}, "name") == party:
frappe.throw(_("Invalid {0} for Inter Company Invoice.").format(partytype))
if not frappe.db.get_value(ref_partytype, {"name": ref_party}, "represents_company") == company:
frappe.throw(_("Invalid Company for Inter Company Invoice."))
elif frappe.db.get_value(partytype, {"name": party, internal: 1}, "name") == party:
companies = frappe.db.sql("""select company from `tabAllowed To Transact With`
where parenttype = '{0}' and parent = '{1}'""".format(partytype, party), as_list = 1)
companies = [d[0] for d in companies]
if not company in companies:
frappe.throw(_("{0} not allowed to transact with {1}. Please change the Company.").format(partytype, company))
def update_linked_invoice(doctype, name, inter_company_invoice_reference):
if inter_company_invoice_reference:
frappe.db.set_value(doctype, inter_company_invoice_reference,\
"inter_company_invoice_reference", name)
def unlink_inter_company_invoice(doctype, name, inter_company_invoice_reference):
ref_doc = "Purchase Invoice" if doctype == "Sales Invoice" else "Sales Invoice"
if inter_company_invoice_reference:
frappe.db.set_value(doctype, name,\
"inter_company_invoice_reference", "")
frappe.db.set_value(ref_doc, inter_company_invoice_reference,\
"inter_company_invoice_reference", "")
def get_list_context(context=None):
from erpnext.controllers.website_list_for_contact import get_list_context
list_context = get_list_context(context)
@ -992,3 +1033,88 @@ def set_account_for_mode_of_payment(self):
for data in self.payments:
if not data.account:
data.account = get_bank_cash_account(data.mode_of_payment, self.company).get("account")
def get_inter_company_details(doc, doctype):
if doctype == "Sales Invoice":
party = frappe.db.get_value("Supplier", {"disabled": 0, "is_internal_supplier": 1, "represents_company": doc.company}, "name")
company = frappe.db.get_value("Customer", {"name": doc.customer}, "represents_company")
else:
party = frappe.db.get_value("Customer", {"disabled": 0, "is_internal_customer": 1, "represents_company": doc.company}, "name")
company = frappe.db.get_value("Supplier", {"name": doc.supplier}, "represents_company")
return {
"party": party,
"company": company
}
def validate_inter_company_invoice(doc, doctype):
details = get_inter_company_details(doc, doctype)
price_list = doc.selling_price_list if doctype == "Sales Invoice" else doc.buying_price_list
valid_price_list = frappe.db.get_value("Price List", {"name": price_list, "buying": 1, "selling": 1})
if not valid_price_list:
frappe.throw(_("Selected Price List should have buying and selling fields checked."))
party = details.get("party")
if not party:
partytype = "Supplier" if doctype == "Sales Invoice" else "Customer"
frappe.throw(_("No {0} found for Inter Company Transactions.").format(partytype))
company = details.get("company")
default_currency = frappe.db.get_value("Company", company, "default_currency")
if default_currency != doc.currency:
frappe.throw(_("Company currencies of both the companies should match for Inter Company Transactions."))
return
@frappe.whitelist()
def make_inter_company_purchase_invoice(source_name, target_doc=None):
return make_inter_company_invoice("Sales Invoice", source_name, target_doc)
def make_inter_company_invoice(doctype, source_name, target_doc=None):
if doctype == "Sales Invoice":
source_doc = frappe.get_doc("Sales Invoice", source_name)
target_doctype = "Purchase Invoice"
else:
source_doc = frappe.get_doc("Purchase Invoice", source_name)
target_doctype = "Sales Invoice"
validate_inter_company_invoice(source_doc, doctype)
details = get_inter_company_details(source_doc, doctype)
def set_missing_values(source, target):
target.run_method("set_missing_values")
def update_details(source_doc, target_doc, source_parent):
target_doc.inter_company_invoice_reference = source_doc.name
if target_doc.doctype == "Purchase Invoice":
target_doc.company = details.get("company")
target_doc.supplier = details.get("party")
target_doc.buying_price_list = source_doc.selling_price_list
else:
target_doc.company = details.get("company")
target_doc.customer = details.get("party")
target_doc.selling_price_list = source_doc.buying_price_list
doclist = get_mapped_doc(doctype, source_name, {
doctype: {
"doctype": target_doctype,
"postprocess": update_details,
"field_no_map": [
"taxes_and_charges"
]
},
doctype +" Item": {
"doctype": target_doctype + " Item",
"field_no_map": [
"income_account",
"expense_account",
"cost_center",
"warehouse"
]
}
}, target_doc, set_missing_values)
return doclist

View File

@ -2,7 +2,7 @@
// License: GNU General Public License v3. See license.txt
cur_frm.add_fetch("customer", "customer_group", "customer_group" );
cur_frm.add_fetch("supplier", "supplier_type", "supplier_type" );
cur_frm.add_fetch("supplier", "supplier_group_name", "supplier_group" );
frappe.ui.form.on("Tax Rule", "tax_type", function(frm) {
frm.toggle_reqd("sales_tax_template", frm.doc.tax_type=="Sales");

View File

@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 0,
"autoname": "TR.####",
@ -12,6 +13,7 @@
"editable_grid": 0,
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -40,9 +42,11 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -69,9 +73,11 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -97,9 +103,11 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -128,9 +136,11 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -159,9 +169,11 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -188,9 +200,11 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -219,9 +233,11 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -250,9 +266,11 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -279,9 +297,11 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -308,9 +328,11 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -337,9 +359,11 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -367,9 +391,11 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -395,9 +421,11 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -426,15 +454,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.tax_type==\"Purchase\"",
"fieldname": "supplier_type",
"fieldname": "supplier_group",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
@ -443,10 +473,10 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Supplier Type",
"label": "Supplier Group",
"length": 0,
"no_copy": 0,
"options": "Supplier Type",
"options": "Supplier Group",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@ -457,9 +487,11 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -486,9 +518,11 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -515,9 +549,11 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -544,9 +580,11 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -574,9 +612,11 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -603,9 +643,11 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -632,9 +674,11 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -660,9 +704,11 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -689,9 +735,11 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -717,9 +765,11 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -747,9 +797,11 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -775,9 +827,11 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -805,20 +859,21 @@
"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,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-02-17 16:22:42.501765",
"modified": "2018-04-19 07:53:43.020808",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Tax Rule",
@ -827,7 +882,6 @@
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,

View File

@ -30,7 +30,7 @@ class TaxRule(Document):
def validate_tax_template(self):
if self.tax_type== "Sales":
self.purchase_tax_template = self.supplier = self.supplier_type = None
self.purchase_tax_template = self.supplier = self.supplier_group = None
if self.customer:
self.customer_group = None
@ -38,7 +38,7 @@ class TaxRule(Document):
self.sales_tax_template = self.customer = self.customer_group = None
if self.supplier:
self.supplier_type = None
self.supplier_group = None
if not (self.sales_tax_template or self.purchase_tax_template):
frappe.throw(_("Tax Template is mandatory."))
@ -53,7 +53,7 @@ class TaxRule(Document):
"customer": self.customer,
"customer_group": self.customer_group,
"supplier": self.supplier,
"supplier_type": self.supplier_type,
"supplier_group": self.supplier_group,
"billing_city": self.billing_city,
"billing_county": self.billing_county,
"billing_state": self.billing_state,

View File

@ -0,0 +1,105 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2018-04-13 18:43:14.898336",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "company",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Company",
"length": 0,
"no_copy": 0,
"options": "Company",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Account",
"length": 0,
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2018-04-13 18:44:25.055382",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Tax Withholding Account",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
}

View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
class TaxWithholdingAccount(Document):
pass

View File

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

View File

@ -0,0 +1,409 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
"autoname": "Prompt",
"beta": 0,
"creation": "2018-04-13 18:42:06.431683",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "is_default",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Is Default",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "enabled",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Enabled",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "percent_of_tax_withheld",
"fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Percent of Tax Withheld",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "threshold",
"fieldtype": "Currency",
"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": "Threshold",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_3",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "book_on_invoice",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Book on Invoice",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "book_on_advance",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Book on Advance",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "withhold_cumulative_tax_amount",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Withhold Cumulative Tax Amount On First Invoice After Threshold",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_7",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "accounts",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Accounts",
"length": 0,
"no_copy": 0,
"options": "Tax Withholding 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,
"translatable": 0,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-05-11 14:25:07.474461",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Tax Withholding Category",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
}

View File

@ -0,0 +1,13 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
class TaxWithholdingCategory(Document):
def validate(self):
if not frappe.db.get_value("Tax Withholding Category",
{"is_default": 1, "name": ("!=", self.name)}, "name"):
self.is_default = 1

View File

@ -0,0 +1,23 @@
/* eslint-disable */
// rename this file from _test_[name] to test_[name] to activate
// and remove above this line
QUnit.test("test: Tax Withholding Category", function (assert) {
let done = assert.async();
// number of asserts
assert.expect(1);
frappe.run_serially([
// insert a new Tax Withholding Category
() => frappe.tests.make('Tax Withholding Category', [
// values to be set
{key: 'value'}
]),
() => {
assert.equal(cur_frm.doc.key, 'value');
},
() => done()
]);
});

View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
import frappe
import unittest
class TestTaxWithholdingCategory(unittest.TestCase):
pass

View File

@ -47,7 +47,7 @@ def _get_party_details(party=None, account=None, party_type="Customer", company=
set_contact_details(out, party, party_type)
set_other_values(out, party, party_type)
set_price_list(out, party, party_type, price_list)
out["taxes_and_charges"] = set_taxes(party.name, party_type, posting_date, company, out.customer_group, out.supplier_type)
out["taxes_and_charges"] = set_taxes(party.name, party_type, posting_date, company, out.customer_group, out.supplier_group)
out["payment_terms_template"] = get_pyt_term_template(party.name, party_type, company)
if not out.get("currency"):
@ -105,7 +105,7 @@ def set_other_values(out, party, party_type):
if party_type=="Customer":
to_copy = ["customer_name", "customer_group", "territory", "language"]
else:
to_copy = ["supplier_name", "supplier_type", "language"]
to_copy = ["supplier_name", "supplier_group", "language"]
for f in to_copy:
out[f] = party.get(f)
@ -169,7 +169,7 @@ def set_account_and_due_date(party, account, party_type, company, posting_date,
def get_party_account(party_type, party, company):
"""Returns the account for the given `party`.
Will first search in party (Customer / Supplier) record, if not found,
will search in group (Customer Group / Supplier Type),
will search in group (Customer Group / Supplier Group),
finally will return default."""
if not company:
frappe.throw(_("Please select a Company"))
@ -181,7 +181,7 @@ def get_party_account(party_type, party, company):
{"parenttype": party_type, "parent": party, "company": company}, "account")
if not account and party_type in ['Customer', 'Supplier']:
party_group_doctype = "Customer Group" if party_type=="Customer" else "Supplier Type"
party_group_doctype = "Customer Group" if party_type=="Customer" else "Supplier Group"
group = frappe.db.get_value(party_type, party, scrub(party_group_doctype))
account = frappe.db.get_value("Party Account",
{"parenttype": party_group_doctype, "parent": group, "company": company}, "account")
@ -274,8 +274,8 @@ def get_due_date(posting_date, party_type, party, company=None, bill_date=None):
due_date = get_due_date_from_template(template_name, posting_date, bill_date).strftime("%Y-%m-%d")
else:
if party_type == "Supplier":
supplier_type = frappe.db.get_value(party_type, party, fieldname="supplier_type")
template_name = frappe.db.get_value("Supplier Type", supplier_type, fieldname="payment_terms")
supplier_group = frappe.db.get_value(party_type, party, fieldname="supplier_group")
template_name = frappe.db.get_value("Supplier Group", supplier_group, fieldname="payment_terms")
if template_name:
due_date = get_due_date_from_template(template_name, posting_date, bill_date).strftime("%Y-%m-%d")
# If due date is calculated from bill_date, check this condition
@ -321,7 +321,7 @@ def validate_due_date(posting_date, due_date, party_type, party, company=None, b
.format(formatdate(default_due_date)))
@frappe.whitelist()
def set_taxes(party, party_type, posting_date, company, customer_group=None, supplier_type=None,
def set_taxes(party, party_type, posting_date, company, customer_group=None, supplier_group=None,
billing_address=None, shipping_address=None, use_for_shopping_cart=None):
from erpnext.accounts.doctype.tax_rule.tax_rule import get_tax_template, get_party_details
args = {
@ -332,8 +332,8 @@ def set_taxes(party, party_type, posting_date, company, customer_group=None, sup
if customer_group:
args['customer_group'] = customer_group
if supplier_type:
args['supplier_type'] = supplier_type
if supplier_group:
args['supplier_group'] = supplier_group
if billing_address or shipping_address:
args.update(get_party_details(party, party_type, {"billing_address": billing_address, \
@ -371,10 +371,10 @@ def get_pyt_term_template(party_name, party_type, company=None):
customer.customer_group, fieldname='payment_terms')
else:
supplier = frappe.db.get_value("Supplier", party_name,
fieldname=['payment_terms', "supplier_type"], as_dict=1)
fieldname=['payment_terms', "supplier_group"], as_dict=1)
template = supplier.payment_terms
if not template and supplier.supplier_type:
template = frappe.db.get_value("Supplier Type", supplier.supplier_type, fieldname='payment_terms')
if not template and supplier.supplier_group:
template = frappe.db.get_value("Supplier Group", supplier.supplier_group, fieldname='payment_terms')
if not template and company:
template = frappe.db.get_value("Company", company, fieldname='payment_terms')
@ -448,7 +448,6 @@ def get_dashboard_info(party_type, party):
return info
def get_party_shipping_address(doctype, name):
"""
Returns an Address name (best guess) for the given doctype and name for which `address_type == 'Shipping'` is true.
@ -476,3 +475,60 @@ def get_party_shipping_address(doctype, name):
return out[0][0]
else:
return ''
def get_patry_tax_withholding_details(ref_doc):
supplier = frappe.get_doc("Supplier", ref_doc.supplier)
tax_withholding_details = []
print(supplier)
for tax in supplier.tax_withholding_config:
tax_mapper = get_tax_mapper()
set_tax_withholding_details(tax_mapper, ref_doc, tax_withholding_category=tax.tax_withholding_category)
if tax.valid_till and date_diff(tax.valid_till, ref_doc.posting_date) > 0:
tax_mapper.update({
"rate": tax.applicable_percentage
})
prepare_tax_withholding_details(tax_mapper, tax_withholding_details)
return tax_withholding_details
def prepare_tax_withholding_details(tax_mapper, tax_withholding_details):
if tax_mapper.get('account_head'):
tax_withholding_details.append({
"threshold": tax_mapper['threshold'],
"tax": tax_mapper
})
del tax_mapper['threshold']
def set_tax_withholding_details(tax_mapper, ref_doc, tax_withholding_category=None, use_default=0):
if tax_withholding_category:
tax_withholding = frappe.get_doc("Tax Withholding Category", tax_withholding_category)
else:
tax_withholding = frappe.get_doc("Tax Withholding Category", {'is_default': 1, 'enabled': 1})
if tax_withholding.book_on_invoice and ref_doc.doctype=='Purchase Invoice' \
or tax_withholding.book_on_advance and ref_doc.doctype in ('Payment Entry', 'Journal Entry'):
for account_detail in tax_withholding.accounts:
if ref_doc.company == account_detail.company:
tax_mapper.update({
"account_head": account_detail.account,
"rate": tax_withholding.percent_of_tax_withheld,
"threshold": tax_withholding.threshold,
"description": tax_withholding.name
})
def get_tax_mapper():
return {
"category": "Total",
"add_deduct_tax": "Deduct",
"charge_type": "On Net Total",
"rate": 0,
"description": '',
"account_head": '',
"threshold": 0.0
}

View File

@ -10,6 +10,12 @@ frappe.query_reports["Accounts Payable"] = {
"options": "Company",
"default": frappe.defaults.get_user_default("Company")
},
{
"fieldname":"finance_book",
"label": __("Finance Book"),
"fieldtype": "Link",
"options": "Finance Book"
},
{
"fieldname":"supplier",
"label": __("Supplier"),

View File

@ -10,6 +10,12 @@ frappe.query_reports["Accounts Receivable"] = {
"options": "Company",
"default": frappe.defaults.get_user_default("Company")
},
{
"fieldname":"finance_book",
"label": __("Finance Book"),
"fieldtype": "Link",
"options": "Finance Book"
},
{
"fieldname":"customer",
"label": __("Customer"),

View File

@ -112,7 +112,7 @@ class ReceivablePayableReport(object):
_("Customer Group") + ":Link/Customer Group:120"
]
if args.get("party_type") == "Supplier":
columns += [_("Supplier Type") + ":Link/Supplier Type:80"]
columns += [_("Supplier Group") + ":Link/Supplier Group:80"]
columns.append(_("Remarks") + "::200")
@ -205,11 +205,11 @@ class ReceivablePayableReport(object):
# Delivery Note
row += [voucher_details.get(gle.voucher_no, {}).get("delivery_note")]
# customer territory / supplier type
# customer territory / supplier group
if args.get("party_type") == "Customer":
row += [self.get_territory(gle.party), self.get_customer_group(gle.party)]
if args.get("party_type") == "Supplier":
row += [self.get_supplier_type(gle.party)]
row += [self.get_supplier_group(gle.party)]
row.append(gle.remarks)
data.append(row)
@ -271,15 +271,15 @@ class ReceivablePayableReport(object):
def get_customer_group(self, party_name):
return self.get_party_map("Customer").get(party_name, {}).get("customer_group") or ""
def get_supplier_type(self, party_name):
return self.get_party_map("Supplier").get(party_name, {}).get("supplier_type") or ""
def get_supplier_group(self, party_name):
return self.get_party_map("Supplier").get(party_name, {}).get("supplier_group") or ""
def get_party_map(self, party_type):
if not hasattr(self, "party_map"):
if party_type == "Customer":
select_fields = "name, customer_name, territory, customer_group"
elif party_type == "Supplier":
select_fields = "name, supplier_name, supplier_type"
select_fields = "name, supplier_name, supplier_group"
self.party_map = dict(((r.name, r) for r in frappe.db.sql("select {0} from `tab{1}`"
.format(select_fields, party_type), as_dict=True)))
@ -332,6 +332,13 @@ class ReceivablePayableReport(object):
conditions.append("company=%s")
values.append(self.filters.company)
if self.filters.finance_book:
conditions.append("finance_book in (%s, '')")
values.append(self.filters.finance_book)
else:
conditions.append("ifnull(finance_book,'')=%s")
values.append('')
if self.filters.get(party_type_field):
conditions.append("party=%s")
values.append(self.filters.get(party_type_field))

View File

@ -35,7 +35,7 @@ class AccountsReceivableSummary(ReceivablePayableReport):
_("Customer Group") + ":Link/Customer Group:120"
]
if args.get("party_type") == "Supplier":
columns += [_("Supplier Type") + ":Link/Supplier Type:80"]
columns += [_("Supplier Group") + ":Link/Supplier Group:80"]
columns.append({
"fieldname": "currency",
@ -66,7 +66,7 @@ class AccountsReceivableSummary(ReceivablePayableReport):
if args.get("party_type") == "Customer":
row += [self.get_territory(party), self.get_customer_group(party)]
if args.get("party_type") == "Supplier":
row += [self.get_supplier_type(party)]
row += [self.get_supplier_group(party)]
row.append(party_dict.currency)
data.append(row)
@ -113,7 +113,7 @@ class AccountsReceivableSummary(ReceivablePayableReport):
"outstanding_amt", "age", "range1", "range2", "range3", "range4", "currency"]
if args.get("party_type") == "Supplier":
cols += ["supplier_type", "remarks"]
cols += ["supplier_group", "remarks"]
if args.get("party_type") == "Customer":
cols += ["territory", "customer_group", "remarks"]

View File

@ -58,7 +58,7 @@ def execute(filters=None):
return columns, data, message, chart
def get_provisional_profit_loss(asset, liability, equity, period_list, company):
def get_provisional_profit_loss(asset, liability, equity, period_list, company, consolidated=False):
provisional_profit_loss = {}
total_row = {}
if asset and (liability or equity):
@ -73,22 +73,23 @@ def get_provisional_profit_loss(asset, liability, equity, period_list, company):
has_value = False
for period in period_list:
key = period if consolidated else period.key
effective_liability = 0.0
if liability:
effective_liability += flt(liability[-2].get(period.key))
effective_liability += flt(liability[-2].get(key))
if equity:
effective_liability += flt(equity[-2].get(period.key))
effective_liability += flt(equity[-2].get(key))
provisional_profit_loss[period.key] = flt(asset[-2].get(period.key)) - effective_liability
total_row[period.key] = effective_liability + provisional_profit_loss[period.key]
provisional_profit_loss[key] = flt(asset[-2].get(key)) - effective_liability
total_row[key] = effective_liability + provisional_profit_loss[key]
if provisional_profit_loss[period.key]:
if provisional_profit_loss[key]:
has_value = True
total += flt(provisional_profit_loss[period.key])
total += flt(provisional_profit_loss[key])
provisional_profit_loss["total"] = total
total_row_total += flt(total_row[period.key])
total_row_total += flt(total_row[key])
total_row["total"] = total_row_total
if has_value:

View File

@ -18,6 +18,60 @@ def execute(filters=None):
period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
filters.periodicity, filters.accumulated_values, filters.company)
cash_flow_accounts = get_cash_flow_accounts()
# compute net profit / loss
income = get_data(filters.company, "Income", "Credit", period_list,
accumulated_values=filters.accumulated_values, ignore_closing_entries=True, ignore_accumulated_values_for_fy= True)
expense = get_data(filters.company, "Expense", "Debit", period_list,
accumulated_values=filters.accumulated_values, ignore_closing_entries=True, ignore_accumulated_values_for_fy= True)
net_profit_loss = get_net_profit_loss(income, expense, period_list, filters.company)
data = []
company_currency = frappe.db.get_value("Company", filters.company, "default_currency")
for cash_flow_account in cash_flow_accounts:
section_data = []
data.append({
"account_name": cash_flow_account['section_header'],
"parent_account": None,
"indent": 0.0,
"account": cash_flow_account['section_header']
})
if len(data) == 1:
# add first net income in operations section
if net_profit_loss:
net_profit_loss.update({
"indent": 1,
"parent_account": cash_flow_accounts[0]['section_header']
})
data.append(net_profit_loss)
section_data.append(net_profit_loss)
for account in cash_flow_account['account_types']:
account_data = get_account_type_based_data(filters.company,
account['account_type'], period_list, filters.accumulated_values)
account_data.update({
"account_name": account['label'],
"account": account['label'],
"indent": 1,
"parent_account": cash_flow_account['section_header'],
"currency": company_currency
})
data.append(account_data)
section_data.append(account_data)
add_total_row_account(data, section_data, cash_flow_account['section_footer'],
period_list, company_currency)
add_total_row_account(data, data, _("Net Change in Cash"), period_list, company_currency)
columns = get_columns(filters.periodicity, period_list, filters.accumulated_values, filters.company)
return columns, data
def get_cash_flow_accounts():
operation_accounts = {
"section_name": "Operations",
"section_footer": _("Net Cash from Operations"),
@ -49,80 +103,17 @@ def execute(filters=None):
}
# combine all cash flow accounts for iteration
cash_flow_accounts = [operation_accounts, investing_accounts, financing_accounts]
# compute net profit / loss
income = get_data(filters.company, "Income", "Credit", period_list,
accumulated_values=filters.accumulated_values, ignore_closing_entries=True, ignore_accumulated_values_for_fy= True)
expense = get_data(filters.company, "Expense", "Debit", period_list,
accumulated_values=filters.accumulated_values, ignore_closing_entries=True, ignore_accumulated_values_for_fy= True)
net_profit_loss = get_net_profit_loss(income, expense, period_list, filters.company)
data = []
company_currency = frappe.db.get_value("Company", filters.company, "default_currency")
for cash_flow_account in cash_flow_accounts:
section_data = []
data.append({
"account_name": cash_flow_account['section_header'],
"parent_account": None,
"indent": 0.0,
"account": cash_flow_account['section_header']
})
if len(data) == 1:
# add first net income in operations section
if net_profit_loss:
net_profit_loss.update({
"indent": 1,
"parent_account": operation_accounts['section_header']
})
data.append(net_profit_loss)
section_data.append(net_profit_loss)
for account in cash_flow_account['account_types']:
account_data = get_account_type_based_data(filters.company,
account['account_type'], period_list, filters.accumulated_values)
account_data.update({
"account_name": account['label'],
"account": account['label'],
"indent": 1,
"parent_account": cash_flow_account['section_header'],
"currency": company_currency
})
data.append(account_data)
section_data.append(account_data)
add_total_row_account(data, section_data, cash_flow_account['section_footer'],
period_list, company_currency)
add_total_row_account(data, data, _("Net Change in Cash"), period_list, company_currency)
columns = get_columns(filters.periodicity, period_list, filters.accumulated_values, filters.company)
return columns, data
return [operation_accounts, investing_accounts, financing_accounts]
def get_account_type_based_data(company, account_type, period_list, accumulated_values):
data = {}
total = 0
for period in period_list:
start_date = get_start_date(period, accumulated_values, company)
gl_sum = frappe.db.sql_list("""
select sum(credit) - sum(debit)
from `tabGL Entry`
where company=%s and posting_date >= %s and posting_date <= %s
and voucher_type != 'Period Closing Voucher'
and account in ( SELECT name FROM tabAccount WHERE account_type = %s)
""", (company, start_date if accumulated_values else period['from_date'],
period['to_date'], account_type))
if gl_sum and gl_sum[0]:
amount = gl_sum[0]
if account_type == "Depreciation":
amount = get_account_type_based_gl_data(company, start_date, period['to_date'], account_type)
if amount and account_type == "Depreciation":
amount *= -1
else:
amount = 0
total += amount
data.setdefault(period["key"], amount)
@ -130,16 +121,28 @@ def get_account_type_based_data(company, account_type, period_list, accumulated_
data["total"] = total
return data
def get_account_type_based_gl_data(company, start_date, end_date, account_type):
gl_sum = frappe.db.sql_list("""
select sum(credit) - sum(debit)
from `tabGL Entry`
where company=%s and posting_date >= %s and posting_date <= %s
and voucher_type != 'Period Closing Voucher'
and account in ( SELECT name FROM tabAccount WHERE account_type = %s)
""", (company, start_date, end_date, account_type))
return gl_sum[0] if gl_sum and gl_sum[0] else 0
def get_start_date(period, accumulated_values, company):
if not accumulated_values and period.get('from_date'):
return period['from_date']
start_date = period["year_start_date"]
if accumulated_values:
start_date = get_fiscal_year(period.to_date, company=company)[1]
return start_date
def add_total_row_account(out, data, label, period_list, currency):
def add_total_row_account(out, data, label, period_list, currency, consolidated = False):
total_row = {
"account_name": "'" + _("{0}").format(label) + "'",
"account": "'" + _("{0}").format(label) + "'",
@ -148,8 +151,9 @@ def add_total_row_account(out, data, label, period_list, currency):
for row in data:
if row.get("parent_account"):
for period in period_list:
total_row.setdefault(period.key, 0.0)
total_row[period.key] += row.get(period.key, 0.0)
key = period if consolidated else period['key']
total_row.setdefault(key, 0.0)
total_row[key] += row.get(key, 0.0)
total_row.setdefault("total", 0.0)
total_row["total"] += row["total"]

View File

@ -0,0 +1,46 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
/* eslint-disable */
frappe.query_reports["Consolidated Financial Statement"] = {
"filters": [
{
"fieldname":"company",
"label": __("Company"),
"fieldtype": "Link",
"options": "Company",
"default": frappe.defaults.get_user_default("Company"),
"reqd": 1
},
{
"fieldname":"from_fiscal_year",
"label": __("Start Year"),
"fieldtype": "Link",
"options": "Fiscal Year",
"default": frappe.defaults.get_user_default("fiscal_year"),
"reqd": 1
},
{
"fieldname":"to_fiscal_year",
"label": __("End Year"),
"fieldtype": "Link",
"options": "Fiscal Year",
"default": frappe.defaults.get_user_default("fiscal_year"),
"reqd": 1
},
{
"fieldname":"report",
"label": __("Report"),
"fieldtype": "Select",
"options": ["Profit and Loss Statement", "Balance Sheet", "Cash Flow"],
"default": "Balance Sheet",
"reqd": 1
},
{
"fieldname":"accumulated_in_group_company",
"label": __("Accumulated Values in Group Company"),
"fieldtype": "Check",
"default": 0
},
]
}

View File

@ -0,0 +1,35 @@
{
"add_total_row": 0,
"creation": "2018-04-14 16:01:07.919565",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"letter_head": "Test AEF",
"modified": "2018-04-14 16:01:07.919565",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Consolidated Financial Statement",
"owner": "Administrator",
"ref_doctype": "Account",
"report_name": "Consolidated Financial Statement",
"report_type": "Script Report",
"roles": [
{
"role": "Accounts User"
},
{
"role": "Auditor"
},
{
"role": "Sales User"
},
{
"role": "Purchase User"
},
{
"role": "Accounts Manager"
}
]
}

View File

@ -0,0 +1,409 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import flt, cint
from erpnext.accounts.report.financial_statements import get_fiscal_year_data, sort_accounts
from erpnext.accounts.report.balance_sheet.balance_sheet import (get_provisional_profit_loss,
check_opening_balance, get_chart_data)
from erpnext.accounts.report.profit_and_loss_statement.profit_and_loss_statement import (get_net_profit_loss,
get_chart_data as get_pl_chart_data)
from erpnext.accounts.report.cash_flow.cash_flow import (get_cash_flow_accounts, get_account_type_based_gl_data,
add_total_row_account)
def execute(filters=None):
columns, data, message, chart = [], [], [], []
fiscal_year = get_fiscal_year_data(filters.get('from_fiscal_year'), filters.get('to_fiscal_year'))
companies_column, companies = get_companies(filters)
columns = get_columns(companies_column)
if filters.get('report') == "Balance Sheet":
data, message, chart = get_balance_sheet_data(fiscal_year, companies, columns, filters)
elif filters.get('report') == "Profit and Loss Statement":
data, message, chart = get_profit_loss_data(fiscal_year, companies, columns, filters)
else:
if cint(frappe.db.get_single_value('Accounts Settings', 'use_custom_cash_flow')):
from erpnext.accounts.report.cash_flow.custom_cash_flow import execute as execute_custom
return execute_custom(filters=filters)
data = get_cash_flow_data(fiscal_year, companies, filters)
return columns, data, message, chart
def get_balance_sheet_data(fiscal_year, companies, columns, filters):
asset = get_data(companies, "Asset", "Debit", fiscal_year, filters=filters)
liability = get_data(companies, "Liability", "Credit", fiscal_year, filters=filters)
equity = get_data(companies, "Equity", "Credit", fiscal_year, filters=filters)
data = []
data.extend(asset or [])
data.extend(liability or [])
data.extend(equity or [])
provisional_profit_loss, total_credit = get_provisional_profit_loss(asset, liability, equity,
companies, filters.get('company'), True)
message, opening_balance = check_opening_balance(asset, liability, equity)
if opening_balance and round(opening_balance,2) !=0:
unclosed ={
"account_name": "'" + _("Unclosed Fiscal Years Profit / Loss (Credit)") + "'",
"account": "'" + _("Unclosed Fiscal Years Profit / Loss (Credit)") + "'",
"warn_if_negative": True,
"currency": frappe.db.get_value("Company", filters.company, "default_currency")
}
for company in companies:
unclosed[company] = opening_balance
if provisional_profit_loss:
provisional_profit_loss[company] = provisional_profit_loss[company] - opening_balance
unclosed["total"]=opening_balance
data.append(unclosed)
if provisional_profit_loss:
data.append(provisional_profit_loss)
if total_credit:
data.append(total_credit)
chart = get_chart_data(filters, columns, asset, liability, equity)
return data, message, chart
def get_profit_loss_data(fiscal_year, companies, columns, filters):
income, expense, net_profit_loss = get_income_expense_data(companies, fiscal_year, filters)
data = []
data.extend(income or [])
data.extend(expense or [])
if net_profit_loss:
data.append(net_profit_loss)
chart = get_pl_chart_data(filters, columns, income, expense, net_profit_loss)
return data, None, chart
def get_income_expense_data(companies, fiscal_year, filters):
company_currency = frappe.db.get_value("Company", filters.company, "default_currency")
income = get_data(companies, "Income", "Credit", fiscal_year, filters, True)
expense = get_data(companies, "Expense", "Debit", fiscal_year, filters, True)
net_profit_loss = get_net_profit_loss(income, expense, companies, filters.company, company_currency, True)
return income, expense, net_profit_loss
def get_cash_flow_data(fiscal_year, companies, filters):
cash_flow_accounts = get_cash_flow_accounts()
income, expense, net_profit_loss = get_income_expense_data(companies, fiscal_year, filters)
data = []
company_currency = frappe.db.get_value("Company", filters.company, "default_currency")
for cash_flow_account in cash_flow_accounts:
section_data = []
data.append({
"account_name": cash_flow_account['section_header'],
"parent_account": None,
"indent": 0.0,
"account": cash_flow_account['section_header']
})
if len(data) == 1:
# add first net income in operations section
if net_profit_loss:
net_profit_loss.update({
"indent": 1,
"parent_account": cash_flow_accounts[0]['section_header']
})
data.append(net_profit_loss)
section_data.append(net_profit_loss)
for account in cash_flow_account['account_types']:
account_data = get_account_type_based_data(account['account_type'], companies, fiscal_year)
account_data.update({
"account_name": account['label'],
"account": account['label'],
"indent": 1,
"parent_account": cash_flow_account['section_header'],
"currency": company_currency
})
data.append(account_data)
section_data.append(account_data)
add_total_row_account(data, section_data, cash_flow_account['section_footer'],
companies, company_currency, True)
add_total_row_account(data, data, _("Net Change in Cash"), companies, company_currency, True)
return data
def get_account_type_based_data(account_type, companies, fiscal_year):
data = {}
total = 0
for company in companies:
amount = get_account_type_based_gl_data(company,
fiscal_year.year_start_date, fiscal_year.year_end_date, account_type)
if amount and account_type == "Depreciation":
amount *= -1
total += amount
data.setdefault(company, amount)
data["total"] = total
return data
def get_columns(companies):
columns = [{
"fieldname": "account",
"label": _("Account"),
"fieldtype": "Link",
"options": "Account",
"width": 300
}]
columns.append({
"fieldname": "currency",
"label": _("Currency"),
"fieldtype": "Link",
"options": "Currency",
"hidden": 1
})
for company in companies:
columns.append({
"fieldname": company,
"label": company,
"fieldtype": "Currency",
"width": 150
})
return columns
def get_data(companies, root_type, balance_must_be, fiscal_year, filters=None, ignore_closing_entries=False):
accounts, accounts_by_name = get_account_heads(root_type,
companies, filters)
company_currency = get_company_currency(filters)
gl_entries_by_account = {}
for root in frappe.db.sql("""select lft, rgt from tabAccount
where root_type=%s and ifnull(parent_account, '') = ''""", root_type, as_dict=1):
set_gl_entries_by_account(fiscal_year.year_start_date,
fiscal_year.year_end_date, root.lft, root.rgt, filters,
gl_entries_by_account, accounts_by_name, ignore_closing_entries=False)
calculate_values(accounts_by_name, gl_entries_by_account, companies, fiscal_year, filters)
accumulate_values_into_parents(accounts, accounts_by_name, companies)
out = prepare_data(accounts, fiscal_year, balance_must_be, companies, company_currency)
if out:
add_total_row(out, root_type, balance_must_be, companies, company_currency)
return out
def get_company_currency(filters=None):
return frappe.db.get_value("Company", filters.get('company'), "default_currency")
def calculate_values(accounts_by_name, gl_entries_by_account, companies, fiscal_year, filters):
for entries in gl_entries_by_account.values():
for entry in entries:
key = entry.account_number or entry.account_name
d = accounts_by_name.get(key)
if d:
for company in companies:
# check if posting date is within the period
if (entry.company == company or (filters.get('accumulated_in_group_company'))
and entry.company in companies.get(company)):
d[company] = d.get(company, 0.0) + flt(entry.debit) - flt(entry.credit)
if entry.posting_date < fiscal_year.year_start_date:
d["opening_balance"] = d.get("opening_balance", 0.0) + flt(entry.debit) - flt(entry.credit)
def accumulate_values_into_parents(accounts, accounts_by_name, companies):
"""accumulate children's values in parent accounts"""
for d in reversed(accounts):
if d.parent_account:
account = d.parent_account.split('-')[0].strip()
for company in companies:
accounts_by_name[account][company] = \
accounts_by_name[account].get(company, 0.0) + d.get(company, 0.0)
accounts_by_name[account]["opening_balance"] = \
accounts_by_name[account].get("opening_balance", 0.0) + d.get("opening_balance", 0.0)
def get_account_heads(root_type, companies, filters):
accounts = get_accounts(root_type, filters)
if not accounts:
return None
accounts, accounts_by_name, parent_children_map = filter_accounts(accounts)
return accounts, accounts_by_name
def get_companies(filters):
companies = {}
all_companies = get_subsidiary_companies(filters.get('company'))
companies.setdefault(filters.get('company'), all_companies)
for d in all_companies:
if d not in companies:
subsidiary_companies = get_subsidiary_companies(d)
companies.setdefault(d, subsidiary_companies)
return all_companies, companies
def get_subsidiary_companies(company):
lft, rgt = frappe.db.get_value('Company',
company, ["lft", "rgt"])
return frappe.db.sql_list("""select name from `tabCompany`
where lft >= {0} and rgt <= {1} order by lft, rgt""".format(lft, rgt))
def get_accounts(root_type, filters):
return frappe.db.sql(""" select name, is_group, company,
parent_account, lft, rgt, root_type, report_type, account_name, account_number
from
`tabAccount` where company = %s and root_type = %s
""" , (filters.get('company'), root_type), as_dict=1)
def prepare_data(accounts, fiscal_year, balance_must_be, companies, company_currency):
data = []
year_start_date = fiscal_year.year_start_date
year_end_date = fiscal_year.year_end_date
for d in accounts:
# add to output
has_value = False
total = 0
row = frappe._dict({
"account_name": _(d.account_name),
"account": _(d.account_name),
"parent_account": _(d.parent_account),
"indent": flt(d.indent),
"year_start_date": year_start_date,
"year_end_date": year_end_date,
"currency": company_currency,
"opening_balance": d.get("opening_balance", 0.0) * (1 if balance_must_be == "Debit" else -1)
})
for company in companies:
if d.get(company) and balance_must_be == "Credit":
# change sign based on Debit or Credit, since calculation is done using (debit - credit)
d[company] *= -1
row[company] = flt(d.get(company, 0.0), 3)
if abs(row[company]) >= 0.005:
# ignore zero values
has_value = True
total += flt(row[company])
row["has_value"] = has_value
row["total"] = total
data.append(row)
return data
def set_gl_entries_by_account(from_date, to_date, root_lft, root_rgt, filters, gl_entries_by_account,
accounts_by_name, ignore_closing_entries=False):
"""Returns a dict like { "account": [gl entries], ... }"""
company_lft, company_rgt = frappe.db.get_value('Company',
filters.get('company'), ["lft", "rgt"])
additional_conditions = get_additional_conditions(from_date, ignore_closing_entries)
gl_entries = frappe.db.sql("""select gl.posting_date, gl.account, gl.debit, gl.credit, gl.is_opening, gl.company,
gl.fiscal_year, gl.debit_in_account_currency, gl.credit_in_account_currency, gl.account_currency,
acc.account_name, acc.account_number
from `tabGL Entry` gl, `tabAccount` acc where acc.name = gl.account and gl.company in
(select name from `tabCompany` where lft >= %(company_lft)s and rgt <= %(company_rgt)s)
{additional_conditions} and gl.posting_date <= %(to_date)s and acc.lft >= %(lft)s and acc.rgt <= %(rgt)s
order by gl.account, gl.posting_date""".format(additional_conditions=additional_conditions),
{
"from_date": from_date,
"to_date": to_date,
"lft": root_lft,
"rgt": root_rgt,
"company_lft": company_lft,
"company_rgt": company_rgt,
},
as_dict=True)
for entry in gl_entries:
key = entry.account_number or entry.account_name
validate_entries(key, entry, accounts_by_name)
gl_entries_by_account.setdefault(key, []).append(entry)
return gl_entries_by_account
def validate_entries(key, entry, accounts_by_name):
if key not in accounts_by_name:
field = "Account number" if entry.account_number else "Account name"
frappe.throw(_("{0} {1} is not present in the parent company").format(field, key))
def get_additional_conditions(from_date, ignore_closing_entries):
additional_conditions = []
if ignore_closing_entries:
additional_conditions.append("ifnull(gl.voucher_type, '')!='Period Closing Voucher'")
if from_date:
additional_conditions.append("gl.posting_date >= %(from_date)s")
return " and {}".format(" and ".join(additional_conditions)) if additional_conditions else ""
def add_total_row(out, root_type, balance_must_be, companies, company_currency):
total_row = {
"account_name": "'" + _("Total {0} ({1})").format(_(root_type), _(balance_must_be)) + "'",
"account": "'" + _("Total {0} ({1})").format(_(root_type), _(balance_must_be)) + "'",
"currency": company_currency
}
for row in out:
if not row.get("parent_account"):
for company in companies:
total_row.setdefault(company, 0.0)
total_row[company] += row.get(company, 0.0)
row[company] = 0.0
total_row.setdefault("total", 0.0)
total_row["total"] += flt(row["total"])
row["total"] = ""
if "total" in total_row:
out.append(total_row)
# blank row after Total
out.append({})
def filter_accounts(accounts, depth=10):
parent_children_map = {}
accounts_by_name = {}
for d in accounts:
key = d.account_number or d.account_name
accounts_by_name[key] = d
parent_children_map.setdefault(d.parent_account or None, []).append(d)
filtered_accounts = []
def add_to_list(parent, level):
if level < depth:
children = parent_children_map.get(parent) or []
sort_accounts(children, is_root=True if parent==None else False)
for child in children:
child.indent = level
filtered_accounts.append(child)
add_to_list(child.name, level + 1)
add_to_list(None, 0)
return filtered_accounts, accounts_by_name, parent_children_map

View File

@ -375,6 +375,12 @@ def get_additional_conditions(from_date, ignore_closing_entries, filters):
additional_conditions.append("project = '%s'" % (frappe.db.escape(filters.get("project"))))
if filters.get("cost_center"):
additional_conditions.append(get_cost_center_cond(filters.get("cost_center")))
if filters.get("finance_book"):
additional_conditions.append("finance_book in ('%s', '')" %
frappe.db.escape(filters.get("finance_book")))
else:
additional_conditions.append("ifnull(finance_book, '') = ''")
return " and {}".format(" and ".join(additional_conditions)) if additional_conditions else ""

View File

@ -2,7 +2,7 @@
<h4 class="text-center">
{% if (filters.party_name) { %}
{%= filters.party_name %}
{% } else if (filters.party) { %}
{% } else if (filters.party && filters.show_name) { %}
{%= filters.party %}
{% } else if (filters.account) { %}
{%= filters.account %}

View File

@ -11,6 +11,12 @@ frappe.query_reports["General Ledger"] = {
"default": frappe.defaults.get_user_default("Company"),
"reqd": 1
},
{
"fieldname":"finance_book",
"label": __("Finance Book"),
"fieldtype": "Link",
"options": "Finance Book"
},
{
"fieldname":"from_date",
"label": __("From Date"),
@ -46,6 +52,9 @@ frappe.query_reports["General Ledger"] = {
"fieldname":"voucher_no",
"label": __("Voucher No"),
"fieldtype": "Data",
on_change: function() {
frappe.query_report_filters_by_name.group_by.set_value("");
}
},
{
"fieldname":"project",
@ -69,22 +78,50 @@ frappe.query_reports["General Ledger"] = {
{
"fieldname":"party",
"label": __("Party"),
"fieldtype": "Dynamic Link",
"get_options": function() {
"fieldtype": "MultiSelect",
get_data: function() {
if(!frappe.query_report_filters_by_name) return;
var party_type = frappe.query_report_filters_by_name.party_type.get_value();
var party = frappe.query_report_filters_by_name.party.get_value();
if(party && !party_type) {
var parties = frappe.query_report_filters_by_name.party.get_value();
if(!party_type) {
frappe.throw(__("Please select Party Type first"));
}
return party_type;
const values = parties.split(/\s*,\s*/).filter(d => d);
const txt = parties.match(/[^,\s*]*$/)[0] || '';
let data = [];
frappe.call({
type: "GET",
method:'frappe.desk.search.search_link',
async: false,
no_spinner: true,
args: {
doctype: frappe.query_report_filters_by_name.party_type.get_value(),
txt: txt,
filters: {
"name": ["not in", values]
}
},
callback: function(r) {
data = r.results;
}
});
return data;
},
on_change: function() {
var party_type = frappe.query_report_filters_by_name.party_type.get_value();
var party = frappe.query_report_filters_by_name.party.get_value();
if(!party_type || !party) {
var parties = frappe.query_report_filters_by_name.party.get_value();
const values = parties.split(/\s*,\s*/).filter(d => d);
if(!party_type || !parties || values.length>1) {
frappe.query_report_filters_by_name.party_name.set_value("");
frappe.query_report_filters_by_name.tax_id.set_value("");
return;
}
} else {
var party = values[0];
frappe.query_report_filters_by_name.show_name = true;
var fieldname = erpnext.utils.get_party_name(party_type) || "name";
frappe.db.get_value(party_type, party, fieldname, function(value) {
frappe.query_report_filters_by_name.party_name.set_value(value[fieldname]);
@ -96,6 +133,7 @@ frappe.query_reports["General Ledger"] = {
});
}
}
}
},
{
"fieldname":"party_name",
@ -103,23 +141,19 @@ frappe.query_reports["General Ledger"] = {
"fieldtype": "Data",
"hidden": 1
},
{
"fieldname":"group_by",
"label": __("Group by"),
"fieldtype": "Select",
"options": ["", "Group by Voucher", "Group by Account", "Group by Party"],
"default": "Group by Voucher"
},
{
"fieldname":"tax_id",
"label": __("Tax Id"),
"fieldtype": "Data",
"hidden": 1
},
{
"fieldname":"group_by_voucher",
"label": __("Group by Voucher"),
"fieldtype": "Check",
"default": 1
},
{
"fieldname":"group_by_account",
"label": __("Group by Account"),
"fieldtype": "Check",
},
{
"fieldname": "presentation_currency",
"label": __("Currency"),

View File

@ -20,6 +20,10 @@ def execute(filters=None):
for acc in frappe.db.sql("""select name, is_group from tabAccount""", as_dict=1):
account_details.setdefault(acc.name, acc)
if filters.get('party'):
parties = str(filters.get("party")).strip()
filters.party = [d.strip() for d in parties.split(',') if d]
validate_filters(filters, account_details)
validate_party(filters)
@ -40,11 +44,11 @@ def validate_filters(filters, account_details):
if filters.get("account") and not account_details.get(filters.account):
frappe.throw(_("Account {0} does not exists").format(filters.account))
if filters.get("account") and filters.get("group_by_account") \
and account_details[filters.account].is_group == 0:
if (filters.get("account") and filters.get("group_by") == 'Group by Account'
and account_details[filters.account].is_group == 0):
frappe.throw(_("Can not filter based on Account, if grouped by Account"))
if filters.get("voucher_no") and filters.get("group_by_voucher"):
if (filters.get("voucher_no") and filters.get("group_by") == 'Group by Voucher'):
frappe.throw(_("Can not filter based on Voucher No, if grouped by Voucher"))
if filters.from_date > filters.to_date:
@ -57,14 +61,13 @@ def validate_party(filters):
if party:
if not party_type:
frappe.throw(_("To filter based on Party, select Party Type first"))
elif not frappe.db.exists(party_type, party):
frappe.throw(_("Invalid {0}: {1}").format(party_type, party))
else:
for d in party:
if not frappe.db.exists(party_type, d):
frappe.throw(_("Invalid {0}: {1}").format(party_type, d))
def set_account_currency(filters):
if not (filters.get("account") or filters.get("party")):
return filters
else:
if filters.get("account") or (filters.get('party') and len(filters.party) == 1):
filters["company_currency"] = frappe.db.get_value("Company", filters.company, "default_currency")
account_currency = None
@ -73,7 +76,7 @@ def set_account_currency(filters):
elif filters.get("party"):
gle_currency = frappe.db.get_value(
"GL Entry", {
"party_type": filters.party_type, "party": filters.party, "company": filters.company
"party_type": filters.party_type, "party": filters.party[0], "company": filters.company
},
"account_currency"
)
@ -82,7 +85,7 @@ def set_account_currency(filters):
account_currency = gle_currency
else:
account_currency = None if filters.party_type in ["Employee", "Student", "Shareholder"] else \
frappe.db.get_value(filters.party_type, filters.party, "default_currency")
frappe.db.get_value(filters.party_type, filters.party[0], "default_currency")
filters["account_currency"] = account_currency or filters.company_currency
@ -106,9 +109,9 @@ def get_gl_entries(filters):
select_fields = """, sum(debit_in_account_currency) as debit_in_account_currency,
sum(credit_in_account_currency) as credit_in_account_currency""" \
group_by_condition = "group by voucher_type, voucher_no, account, cost_center" \
if filters.get("group_by_voucher") else "group by name"
group_by_condition = "group by name"
if filters.get("group_by") == "Group by Voucher":
group_by_condition = "group by voucher_type, voucher_no, account, cost_center"
gl_entries = frappe.db.sql(
"""
@ -144,19 +147,28 @@ def get_conditions(filters):
if filters.get("voucher_no"):
conditions.append("voucher_no=%(voucher_no)s")
if filters.get("group_by") == "Group by Party" and not filters.get("party_type"):
conditions.append("party_type in ('Customer', 'Supplier')")
if filters.get("party_type"):
conditions.append("party_type=%(party_type)s")
if filters.get("party"):
conditions.append("party=%(party)s")
conditions.append("party in %(party)s")
if not (filters.get("account") or filters.get("party") or filters.get("group_by_account")):
if not (filters.get("account") or filters.get("party") or
filters.get("group_by") in ["Group by Account", "Group by Party"]):
conditions.append("posting_date >=%(from_date)s")
conditions.append("posting_date <=%(to_date)s")
if filters.get("project"):
conditions.append("project=%(project)s")
if filters.get("finance_book"):
conditions.append("finance_book in (%(finance_book)s, '')")
else:
conditions.append("ifnull(finance_book, '')=''")
from frappe.desk.reportview import build_match_conditions
match_conditions = build_match_conditions("GL Entry")
@ -168,15 +180,17 @@ def get_conditions(filters):
def get_data_with_opening_closing(filters, account_details, gl_entries):
data = []
gle_map = initialize_gle_map(gl_entries)
gle_map = initialize_gle_map(gl_entries, filters)
totals, entries = get_accountwise_gle(filters, gl_entries, gle_map)
# Opening for filtered account
data.append(totals.opening)
if filters.get("group_by_account"):
if filters.get("group_by") in ["Group by Account", "Group by Party"]:
for acc, acc_dict in gle_map.items():
# acc
if acc_dict.entries:
# opening
data.append({})
@ -219,16 +233,19 @@ def get_totals_dict():
)
def initialize_gle_map(gl_entries):
def initialize_gle_map(gl_entries, filters):
gle_map = frappe._dict()
group_by = 'party' if filters.get('group_by') == 'Group by Party' else "account"
for gle in gl_entries:
gle_map.setdefault(gle.account, _dict(totals=get_totals_dict(), entries=[]))
gle_map.setdefault(gle.get(group_by), _dict(totals=get_totals_dict(), entries=[]))
return gle_map
def get_accountwise_gle(filters, gl_entries, gle_map):
totals = get_totals_dict()
entries = []
group_by = 'party' if filters.get('group_by') == 'Group by Party' else "account"
def update_value_in_dict(data, key, gle):
data[key].debit += flt(gle.debit)
@ -240,21 +257,21 @@ def get_accountwise_gle(filters, gl_entries, gle_map):
from_date, to_date = getdate(filters.from_date), getdate(filters.to_date)
for gle in gl_entries:
if gle.posting_date < from_date or cstr(gle.is_opening) == "Yes":
update_value_in_dict(gle_map[gle.account].totals, 'opening', gle)
update_value_in_dict(gle_map[gle.get(group_by)].totals, 'opening', gle)
update_value_in_dict(totals, 'opening', gle)
update_value_in_dict(gle_map[gle.account].totals, 'closing', gle)
update_value_in_dict(gle_map[gle.get(group_by)].totals, 'closing', gle)
update_value_in_dict(totals, 'closing', gle)
elif gle.posting_date <= to_date:
update_value_in_dict(gle_map[gle.account].totals, 'total', gle)
update_value_in_dict(gle_map[gle.get(group_by)].totals, 'total', gle)
update_value_in_dict(totals, 'total', gle)
if filters.get("group_by_account"):
gle_map[gle.account].entries.append(gle)
if filters.get("group_by") in ["Group by Account", "Group by Party"]:
gle_map[gle.get(group_by)].entries.append(gle)
else:
entries.append(gle)
update_value_in_dict(gle_map[gle.account].totals, 'closing', gle)
update_value_in_dict(gle_map[gle.get(group_by)].totals, 'closing', gle)
update_value_in_dict(totals, 'closing', gle)
return totals, entries

View File

@ -33,7 +33,7 @@ def execute(filters=None):
return columns, data, None, chart
def get_net_profit_loss(income, expense, period_list, company, currency=None):
def get_net_profit_loss(income, expense, period_list, company, currency=None, consolidated=False):
total = 0
net_profit_loss = {
"account_name": "'" + _("Profit for the year") + "'",
@ -45,21 +45,21 @@ def get_net_profit_loss(income, expense, period_list, company, currency=None):
has_value = False
for period in period_list:
total_income = flt(income[-2][period.key], 3) if income else 0
total_expense = flt(expense[-2][period.key], 3) if expense else 0
key = period if consolidated else period.key
total_income = flt(income[-2][key], 3) if income else 0
total_expense = flt(expense[-2][key], 3) if expense else 0
net_profit_loss[period.key] = total_income - total_expense
net_profit_loss[key] = total_income - total_expense
if net_profit_loss[period.key]:
if net_profit_loss[key]:
has_value=True
total += flt(net_profit_loss[period.key])
total += flt(net_profit_loss[key])
net_profit_loss["total"] = total
if has_value:
return net_profit_loss
def get_chart_data(filters, columns, income, expense, net_profit_loss):
labels = [d.get("label") for d in columns[2:]]

View File

@ -42,7 +42,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
row.append(inv.get(col))
row += [
supplier_details.get(inv.supplier), # supplier_type
supplier_details.get(inv.supplier), # supplier_group
inv.tax_id, inv.credit_to, inv.mode_of_payment, ", ".join(project),
inv.bill_no, inv.bill_date, inv.remarks,
", ".join(purchase_order), ", ".join(purchase_receipt), company_currency
@ -83,7 +83,7 @@ def get_columns(invoice_list, additional_table_columns):
columns += additional_table_columns
columns += [
_("Supplier Type") + ":Link/Supplier Type:120", _("Tax Id") + "::80", _("Payable Account") + ":Link/Account:120",
_("Supplier Group") + ":Link/Supplier Group:120", _("Tax Id") + "::80", _("Payable Account") + ":Link/Account:120",
_("Mode of Payment") + ":Link/Mode of Payment:80", _("Project") + ":Link/Project:80",
_("Bill No") + "::120", _("Bill Date") + ":Date:80", _("Remarks") + "::150",
_("Purchase Order") + ":Link/Purchase Order:100",
@ -229,8 +229,8 @@ def get_account_details(invoice_list):
def get_supplier_details(suppliers):
supplier_details = {}
for supp in frappe.db.sql("""select name, supplier_type from `tabSupplier`
for supp in frappe.db.sql("""select name, supplier_group from `tabSupplier`
where name in (%s)""" % ", ".join(["%s"]*len(suppliers)), tuple(suppliers), as_dict=1):
supplier_details.setdefault(supp.name, supp.supplier_type)
supplier_details.setdefault(supp.name, supp.supplier_group)
return supplier_details

View File

@ -23,6 +23,14 @@ frappe.ui.form.on('Asset', {
}
};
});
frm.set_query("department", function() {
return {
"filters": {
"company": frm.doc.company,
}
};
});
},
refresh: function(frm) {
@ -49,6 +57,19 @@ frappe.ui.form.on('Asset', {
erpnext.asset.restore_asset(frm);
});
}
if (frm.doc.purchase_receipt) {
frm.add_custom_button("General Ledger", function() {
frappe.route_options = {
"voucher_no": frm.doc.name,
"from_date": frm.doc.available_for_use_date,
"to_date": frm.doc.available_for_use_date,
"company": frm.doc.company
};
frappe.set_route("query-report", "General Ledger");
});
}
if (frm.doc.status=='Submitted' && !frm.doc.is_existing_asset && !frm.doc.purchase_invoice) {
frm.add_custom_button(__("Purchase Invoice"), function() {
frm.trigger("make_purchase_invoice");
@ -59,6 +80,12 @@ frappe.ui.form.on('Asset', {
frm.trigger("create_asset_maintenance");
}, __("Make"));
}
if (frm.doc.status != 'Fully Depreciated') {
frm.add_custom_button(__("Asset Adjustment"), function() {
frm.trigger("create_asset_maintenance");
}, __("Make"));
}
frm.page.set_inner_btn_group_as_primary(__("Make"));
frm.trigger("setup_chart");
}
@ -123,9 +150,7 @@ frappe.ui.form.on('Asset', {
},
callback: function(r, rt) {
if(r.message) {
$.each(r.message, function(field, value) {
frm.set_value(field, value);
})
frm.set_value('finance_books', r.message);
}
}
})
@ -133,7 +158,7 @@ frappe.ui.form.on('Asset', {
},
is_existing_asset: function(frm) {
frm.toggle_reqd("next_depreciation_date", (!frm.doc.is_existing_asset && frm.doc.calculate_depreciation));
// frm.toggle_reqd("next_depreciation_date", (!frm.doc.is_existing_asset && frm.doc.calculate_depreciation));
},
opening_accumulated_depreciation: function(frm) {
@ -173,7 +198,8 @@ frappe.ui.form.on('Asset', {
args: {
"asset": frm.doc.name,
"item_code": frm.doc.item_code,
"company": frm.doc.company
"company": frm.doc.company,
"serial_no": frm.doc.serial_no
},
method: "erpnext.assets.doctype.asset.asset.make_sales_invoice",
callback: function(r) {
@ -282,15 +308,14 @@ erpnext.asset.transfer_asset = function(frm) {
title: __("Transfer Asset"),
fields: [
{
"label": __("Target Warehouse"),
"fieldname": "target_warehouse",
"label": __("Target Location"),
"fieldname": "target_location",
"fieldtype": "Link",
"options": "Warehouse",
"options": "Location",
"get_query": function () {
return {
filters: [
["Warehouse", "company", "in", ["", cstr(frm.doc.company)]],
["Warehouse", "is_group", "=", 0]
["Location", "is_group", "=", 0]
]
}
},
@ -317,8 +342,8 @@ erpnext.asset.transfer_asset = function(frm) {
args: {
"asset": frm.doc.name,
"transaction_date": args.transfer_date,
"source_warehouse": frm.doc.warehouse,
"target_warehouse": args.target_warehouse,
"source_warehouse": frm.doc.location,
"target_warehouse": args.target_location,
"company": frm.doc.company
}
},

File diff suppressed because it is too large Load Diff

View File

@ -7,11 +7,14 @@ import frappe
from frappe import _
from frappe.utils import flt, add_months, cint, nowdate, getdate, today, date_diff
from frappe.model.document import Document
from erpnext.accounts.doctype.purchase_invoice.purchase_invoice import get_fixed_asset_account
from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account
from erpnext.assets.doctype.asset.depreciation \
import get_disposal_account_and_cost_center, get_depreciation_accounts
from erpnext.accounts.general_ledger import make_gl_entries
from erpnext.accounts.utils import get_account_currency
from erpnext.controllers.accounts_controller import AccountsController
class Asset(Document):
class Asset(AccountsController):
def validate(self):
self.status = self.get_status()
self.validate_item()
@ -26,6 +29,7 @@ class Asset(Document):
def on_submit(self):
self.set_status()
self.update_stock_movement()
def on_cancel(self):
self.validate_cancellation()
@ -45,29 +49,119 @@ class Asset(Document):
frappe.throw(_("Item {0} must be a non-stock item").format(self.item_code))
def set_missing_values(self):
if self.item_code:
item_details = get_item_details(self.item_code)
for field, value in item_details.items():
if not self.get(field):
self.set(field, value)
if not self.asset_category:
self.asset_category = frappe.db.get_value("Item", self.item_code, "asset_category")
if self.item_code and not self.get('finance_books'):
finance_books = get_item_details(self.item_code, self.asset_category)
self.set('finance_books', finance_books)
def validate_asset_values(self):
if flt(self.expected_value_after_useful_life) >= flt(self.gross_purchase_amount):
frappe.throw(_("Expected Value After Useful Life must be less than Gross Purchase Amount"))
if not flt(self.gross_purchase_amount):
frappe.throw(_("Gross Purchase Amount is mandatory"), frappe.MandatoryError)
if not self.calculate_depreciation:
return
if self.available_for_use_date and getdate(self.available_for_use_date) < getdate(nowdate()):
frappe.throw(_("Available-for-use Date is entered as past date"))
def make_depreciation_schedule(self):
if self.depreciation_method != 'Manual':
self.schedules = []
if not self.get("schedules") and self.available_for_use_date:
total_depreciations = sum([d.total_number_of_depreciations for d in self.get('finance_books')])
for d in self.get('finance_books'):
self.validate_asset_finance_books(d)
value_after_depreciation = (flt(self.gross_purchase_amount) -
flt(self.opening_accumulated_depreciation))
d.value_after_depreciation = value_after_depreciation
no_of_depreciations = cint(d.total_number_of_depreciations - 1) - cint(self.number_of_depreciations_booked)
end_date = add_months(d.depreciation_start_date,
no_of_depreciations * cint(d.frequency_of_depreciation))
total_days = date_diff(end_date, self.available_for_use_date)
rate_per_day = value_after_depreciation / total_days
number_of_pending_depreciations = cint(d.total_number_of_depreciations) - \
cint(self.number_of_depreciations_booked)
from_date = self.available_for_use_date
if number_of_pending_depreciations:
next_depr_date = getdate(add_months(self.available_for_use_date,
number_of_pending_depreciations * 12))
if (cint(frappe.db.get_value("Asset Settings", None, "schedule_based_on_fiscal_year")) == 1
and getdate(d.depreciation_start_date) < next_depr_date):
number_of_pending_depreciations += 1
for n in range(number_of_pending_depreciations):
if n == range(number_of_pending_depreciations)[-1]:
schedule_date = add_months(self.available_for_use_date, n * 12)
previous_scheduled_date = add_months(d.depreciation_start_date, (n-1) * 12)
depreciation_amount = \
self.get_depreciation_amount_prorata_temporis(value_after_depreciation,
d, previous_scheduled_date, schedule_date)
elif n == range(number_of_pending_depreciations)[0]:
schedule_date = d.depreciation_start_date
depreciation_amount = \
self.get_depreciation_amount_prorata_temporis(value_after_depreciation,
d, self.available_for_use_date, schedule_date)
else:
schedule_date = add_months(d.depreciation_start_date, n * 12)
depreciation_amount = \
self.get_depreciation_amount_prorata_temporis(value_after_depreciation, d)
if value_after_depreciation != 0:
value_after_depreciation -= flt(depreciation_amount)
self.append("schedules", {
"schedule_date": schedule_date,
"depreciation_amount": depreciation_amount,
"depreciation_method": d.depreciation_method,
"finance_book": d.finance_book,
"finance_book_id": d.idx
})
else:
for n in range(number_of_pending_depreciations):
schedule_date = add_months(d.depreciation_start_date,
n * cint(d.frequency_of_depreciation))
if d.depreciation_method in ("Straight Line", "Manual"):
days = date_diff(schedule_date, from_date)
depreciation_amount = days * rate_per_day
from_date = schedule_date
else:
depreciation_amount = self.get_depreciation_amount(value_after_depreciation,
d.total_number_of_depreciations, d)
if depreciation_amount:
value_after_depreciation -= flt(depreciation_amount)
self.append("schedules", {
"schedule_date": schedule_date,
"depreciation_amount": depreciation_amount,
"depreciation_method": d.depreciation_method,
"finance_book": d.finance_book,
"finance_book_id": d.idx
})
def validate_asset_finance_books(self, row):
if flt(row.expected_value_after_useful_life) >= flt(self.gross_purchase_amount):
frappe.throw(_("Row {0}: Expected Value After Useful Life must be less than Gross Purchase Amount")
.format(row.idx))
if not self.is_existing_asset:
self.opening_accumulated_depreciation = 0
self.number_of_depreciations_booked = 0
if not self.next_depreciation_date:
frappe.throw(_("Next Depreciation Date is mandatory for new asset"))
else:
depreciable_amount = flt(self.gross_purchase_amount) - flt(self.expected_value_after_useful_life)
depreciable_amount = flt(self.gross_purchase_amount) - flt(row.expected_value_after_useful_life)
if flt(self.opening_accumulated_depreciation) > depreciable_amount:
frappe.throw(_("Opening Accumulated Depreciation must be less than equal to {0}")
.format(depreciable_amount))
@ -78,139 +172,89 @@ class Asset(Document):
else:
self.number_of_depreciations_booked = 0
if cint(self.number_of_depreciations_booked) > cint(self.total_number_of_depreciations):
if cint(self.number_of_depreciations_booked) > cint(row.total_number_of_depreciations):
frappe.throw(_("Number of Depreciations Booked cannot be greater than Total Number of Depreciations"))
self.value_after_depreciation = (flt(self.gross_purchase_amount) -
flt(self.opening_accumulated_depreciation))
if row.depreciation_start_date and getdate(row.depreciation_start_date) < getdate(nowdate()):
frappe.msgprint(_("Depreciation Row {0}: Depreciation Start Date is entered as past date")
.format(row.idx), title=_('Warning'), indicator='red')
if self.next_depreciation_date and getdate(self.next_depreciation_date) < getdate(nowdate()):
frappe.msgprint(_("Next Depreciation Date is entered as past date"), title=_('Warning'), indicator='red')
if row.depreciation_start_date and getdate(row.depreciation_start_date) < getdate(self.purchase_date):
frappe.throw(_("Depreciation Row {0}: Next Depreciation Date cannot be before Purchase Date")
.format(row.idx))
if self.next_depreciation_date and getdate(self.next_depreciation_date) < getdate(self.purchase_date):
frappe.throw(_("Next Depreciation Date cannot be before Purchase Date"))
if row.depreciation_start_date and getdate(row.depreciation_start_date) < getdate(self.available_for_use_date):
frappe.throw(_("Depreciation Row {0}: Next Depreciation Date cannot be before Available-for-use Date")
.format(row.idx))
if self.next_depreciation_date and getdate(self.next_depreciation_date) < getdate(self.available_for_use_date):
frappe.throw(_("Next Depreciation Date cannot be before Available-for-use Date"))
def set_accumulated_depreciation(self, ignore_booked_entry = False):
straight_line_idx = [d.idx for d in self.get("schedules") if d.depreciation_method == 'Straight Line']
finance_books = []
if (flt(self.value_after_depreciation) > flt(self.expected_value_after_useful_life)
and not self.next_depreciation_date and self.calculate_depreciation):
frappe.throw(_("Please set Next Depreciation Date"))
def make_depreciation_schedule(self):
if self.depreciation_method != 'Manual':
self.schedules = []
if not self.get("schedules") and self.next_depreciation_date:
value_after_depreciation = flt(self.value_after_depreciation)
number_of_pending_depreciations = cint(self.total_number_of_depreciations) - \
cint(self.number_of_depreciations_booked)
if number_of_pending_depreciations:
next_depr_date = getdate(add_months(self.available_for_use_date,
number_of_pending_depreciations * 12))
if (cint(frappe.db.get_value("Asset Settings", None, "schedule_based_on_fiscal_year")) == 1
and getdate(self.next_depreciation_date) < next_depr_date):
number_of_pending_depreciations += 1
for n in range(number_of_pending_depreciations):
if n == range(number_of_pending_depreciations)[-1]:
schedule_date = add_months(self.available_for_use_date, n * 12)
previous_scheduled_date = add_months(self.next_depreciation_date, (n-1) * 12)
depreciation_amount = \
self.get_depreciation_amount_prorata_temporis(value_after_depreciation,
previous_scheduled_date, schedule_date)
elif n == range(number_of_pending_depreciations)[0]:
schedule_date = self.next_depreciation_date
depreciation_amount = \
self.get_depreciation_amount_prorata_temporis(value_after_depreciation,
self.available_for_use_date, schedule_date)
else:
schedule_date = add_months(self.next_depreciation_date, n * 12)
depreciation_amount = \
self.get_depreciation_amount_prorata_temporis(value_after_depreciation)
if value_after_depreciation != 0:
value_after_depreciation -= flt(depreciation_amount)
self.append("schedules", {
"schedule_date": schedule_date,
"depreciation_amount": depreciation_amount
})
else:
for n in range(number_of_pending_depreciations):
schedule_date = add_months(self.next_depreciation_date,
n * cint(self.frequency_of_depreciation))
depreciation_amount = self.get_depreciation_amount(value_after_depreciation)
if depreciation_amount:
value_after_depreciation -= flt(depreciation_amount)
self.append("schedules", {
"schedule_date": schedule_date,
"depreciation_amount": depreciation_amount
})
def set_accumulated_depreciation(self):
accumulated_depreciation = flt(self.opening_accumulated_depreciation)
value_after_depreciation = flt(self.value_after_depreciation)
for i, d in enumerate(self.get("schedules")):
if ignore_booked_entry and d.journal_entry:
continue
if d.finance_book_id not in finance_books:
accumulated_depreciation = flt(self.opening_accumulated_depreciation)
value_after_depreciation = flt(self.get_value_after_depreciation(d.finance_book_id))
finance_books.append(d.finance_book_id)
depreciation_amount = flt(d.depreciation_amount, d.precision("depreciation_amount"))
value_after_depreciation -= flt(depreciation_amount)
if i==len(self.get("schedules"))-1 and self.depreciation_method == "Straight Line":
if straight_line_idx and i == max(straight_line_idx) - 1:
book = self.get('finance_books')[cint(d.finance_book_id) - 1]
depreciation_amount += flt(value_after_depreciation -
flt(self.expected_value_after_useful_life), d.precision("depreciation_amount"))
flt(book.expected_value_after_useful_life), d.precision("depreciation_amount"))
d.depreciation_amount = depreciation_amount
accumulated_depreciation += d.depreciation_amount
d.accumulated_depreciation_amount = flt(accumulated_depreciation,
d.precision("accumulated_depreciation_amount"))
def get_depreciation_amount(self, depreciable_value):
if self.depreciation_method in ("Straight Line", "Manual"):
depreciation_amount = (flt(self.value_after_depreciation) -
flt(self.expected_value_after_useful_life)) / (cint(self.total_number_of_depreciations) -
cint(self.number_of_depreciations_booked))
else:
factor = 200.0 / self.total_number_of_depreciations
def get_value_after_depreciation(self, idx):
return flt(self.get('finance_books')[cint(idx)-1].value_after_depreciation)
def get_depreciation_amount(self, depreciable_value, total_number_of_depreciations, row):
percentage_value = 100.0 if row.depreciation_method == 'Written Down Value' else 200.0
factor = percentage_value / total_number_of_depreciations
depreciation_amount = flt(depreciable_value * factor / 100, 0)
value_after_depreciation = flt(depreciable_value) - depreciation_amount
if value_after_depreciation < flt(self.expected_value_after_useful_life):
depreciation_amount = flt(depreciable_value) - flt(self.expected_value_after_useful_life)
if value_after_depreciation < flt(row.expected_value_after_useful_life):
depreciation_amount = flt(depreciable_value) - flt(row.expected_value_after_useful_life)
return depreciation_amount
def get_depreciation_amount_prorata_temporis(self, depreciable_value, start_date=None, end_date=None):
def get_depreciation_amount_prorata_temporis(self, depreciable_value, row, start_date=None, end_date=None):
if start_date and end_date:
prorata_temporis = min(abs(flt(date_diff(str(end_date), str(start_date)))) / flt(frappe.db.get_value("Asset Settings", None, "number_of_days_in_fiscal_year")), 1)
else:
prorata_temporis = 1
if self.depreciation_method in ("Straight Line", "Manual"):
depreciation_amount = (flt(self.value_after_depreciation) -
flt(self.expected_value_after_useful_life)) / (cint(self.total_number_of_depreciations) -
if row.depreciation_method in ("Straight Line", "Manual"):
depreciation_amount = (flt(row.value_after_depreciation) -
flt(row.expected_value_after_useful_life)) / (cint(row.total_number_of_depreciations) -
cint(self.number_of_depreciations_booked)) * prorata_temporis
else:
depreciation_amount = self.get_depreciation_amount(depreciable_value, row)
return depreciation_amount
else:
self.get_depreciation_amount(depreciable_value)
def validate_expected_value_after_useful_life(self):
for row in self.get('finance_books'):
accumulated_depreciation_after_full_schedule = \
max([d.accumulated_depreciation_amount for d in self.get("schedules")])
max([d.accumulated_depreciation_amount for d in self.get("schedules") if d.finance_book_id == row.idx])
asset_value_after_full_schedule = flt(flt(self.gross_purchase_amount) -
flt(accumulated_depreciation_after_full_schedule),
self.precision('expected_value_after_useful_life'))
self.precision('gross_purchase_amount'))
if self.expected_value_after_useful_life < asset_value_after_full_schedule:
frappe.throw(_("Expected value after useful life must be greater than or equal to {0}")
.format(asset_value_after_full_schedule))
if row.expected_value_after_useful_life < asset_value_after_full_schedule:
frappe.throw(_("Depreciation Row {0}: Expected value after useful life must be greater than or equal to {1}")
.format(row.idx, asset_value_after_full_schedule))
def validate_cancellation(self):
if self.status not in ("Submitted", "Partially Depreciated", "Fully Depreciated"):
@ -219,6 +263,9 @@ class Asset(Document):
if self.purchase_invoice:
frappe.throw(_("Please cancel Purchase Invoice {0} first").format(self.purchase_invoice))
if self.purchase_receipt:
frappe.throw(_("Please cancel Purchase Receipt {0} first").format(self.purchase_receipt))
def delete_depreciation_entries(self):
for d in self.get("schedules"):
if d.journal_entry:
@ -240,9 +287,15 @@ class Asset(Document):
status = "Draft"
elif self.docstatus == 1:
status = "Submitted"
expected_value_after_useful_life = flt(sum([d.expected_value_after_useful_life
for d in self.get('finance_books')]))
value_after_depreciation = flt(sum([d.value_after_depreciation
for d in self.get('finance_books')]))
if self.journal_entry_for_scrap:
status = "Scrapped"
elif flt(self.value_after_depreciation) <= flt(self.expected_value_after_useful_life):
elif flt(value_after_depreciation) <= expected_value_after_useful_life:
status = "Fully Depreciated"
elif flt(self.value_after_depreciation) < flt(self.gross_purchase_amount):
status = 'Partially Depreciated'
@ -250,6 +303,45 @@ class Asset(Document):
status = "Cancelled"
return status
def update_stock_movement(self):
asset_movement = frappe.db.get_value('Asset Movement',
{'asset': self.name, 'reference_name': self.purchase_receipt, 'docstatus': 0}, 'name')
if asset_movement:
doc = frappe.get_doc('Asset Movement', asset_movement)
doc.submit()
def make_gl_entries(self):
if self.purchase_receipt and self.purchase_receipt_amount:
from erpnext.accounts.general_ledger import make_gl_entries
gl_entries = []
cwip_account = get_cwip_account(self.name, self.asset_category, self.company)
fixed_aseet_account = get_asset_category_account(self.name, 'fixed_asset_account',
asset_category = self.asset_category, company = self.company)
gl_entries.append(self.get_gl_dict({
"account": cwip_account,
"against": fixed_aseet_account,
"remarks": self.get("remarks") or _("Accounting Entry for Asset"),
"posting_date": self.available_for_use_date,
"credit": self.purchase_receipt_amount,
"credit_in_account_currency": self.purchase_receipt_amount
}))
gl_entries.append(self.get_gl_dict({
"account": fixed_aseet_account,
"against": cwip_account,
"remarks": self.get("remarks") or _("Accounting Entry for Asset"),
"posting_date": self.available_for_use_date,
"debit": self.purchase_receipt_amount,
"debit_in_account_currency": self.purchase_receipt_amount
}))
make_gl_entries(gl_entries)
self.db_set('booked_fixed_asset', 1)
def update_maintenance_status():
assets = frappe.get_all('Asset', filters = {'docstatus': 1, 'maintenance_required': 1})
@ -260,6 +352,18 @@ def update_maintenance_status():
if frappe.db.exists('Asset Repair', {'asset_name': asset.name, 'repair_status': 'Pending'}):
asset.set_status('Out of Order')
def make_post_gl_entry():
assets = frappe.db.sql_list(""" select name from `tabAsset`
where ifnull(booked_fixed_asset, 0) = 0 and available_for_use_date = %s""", nowdate())
for asset in assets:
doc = frappe.get_doc('Asset', asset)
doc.make_gl_entries()
def get_asset_naming_series():
meta = frappe.get_meta('Asset')
return meta.get_field("naming_series").options
@frappe.whitelist()
def make_purchase_invoice(asset, item_code, gross_purchase_amount, company, posting_date):
pi = frappe.new_doc("Purchase Invoice")
@ -271,7 +375,7 @@ def make_purchase_invoice(asset, item_code, gross_purchase_amount, company, post
"item_code": item_code,
"is_fixed_asset": 1,
"asset": asset,
"expense_account": get_fixed_asset_account(asset),
"expense_account": get_asset_category_account(asset, 'fixed_asset_account'),
"qty": 1,
"price_list_rate": gross_purchase_amount,
"rate": gross_purchase_amount
@ -280,7 +384,7 @@ def make_purchase_invoice(asset, item_code, gross_purchase_amount, company, post
return pi
@frappe.whitelist()
def make_sales_invoice(asset, item_code, company):
def make_sales_invoice(asset, item_code, company, serial_no=None):
si = frappe.new_doc("Sales Invoice")
si.company = company
si.currency = frappe.db.get_value("Company", company, "default_currency")
@ -290,6 +394,7 @@ def make_sales_invoice(asset, item_code, company):
"is_fixed_asset": 1,
"asset": asset,
"income_account": disposal_account,
"serial_no": serial_no,
"cost_center": depreciation_cost_center,
"qty": 1
})
@ -322,17 +427,32 @@ def transfer_asset(args):
frappe.msgprint(_("Asset Movement record {0} created").format("<a href='#Form/Asset Movement/{0}'>{0}</a>".format(movement_entry.name)))
@frappe.whitelist()
def get_item_details(item_code):
asset_category = frappe.db.get_value("Item", item_code, "asset_category")
def get_item_details(item_code, asset_category=None):
if not asset_category:
frappe.throw(_("Please enter Asset Category in Item {0}").format(item_code))
ret = frappe.db.get_value("Asset Category", asset_category,
["depreciation_method", "total_number_of_depreciations", "frequency_of_depreciation"], as_dict=1)
ret.update({
"asset_category": asset_category
asset_category_doc = frappe.get_doc('Asset Category', asset_category)
books = []
for d in asset_category_doc.finance_books:
books.append({
'finance_book': d.finance_book,
'depreciation_method': d.depreciation_method,
'total_number_of_depreciations': d.total_number_of_depreciations,
'frequency_of_depreciation': d.frequency_of_depreciation,
'start_date': nowdate()
})
return ret
return books
def get_cwip_account(asset, asset_category=None, company=None):
cwip_account = get_asset_category_account(asset, 'capital_work_in_progress_account',
asset_category = asset_category, company = company)
if not cwip_account:
cwip_account = frappe.db.get_value('Company', company, 'capital_work_in_progress_account')
if not cwip_account:
frappe.throw(_("Set Capital Work In Progress Account in asset category {0} or company {1}")
.format(asset_category, company))
return cwip_account

View File

@ -1,6 +1,9 @@
def get_data():
return {
'fieldname': 'asset_name',
'non_standard_fieldnames': {
'Asset Movement': 'asset'
},
'transactions': [
{
'label': ['Maintenance'],
@ -9,6 +12,10 @@ def get_data():
{
'label': ['Repair'],
'items': ['Asset Repair']
},
{
'label': ['Movement'],
'items': ['Asset Movement']
}
]
}

View File

@ -5,7 +5,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import flt, today, getdate
from frappe.utils import flt, today, getdate, cint
def post_depreciation_entries(date=None):
# Return if automatic booking of asset depreciation is disabled
@ -47,6 +47,7 @@ def make_depreciation_entry(asset_name, date=None):
je.naming_series = depreciation_series
je.posting_date = d.schedule_date
je.company = asset.company
je.finance_book = d.finance_book
je.remark = "Depreciation Entry against {0} worth {1}".format(asset_name, d.depreciation_amount)
je.append("accounts", {
@ -68,9 +69,12 @@ def make_depreciation_entry(asset_name, date=None):
je.submit()
d.db_set("journal_entry", je.name)
asset.value_after_depreciation -= d.depreciation_amount
asset.db_set("value_after_depreciation", asset.value_after_depreciation)
idx = cint(d.finance_book_id)
finance_books = asset.get('finance_books')[idx - 1]
finance_books.value_after_depreciation -= d.depreciation_amount
finance_books.db_update()
asset.set_status()
return asset

View File

@ -0,0 +1,30 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Asset Adjustment', {
asset: function(frm) {
frm.trigger("set_current_asset_value");
},
finance_book: function(frm) {
frm.trigger("set_current_asset_value");
},
set_current_asset_value: function(frm) {
debugger
if (frm.doc.finance_book && frm.doc.asset) {
frm.call({
method: "erpnext.assets.doctype.asset_adjustment.asset_adjustment.get_current_asset_value",
args: {
asset: frm.doc.asset,
finance_book: frm.doc.finance_book
},
callback: function(r) {
if (r.message) {
frm.set_value('current_asset_value', r.message);
}
}
});
}
}
});

View File

@ -0,0 +1,437 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2018-05-11 00:22:43.695151",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "company",
"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": "Company",
"length": 0,
"no_copy": 0,
"options": "Company",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "asset",
"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": "Asset",
"length": 0,
"no_copy": 0,
"options": "Asset",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "asset_category",
"fieldtype": "Read Only",
"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": "Asset Category",
"length": 0,
"no_copy": 0,
"options": "asset.asset_category",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "finance_book",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Finance Book",
"length": 0,
"no_copy": 0,
"options": "Finance Book",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "journal_entry",
"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": "Journal Entry",
"length": 0,
"no_copy": 0,
"options": "Journal Entry",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_4",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "date",
"fieldtype": "Datetime",
"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": "Date",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "current_asset_value",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Current Asset Value",
"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": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "new_asset_value",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "New Asset Value",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "difference_amount",
"fieldtype": "Currency",
"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": "Difference Amount",
"length": 0,
"no_copy": 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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "amended_from",
"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",
"length": 0,
"no_copy": 1,
"options": "Asset Adjustment",
"permlevel": 0,
"print_hide": 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,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 1,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-05-11 21:45:03.459696",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Adjustment",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 1,
"apply_user_permissions": 0,
"cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 1,
"write": 1
},
{
"amend": 1,
"apply_user_permissions": 0,
"cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User",
"set_user_permissions": 0,
"share": 1,
"submit": 1,
"write": 1
},
{
"amend": 1,
"apply_user_permissions": 0,
"cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 1,
"write": 1
}
],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "asset",
"track_changes": 1,
"track_seen": 0
}

View File

@ -0,0 +1,103 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import flt, getdate, cint, date_diff
from erpnext.assets.doctype.asset.depreciation import get_depreciation_accounts
from frappe.model.document import Document
class AssetAdjustment(Document):
def validate(self):
self.set_difference_amount()
self.set_current_asset_value()
def on_submit(self):
self.make_depreciation_entry()
self.reschedule_depreciations()
def on_cancel(self):
if self.journal_entry:
frappe.throw(_("Cancel the journal entry {0} first").format(self.journal_entry))
def set_difference_amount(self):
self.difference_amount = flt(self.current_asset_value - self.new_asset_value)
def set_current_asset_value(self):
if not self.current_asset_value and self.asset and self.finance_book:
self.current_asset_value = get_current_asset_value(self.asset, self.finance_book)
def make_depreciation_entry(self):
asset = frappe.get_doc("Asset", self.asset)
fixed_asset_account, accumulated_depreciation_account, depreciation_expense_account = \
get_depreciation_accounts(asset)
depreciation_cost_center, depreciation_series = frappe.db.get_value("Company", asset.company,
["depreciation_cost_center", "series_for_depreciation_entry"])
je = frappe.new_doc("Journal Entry")
je.voucher_type = "Depreciation Entry"
je.naming_series = depreciation_series
je.posting_date = self.date
je.company = self.company
je.remark = "Depreciation Entry against {0} worth {1}".format(self.asset, self.difference_amount)
je.append("accounts", {
"account": accumulated_depreciation_account,
"credit_in_account_currency": self.difference_amount,
})
je.append("accounts", {
"account": depreciation_expense_account,
"debit_in_account_currency": self.difference_amount,
"cost_center": depreciation_cost_center
})
je.flags.ignore_permissions = True
je.submit()
self.db_set("journal_entry", je.name)
def reschedule_depreciations(self):
asset = frappe.get_doc('Asset', self.asset)
for d in asset.finance_books:
d.value_after_depreciation = self.new_asset_value
if d.depreciation_method in ("Straight Line", "Manual"):
end_date = max([s.schedule_date for s in asset.schedules if cint(s.finance_book_id) == d.idx])
total_days = date_diff(end_date, self.date)
rate_per_day = flt(d.value_after_depreciation) / flt(total_days)
from_date = self.date
else:
no_of_depreciations = len([e.name for e in asset.schedules
if (cint(s.finance_book_id) == d.idx and not e.journal_entry)])
value_after_depreciation = d.value_after_depreciation
for data in asset.schedules:
if cint(data.finance_book_id) == d.idx and not data.journal_entry:
if d.depreciation_method in ("Straight Line", "Manual"):
days = date_diff(data.schedule_date, from_date)
depreciation_amount = days * rate_per_day
from_date = data.schedule_date
else:
depreciation_amount = asset.get_depreciation_amount(value_after_depreciation,
no_of_depreciations, d)
if depreciation_amount:
value_after_depreciation -= flt(depreciation_amount)
data.depreciation_amount = depreciation_amount
d.db_update()
asset.set_accumulated_depreciation(ignore_booked_entry=True)
for asset_data in asset.schedules:
if not asset_data.journal_entry:
asset_data.db_update()
@frappe.whitelist()
def get_current_asset_value(asset, finance_book):
return frappe.db.get_value('Asset Finance Book',
{'parent': asset, 'parenttype': 'Asset', 'finance_book': finance_book}, 'value_after_depreciation', debug=1)

View File

@ -2,15 +2,15 @@
// rename this file from _test_[name] to test_[name] to activate
// and remove above this line
QUnit.test("test: Health Insurance", function (assert) {
QUnit.test("test: Asset Adjustment", function (assert) {
let done = assert.async();
// number of asserts
assert.expect(1);
frappe.run_serially([
// insert a new Health Insurance
() => frappe.tests.make('Health Insurance', [
// insert a new Asset Adjustment
() => frappe.tests.make('Asset Adjustment', [
// values to be set
{key: 'value'}
]),

View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
import frappe
import unittest
class TestAssetAdjustment(unittest.TestCase):
pass

View File

@ -40,5 +40,16 @@ frappe.ui.form.on('Asset Category', {
};
});
frm.set_query('capital_work_in_progress_account', 'accounts', function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
return {
"filters": {
"account_type": "Capital Work in Progress",
"is_group": 0,
"company": d.company_name
}
};
});
}
});

View File

@ -43,38 +43,6 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "Straight Line",
"fieldname": "depreciation_method",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Depreciation Method",
"length": 0,
"no_copy": 0,
"options": "\nStraight Line\nDouble Declining Balance\nManual",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@ -110,16 +78,16 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "total_number_of_depreciations",
"fieldtype": "Int",
"fieldname": "finance_book_detail",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Total Number of Depreciations",
"label": "Finance Book Detail",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@ -129,7 +97,7 @@
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
@ -140,18 +108,19 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "frequency_of_depreciation",
"fieldtype": "Int",
"fieldname": "finance_books",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Frequency of Depreciation (Months)",
"label": "Finance Books",
"length": 0,
"no_copy": 0,
"options": "Asset Finance Book",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@ -159,7 +128,7 @@
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
@ -236,7 +205,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-12-01 15:14:25.645077",
"modified": "2018-05-12 14:56:04.116425",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Category",

View File

@ -10,6 +10,22 @@ from frappe.model.document import Document
class AssetCategory(Document):
def validate(self):
for field in ("total_number_of_depreciations", "frequency_of_depreciation"):
if cint(self.get(field))<1:
frappe.throw(_("{0} must be greater than 0").format(self.meta.get_label(field)), frappe.MandatoryError)
for d in self.finance_books:
for field in ("Total Number of Depreciations", "Frequency of Depreciation"):
if cint(d.get(frappe.scrub(field)))<1:
frappe.throw(_("Row {0}: {1} must be greater than 0").format(d.idx, field), frappe.MandatoryError)
@frappe.whitelist()
def get_asset_category_account(asset, fieldname, account=None, asset_category = None, company = None):
if not asset_category and company:
if account:
if frappe.db.get_value("Account", account, "account_type") != "Fixed Asset":
account=None
if not account:
asset_category, company = frappe.db.get_value("Asset", asset, ["asset_category", "company"])
account = frappe.db.get_value("Asset Category Account",
filters={"parent": asset_category, "company_name": company}, fieldname=fieldname)
return account

View File

@ -17,7 +17,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 3,
"columns": 2,
"fieldname": "company_name",
"fieldtype": "Link",
"hidden": 0,
@ -48,7 +48,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 3,
"columns": 2,
"fieldname": "fixed_asset_account",
"fieldtype": "Link",
"hidden": 0,
@ -135,6 +135,37 @@
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 2,
"fieldname": "capital_work_in_progress_account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Capital Work In Progress 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": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"has_web_view": 0,
@ -147,7 +178,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2017-11-28 16:54:12.252271",
"modified": "2018-05-10 17:06:48.839347",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Category Account",

View File

@ -0,0 +1,289 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2018-05-08 14:44:37.095570",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fieldname": "finance_book",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Finance Book",
"length": 0,
"no_copy": 0,
"options": "Finance Book",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "depreciation_method",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Depreciation Method",
"length": 0,
"no_copy": 0,
"options": "\nStraight Line\nDouble Declining Balance\nWritten Down Value\nManual",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "total_number_of_depreciations",
"fieldtype": "Int",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Total Number of Depreciations",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_5",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "frequency_of_depreciation",
"fieldtype": "Int",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Frequency of Depreciation (Months)",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:parent.doctype == 'Asset'",
"fieldname": "depreciation_start_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Depreciation Start Date",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0",
"depends_on": "eval:parent.doctype == 'Asset'",
"fieldname": "expected_value_after_useful_life",
"fieldtype": "Currency",
"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": "Expected Value After Useful Life",
"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": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "value_after_depreciation",
"fieldtype": "Currency",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Value After Depreciation",
"length": 0,
"no_copy": 1,
"options": "Company:company:default_currency",
"permlevel": 0,
"precision": "",
"print_hide": 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,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2018-05-12 14:56:44.800046",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Finance Book",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
}

View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
class AssetFinanceBook(Document):
pass

View File

@ -42,6 +42,7 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -73,6 +74,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -104,6 +106,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -135,6 +138,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -164,6 +168,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -195,6 +200,39 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "serial_no",
"fieldtype": "Small Text",
"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": "Serial No",
"length": 0,
"no_copy": 0,
"options": "asset_name.serial_no",
"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
},
{
@ -224,6 +262,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -255,6 +294,7 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -284,6 +324,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -315,6 +356,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -346,6 +388,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -376,6 +419,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -407,6 +451,7 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}
],
@ -420,7 +465,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-12-01 15:13:29.816396",
"modified": "2018-04-20 08:39:27.072622",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Maintenance",
@ -429,7 +474,6 @@
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@ -449,7 +493,6 @@
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,

View File

@ -11,6 +11,9 @@ from frappe.utils import add_days, add_months, add_years, getdate, nowdate
class AssetMaintenance(Document):
def validate(self):
if not self.serial_no:
self.serial_no = frappe.db.get_value("Asset", self.asset_name, 'serial_no')
for task in self.get('asset_maintenance_tasks'):
if task.end_date and (getdate(task.start_date) >= getdate(task.end_date)):
throw(_("Start date should be less than end date for task {0}").format(task.maintenance_task))

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