Merge branch 'develop' into fix_by_voucher_order_develop
This commit is contained in:
		
						commit
						85e2fd965a
					
				| @ -7,8 +7,8 @@ context('Form', () => { | ||||
| 	it('create a new opportunity', () => { | ||||
| 		cy.visit('/desk#Form/Opportunity/New Opportunity 1'); | ||||
| 		cy.get('.page-title').should('contain', 'Not Saved'); | ||||
| 		cy.fill_field('enquiry_from', 'Customer', 'Select'); | ||||
| 		cy.fill_field('customer', 'Test Customer', 'Link').blur(); | ||||
| 		cy.fill_field('opportunity_from', 'Customer', 'Select'); | ||||
| 		cy.fill_field('party_name', 'Test Customer', 'Link').blur(); | ||||
| 		cy.get('.primary-action').click(); | ||||
| 		cy.get('.page-title').should('contain', 'Open'); | ||||
| 		cy.get('.form-inner-toolbar button:contains("Lost")').click({ force: true }); | ||||
| @ -29,4 +29,3 @@ context('Form', () => { | ||||
| 		cy.get('.page-title').should('contain', 'Lost'); | ||||
| 	}); | ||||
| }); | ||||
| 
 | ||||
|  | ||||
| @ -5,7 +5,7 @@ import frappe | ||||
| from erpnext.hooks import regional_overrides | ||||
| from frappe.utils import getdate | ||||
| 
 | ||||
| __version__ = '11.1.20' | ||||
| __version__ = '11.1.39' | ||||
| 
 | ||||
| def get_default_company(user=None): | ||||
| 	'''Get default company for user''' | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| { | ||||
|     "country_code": "de",  | ||||
|     "name": "Germany - Kontenplan SKR04",  | ||||
|     "name": "SKR04 ohne Kontonummern",  | ||||
|     "tree": { | ||||
|         "Bilanz - Aktiva": { | ||||
|             "Anlageverm\u00f6gen": { | ||||
| @ -1384,7 +1384,6 @@ | ||||
|                         "Diskontertr\u00e4ge": {},  | ||||
|                         "Diskontertr\u00e4ge aus verbundenen Unternehmen": {},  | ||||
|                         "Laufende Ertr\u00e4ge aus Anteilen an Kapitalgesellschaften 100% / 50% steuerfrei": {}, | ||||
|                         "Laufende Ertr\u00e4ge aus Anteilen an Kapitalgesellschaften 100% / 50% steuerfrei": {},  | ||||
|                         "Sonstige Zinsen und \u00e4hnliche Ertr\u00e4ge 2": {},  | ||||
|                         "Sonstige Zinsen und \u00e4hnliche Ertr\u00e4ge aus verbundenen Unternehmen": {},  | ||||
|                         "Sonstige Zinsertr\u00e4ge": {},  | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -38,24 +38,24 @@ | ||||
|                 "Kas": { | ||||
|                     "Kas Mata Uang Lain": { | ||||
|                         "Kas USD": { | ||||
|                             "account_number": "1112.0010",  | ||||
|                             "account_number": "1112.001",  | ||||
|                             "account_type": "Cash" | ||||
|                         },  | ||||
|                         "account_number": "1112.000" | ||||
|                     },  | ||||
|                     "Kas Rupiah": { | ||||
|                         "Kas Besar": { | ||||
|                             "account_number": "1111.0020",  | ||||
|                             "account_number": "1111.002",  | ||||
|                             "account_type": "Cash" | ||||
|                         },  | ||||
|                         "Kas Kecil": { | ||||
|                             "account_number": "1111.0010",  | ||||
|                             "account_number": "1111.001",  | ||||
|                             "account_type": "Cash" | ||||
|                         },  | ||||
|                         "account_number": "1111.000",  | ||||
|                         "account_type": "Cash" | ||||
|                     },  | ||||
|                     "account_number": "1110.0000" | ||||
|                     "account_number": "1110.000" | ||||
|                 },  | ||||
|                 "Pendapatan Yang Akan di Terima": { | ||||
|                     "Pendapatan Yang di Terima": { | ||||
| @ -98,7 +98,7 @@ | ||||
|                     },  | ||||
|                     "account_number": "1130.000" | ||||
|                 },  | ||||
|                 "account_number": "1100.0000" | ||||
|                 "account_number": "1100.000" | ||||
|             },  | ||||
|             "Aktiva Tetap": { | ||||
|                 "Aktiva": { | ||||
| @ -121,20 +121,20 @@ | ||||
|                 "Investasi": { | ||||
|                     "Investasi": { | ||||
|                         "Deposito": { | ||||
|                             "account_number": "1231.003",  | ||||
|                             "account_number": "1231.300",  | ||||
|                             "is_group": 1 | ||||
|                         },  | ||||
|                         "Investai Saham": { | ||||
|                         "Investasi Saham": { | ||||
|                             "Investasi Saham": { | ||||
|                                 "account_number": "1231.0011" | ||||
|                                 "account_number": "1231.101" | ||||
|                             },  | ||||
|                             "account_number": "1231.001" | ||||
|                             "account_number": "1231.100" | ||||
|                         },  | ||||
|                         "Investasi Perumahan": { | ||||
|                             "Investasi Perumahan": { | ||||
|                                 "account_number": "1231.0021" | ||||
|                                 "account_number": "1231.201" | ||||
|                             },  | ||||
|                             "account_number": "1231.002" | ||||
|                             "account_number": "1231.200" | ||||
|                         },  | ||||
|                         "account_number": "1231.000" | ||||
|                     },  | ||||
| @ -142,7 +142,7 @@ | ||||
|                 },  | ||||
|                 "account_number": "1200.000" | ||||
|             },  | ||||
|             "account_number": "1000.0000",  | ||||
|             "account_number": "1000.000",  | ||||
|             "root_type": "Asset" | ||||
|         },  | ||||
|         "Beban": { | ||||
|  | ||||
| @ -0,0 +1,8 @@ | ||||
| // Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
 | ||||
| // For license information, please see license.txt
 | ||||
| 
 | ||||
| frappe.ui.form.on('Account Subtype', { | ||||
| 	refresh: function() { | ||||
| 
 | ||||
| 	} | ||||
| }); | ||||
							
								
								
									
										134
									
								
								erpnext/accounts/doctype/account_subtype/account_subtype.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								erpnext/accounts/doctype/account_subtype/account_subtype.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,134 @@ | ||||
| { | ||||
|  "allow_copy": 0,  | ||||
|  "allow_events_in_timeline": 0,  | ||||
|  "allow_guest_to_view": 0,  | ||||
|  "allow_import": 1,  | ||||
|  "allow_rename": 1,  | ||||
|  "autoname": "field:account_subtype",  | ||||
|  "beta": 0,  | ||||
|  "creation": "2018-10-25 15:46:08.054586",  | ||||
|  "custom": 0,  | ||||
|  "docstatus": 0,  | ||||
|  "doctype": "DocType",  | ||||
|  "document_type": "",  | ||||
|  "editable_grid": 1,  | ||||
|  "engine": "InnoDB",  | ||||
|  "fields": [ | ||||
|   { | ||||
|    "allow_bulk_edit": 0,  | ||||
|    "allow_in_quick_entry": 0,  | ||||
|    "allow_on_submit": 0,  | ||||
|    "bold": 0,  | ||||
|    "collapsible": 0,  | ||||
|    "columns": 0,  | ||||
|    "fieldname": "account_subtype",  | ||||
|    "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": "Account Subtype",  | ||||
|    "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": 1 | ||||
|   } | ||||
|  ],  | ||||
|  "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-10-25 15:47:03.841390",  | ||||
|  "modified_by": "Administrator",  | ||||
|  "module": "Accounts",  | ||||
|  "name": "Account Subtype",  | ||||
|  "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": 0,  | ||||
|  "track_seen": 0,  | ||||
|  "track_views": 0 | ||||
| } | ||||
| @ -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 AccountSubtype(Document): | ||||
| 	pass | ||||
| @ -0,0 +1,23 @@ | ||||
| /* eslint-disable */ | ||||
| // rename this file from _test_[name] to test_[name] to activate
 | ||||
| // and remove above this line
 | ||||
| 
 | ||||
| QUnit.test("test: Account Subtype", function (assert) { | ||||
| 	let done = assert.async(); | ||||
| 
 | ||||
| 	// number of asserts
 | ||||
| 	assert.expect(1); | ||||
| 
 | ||||
| 	frappe.run_serially([ | ||||
| 		// insert a new Account Subtype
 | ||||
| 		() => frappe.tests.make('Account Subtype', [ | ||||
| 			// values to be set
 | ||||
| 			{key: 'value'} | ||||
| 		]), | ||||
| 		() => { | ||||
| 			assert.equal(cur_frm.doc.key, 'value'); | ||||
| 		}, | ||||
| 		() => done() | ||||
| 	]); | ||||
| 
 | ||||
| }); | ||||
| @ -0,0 +1,9 @@ | ||||
| # -*- coding: utf-8 -*- | ||||
| # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors | ||||
| # See license.txt | ||||
| from __future__ import unicode_literals | ||||
| 
 | ||||
| import unittest | ||||
| 
 | ||||
| class TestAccountSubtype(unittest.TestCase): | ||||
| 	pass | ||||
							
								
								
									
										0
									
								
								erpnext/accounts/doctype/account_type/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								erpnext/accounts/doctype/account_type/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										8
									
								
								erpnext/accounts/doctype/account_type/account_type.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								erpnext/accounts/doctype/account_type/account_type.js
									
									
									
									
									
										Normal 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('Account Type', { | ||||
| 	refresh: function() { | ||||
| 
 | ||||
| 	} | ||||
| }); | ||||
							
								
								
									
										134
									
								
								erpnext/accounts/doctype/account_type/account_type.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								erpnext/accounts/doctype/account_type/account_type.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,134 @@ | ||||
| { | ||||
|  "allow_copy": 0,  | ||||
|  "allow_events_in_timeline": 0,  | ||||
|  "allow_guest_to_view": 0,  | ||||
|  "allow_import": 1,  | ||||
|  "allow_rename": 1,  | ||||
|  "autoname": "field:account_type",  | ||||
|  "beta": 0,  | ||||
|  "creation": "2018-10-25 15:45:45.789963",  | ||||
|  "custom": 0,  | ||||
|  "docstatus": 0,  | ||||
|  "doctype": "DocType",  | ||||
|  "document_type": "",  | ||||
|  "editable_grid": 1,  | ||||
|  "engine": "InnoDB",  | ||||
|  "fields": [ | ||||
|   { | ||||
|    "allow_bulk_edit": 0,  | ||||
|    "allow_in_quick_entry": 0,  | ||||
|    "allow_on_submit": 0,  | ||||
|    "bold": 0,  | ||||
|    "collapsible": 0,  | ||||
|    "columns": 0,  | ||||
|    "fieldname": "account_type",  | ||||
|    "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": "Account Type",  | ||||
|    "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": 1 | ||||
|   } | ||||
|  ],  | ||||
|  "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-10-25 15:46:51.042604",  | ||||
|  "modified_by": "Administrator",  | ||||
|  "module": "Accounts",  | ||||
|  "name": "Account Type",  | ||||
|  "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": 0,  | ||||
|  "track_seen": 0,  | ||||
|  "track_views": 0 | ||||
| } | ||||
							
								
								
									
										9
									
								
								erpnext/accounts/doctype/account_type/account_type.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								erpnext/accounts/doctype/account_type/account_type.py
									
									
									
									
									
										Normal 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 AccountType(Document): | ||||
| 	pass | ||||
							
								
								
									
										23
									
								
								erpnext/accounts/doctype/account_type/test_account_type.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								erpnext/accounts/doctype/account_type/test_account_type.js
									
									
									
									
									
										Normal 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: Account Type", function (assert) { | ||||
| 	let done = assert.async(); | ||||
| 
 | ||||
| 	// number of asserts
 | ||||
| 	assert.expect(1); | ||||
| 
 | ||||
| 	frappe.run_serially([ | ||||
| 		// insert a new Account Type
 | ||||
| 		() => frappe.tests.make('Account Type', [ | ||||
| 			// values to be set
 | ||||
| 			{key: 'value'} | ||||
| 		]), | ||||
| 		() => { | ||||
| 			assert.equal(cur_frm.doc.key, 'value'); | ||||
| 		}, | ||||
| 		() => done() | ||||
| 	]); | ||||
| 
 | ||||
| }); | ||||
| @ -0,0 +1,9 @@ | ||||
| # -*- coding: utf-8 -*- | ||||
| # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors | ||||
| # See license.txt | ||||
| from __future__ import unicode_literals | ||||
| 
 | ||||
| import unittest | ||||
| 
 | ||||
| class TestAccountType(unittest.TestCase): | ||||
| 	pass | ||||
| @ -5,6 +5,7 @@ | ||||
| from __future__ import unicode_literals | ||||
| import frappe | ||||
| from frappe.model.document import Document | ||||
| from frappe import _ | ||||
| 
 | ||||
| class AccountingPeriod(Document): | ||||
| 	def validate(self): | ||||
| @ -33,7 +34,7 @@ class AccountingPeriod(Document): | ||||
| 			}, as_dict=True) | ||||
| 
 | ||||
| 		if len(existing_accounting_period) > 0: | ||||
| 			frappe.throw("Accounting Period overlaps with {0}".format(existing_accounting_period[0].get("name"))) | ||||
| 			frappe.throw(_("Accounting Period overlaps with {0}".format(existing_accounting_period[0].get("name")))) | ||||
| 
 | ||||
| 	def get_doctypes_for_closing(self): | ||||
| 		docs_for_closing = [] | ||||
|  | ||||
| @ -1,203 +1,203 @@ | ||||
| { | ||||
|  "creation": "2013-06-24 15:49:57", | ||||
|  "description": "Settings for Accounts", | ||||
|  "doctype": "DocType", | ||||
|  "document_type": "Other", | ||||
|  "editable_grid": 1, | ||||
|  "engine": "InnoDB", | ||||
|  "field_order": [ | ||||
|   "auto_accounting_for_stock", | ||||
|   "acc_frozen_upto", | ||||
|   "frozen_accounts_modifier", | ||||
|   "determine_address_tax_category_from", | ||||
|   "column_break_4", | ||||
|   "credit_controller", | ||||
|   "check_supplier_invoice_uniqueness", | ||||
|   "make_payment_via_journal_entry", | ||||
|   "unlink_payment_on_cancellation_of_invoice", | ||||
|   "unlink_advance_payment_on_cancelation_of_order", | ||||
|   "book_asset_depreciation_entry_automatically", | ||||
|   "allow_cost_center_in_entry_of_bs_account", | ||||
|   "add_taxes_from_item_tax_template", | ||||
|   "automatically_fetch_payment_terms", | ||||
|   "print_settings", | ||||
|   "show_inclusive_tax_in_print", | ||||
|   "column_break_12", | ||||
|   "show_payment_schedule_in_print", | ||||
|   "currency_exchange_section", | ||||
|   "allow_stale", | ||||
|   "stale_days", | ||||
|   "report_settings_sb", | ||||
|   "use_custom_cash_flow" | ||||
|  ], | ||||
|  "fields": [ | ||||
|   { | ||||
|    "default": "1", | ||||
|    "description": "If enabled, the system will post accounting entries for inventory automatically.", | ||||
|    "fieldname": "auto_accounting_for_stock", | ||||
|    "fieldtype": "Check", | ||||
|    "hidden": 1, | ||||
|    "in_list_view": 1, | ||||
|    "label": "Make Accounting Entry For Every Stock Movement" | ||||
|   }, | ||||
|   { | ||||
|    "description": "Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.", | ||||
|    "fieldname": "acc_frozen_upto", | ||||
|    "fieldtype": "Date", | ||||
|    "in_list_view": 1, | ||||
|    "label": "Accounts Frozen Upto" | ||||
|   }, | ||||
|   { | ||||
|    "description": "Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts", | ||||
|    "fieldname": "frozen_accounts_modifier", | ||||
|    "fieldtype": "Link", | ||||
|    "in_list_view": 1, | ||||
|    "label": "Role Allowed to Set Frozen Accounts & Edit Frozen Entries", | ||||
|    "options": "Role" | ||||
|   }, | ||||
|   { | ||||
|    "default": "Billing Address", | ||||
|    "description": "Address used to determine Tax Category in transactions.", | ||||
|    "fieldname": "determine_address_tax_category_from", | ||||
|    "fieldtype": "Select", | ||||
|    "label": "Determine Address Tax Category From", | ||||
|    "options": "Billing Address\nShipping Address" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "column_break_4", | ||||
|    "fieldtype": "Column Break" | ||||
|   }, | ||||
|   { | ||||
|    "description": "Role that is allowed to submit transactions that exceed credit limits set.", | ||||
|    "fieldname": "credit_controller", | ||||
|    "fieldtype": "Link", | ||||
|    "in_list_view": 1, | ||||
|    "label": "Credit Controller", | ||||
|    "options": "Role" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "check_supplier_invoice_uniqueness", | ||||
|    "fieldtype": "Check", | ||||
|    "label": "Check Supplier Invoice Number Uniqueness" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "make_payment_via_journal_entry", | ||||
|    "fieldtype": "Check", | ||||
|    "label": "Make Payment via Journal Entry" | ||||
|   }, | ||||
|   { | ||||
|    "default": "1", | ||||
|    "fieldname": "unlink_payment_on_cancellation_of_invoice", | ||||
|    "fieldtype": "Check", | ||||
|    "label": "Unlink Payment on Cancellation of Invoice" | ||||
|   }, | ||||
|   { | ||||
|    "default": "1", | ||||
|    "fieldname": "unlink_advance_payment_on_cancelation_of_order", | ||||
|    "fieldtype": "Check", | ||||
|    "label": "Unlink Advance Payment on Cancelation of Order" | ||||
|   }, | ||||
|   { | ||||
|    "default": "1", | ||||
|    "fieldname": "book_asset_depreciation_entry_automatically", | ||||
|    "fieldtype": "Check", | ||||
|    "label": "Book Asset Depreciation Entry Automatically" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "allow_cost_center_in_entry_of_bs_account", | ||||
|    "fieldtype": "Check", | ||||
|    "label": "Allow Cost Center In Entry of Balance Sheet Account" | ||||
|   }, | ||||
|   { | ||||
|    "default": "1", | ||||
|    "fieldname": "add_taxes_from_item_tax_template", | ||||
|    "fieldtype": "Check", | ||||
|    "label": "Automatically Add Taxes and Charges from Item Tax Template" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "print_settings", | ||||
|    "fieldtype": "Section Break", | ||||
|    "label": "Print Settings" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "show_inclusive_tax_in_print", | ||||
|    "fieldtype": "Check", | ||||
|    "label": "Show Inclusive Tax In Print" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "column_break_12", | ||||
|    "fieldtype": "Column Break" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "show_payment_schedule_in_print", | ||||
|    "fieldtype": "Check", | ||||
|    "label": "Show Payment Schedule in Print" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "currency_exchange_section", | ||||
|    "fieldtype": "Section Break", | ||||
|    "label": "Currency Exchange Settings" | ||||
|   }, | ||||
|   { | ||||
|    "default": "1", | ||||
|    "fieldname": "allow_stale", | ||||
|    "fieldtype": "Check", | ||||
|    "in_list_view": 1, | ||||
|    "label": "Allow Stale Exchange Rates" | ||||
|   }, | ||||
|   { | ||||
|    "default": "1", | ||||
|    "depends_on": "eval:doc.allow_stale==0", | ||||
|    "fieldname": "stale_days", | ||||
|    "fieldtype": "Int", | ||||
|    "label": "Stale Days" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "report_settings_sb", | ||||
|    "fieldtype": "Section Break", | ||||
|    "label": "Report Settings" | ||||
|   }, | ||||
|   { | ||||
|    "default": "0", | ||||
|    "description": "Only select if you have setup Cash Flow Mapper documents", | ||||
|    "fieldname": "use_custom_cash_flow", | ||||
|    "fieldtype": "Check", | ||||
|    "label": "Use Custom Cash Flow Format" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "automatically_fetch_payment_terms", | ||||
|    "fieldtype": "Check", | ||||
|    "label": "Automatically Fetch Payment Terms" | ||||
|    "creation": "2013-06-24 15:49:57", | ||||
|    "description": "Settings for Accounts", | ||||
|    "doctype": "DocType", | ||||
|    "document_type": "Other", | ||||
|    "editable_grid": 1, | ||||
|    "engine": "InnoDB", | ||||
|    "field_order": [ | ||||
|     "auto_accounting_for_stock", | ||||
|     "acc_frozen_upto", | ||||
|     "frozen_accounts_modifier", | ||||
|     "determine_address_tax_category_from", | ||||
|     "column_break_4", | ||||
|     "credit_controller", | ||||
|     "check_supplier_invoice_uniqueness", | ||||
|     "make_payment_via_journal_entry", | ||||
|     "unlink_payment_on_cancellation_of_invoice", | ||||
|     "unlink_advance_payment_on_cancelation_of_order", | ||||
|     "book_asset_depreciation_entry_automatically", | ||||
|     "allow_cost_center_in_entry_of_bs_account", | ||||
|     "add_taxes_from_item_tax_template", | ||||
|     "automatically_fetch_payment_terms", | ||||
|     "print_settings", | ||||
|     "show_inclusive_tax_in_print", | ||||
|     "column_break_12", | ||||
|     "show_payment_schedule_in_print", | ||||
|     "currency_exchange_section", | ||||
|     "allow_stale", | ||||
|     "stale_days", | ||||
|     "report_settings_sb", | ||||
|     "use_custom_cash_flow" | ||||
|    ], | ||||
|    "fields": [ | ||||
|     { | ||||
|      "default": "1", | ||||
|      "description": "If enabled, the system will post accounting entries for inventory automatically.", | ||||
|      "fieldname": "auto_accounting_for_stock", | ||||
|      "fieldtype": "Check", | ||||
|      "hidden": 1, | ||||
|      "in_list_view": 1, | ||||
|      "label": "Make Accounting Entry For Every Stock Movement" | ||||
|     }, | ||||
|     { | ||||
|      "description": "Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.", | ||||
|      "fieldname": "acc_frozen_upto", | ||||
|      "fieldtype": "Date", | ||||
|      "in_list_view": 1, | ||||
|      "label": "Accounts Frozen Upto" | ||||
|     }, | ||||
|     { | ||||
|      "description": "Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts", | ||||
|      "fieldname": "frozen_accounts_modifier", | ||||
|      "fieldtype": "Link", | ||||
|      "in_list_view": 1, | ||||
|      "label": "Role Allowed to Set Frozen Accounts & Edit Frozen Entries", | ||||
|      "options": "Role" | ||||
|     }, | ||||
|     { | ||||
|      "default": "Billing Address", | ||||
|      "description": "Address used to determine Tax Category in transactions.", | ||||
|      "fieldname": "determine_address_tax_category_from", | ||||
|      "fieldtype": "Select", | ||||
|      "label": "Determine Address Tax Category From", | ||||
|      "options": "Billing Address\nShipping Address" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "column_break_4", | ||||
|      "fieldtype": "Column Break" | ||||
|     }, | ||||
|     { | ||||
|      "description": "Role that is allowed to submit transactions that exceed credit limits set.", | ||||
|      "fieldname": "credit_controller", | ||||
|      "fieldtype": "Link", | ||||
|      "in_list_view": 1, | ||||
|      "label": "Credit Controller", | ||||
|      "options": "Role" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "check_supplier_invoice_uniqueness", | ||||
|      "fieldtype": "Check", | ||||
|      "label": "Check Supplier Invoice Number Uniqueness" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "make_payment_via_journal_entry", | ||||
|      "fieldtype": "Check", | ||||
|      "label": "Make Payment via Journal Entry" | ||||
|     }, | ||||
|     { | ||||
|      "default": "1", | ||||
|      "fieldname": "unlink_payment_on_cancellation_of_invoice", | ||||
|      "fieldtype": "Check", | ||||
|      "label": "Unlink Payment on Cancellation of Invoice" | ||||
|     }, | ||||
|     { | ||||
|      "default": "1", | ||||
|      "fieldname": "unlink_advance_payment_on_cancelation_of_order", | ||||
|      "fieldtype": "Check", | ||||
|      "label": "Unlink Advance Payment on Cancelation of Order" | ||||
|     }, | ||||
|     { | ||||
|      "default": "1", | ||||
|      "fieldname": "book_asset_depreciation_entry_automatically", | ||||
|      "fieldtype": "Check", | ||||
|      "label": "Book Asset Depreciation Entry Automatically" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "allow_cost_center_in_entry_of_bs_account", | ||||
|      "fieldtype": "Check", | ||||
|      "label": "Allow Cost Center In Entry of Balance Sheet Account" | ||||
|     }, | ||||
|     { | ||||
|      "default": "1", | ||||
|      "fieldname": "add_taxes_from_item_tax_template", | ||||
|      "fieldtype": "Check", | ||||
|      "label": "Automatically Add Taxes and Charges from Item Tax Template" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "print_settings", | ||||
|      "fieldtype": "Section Break", | ||||
|      "label": "Print Settings" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "show_inclusive_tax_in_print", | ||||
|      "fieldtype": "Check", | ||||
|      "label": "Show Inclusive Tax In Print" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "column_break_12", | ||||
|      "fieldtype": "Column Break" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "show_payment_schedule_in_print", | ||||
|      "fieldtype": "Check", | ||||
|      "label": "Show Payment Schedule in Print" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "currency_exchange_section", | ||||
|      "fieldtype": "Section Break", | ||||
|      "label": "Currency Exchange Settings" | ||||
|     }, | ||||
|     { | ||||
|      "default": "1", | ||||
|      "fieldname": "allow_stale", | ||||
|      "fieldtype": "Check", | ||||
|      "in_list_view": 1, | ||||
|      "label": "Allow Stale Exchange Rates" | ||||
|     }, | ||||
|     { | ||||
|      "default": "1", | ||||
|      "depends_on": "eval:doc.allow_stale==0", | ||||
|      "fieldname": "stale_days", | ||||
|      "fieldtype": "Int", | ||||
|      "label": "Stale Days" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "report_settings_sb", | ||||
|      "fieldtype": "Section Break", | ||||
|      "label": "Report Settings" | ||||
|     }, | ||||
|     { | ||||
|      "default": "0", | ||||
|      "description": "Only select if you have setup Cash Flow Mapper documents", | ||||
|      "fieldname": "use_custom_cash_flow", | ||||
|      "fieldtype": "Check", | ||||
|      "label": "Use Custom Cash Flow Format" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "automatically_fetch_payment_terms", | ||||
|      "fieldtype": "Check", | ||||
|      "label": "Automatically Fetch Payment Terms" | ||||
|     } | ||||
|    ], | ||||
|    "icon": "icon-cog", | ||||
|    "idx": 1, | ||||
|    "issingle": 1, | ||||
|    "modified": "2019-04-28 18:20:55.789946", | ||||
|    "modified_by": "Administrator", | ||||
|    "module": "Accounts", | ||||
|    "name": "Accounts Settings", | ||||
|    "owner": "Administrator", | ||||
|    "permissions": [ | ||||
|     { | ||||
|      "create": 1, | ||||
|      "email": 1, | ||||
|      "print": 1, | ||||
|      "read": 1, | ||||
|      "role": "Accounts Manager", | ||||
|      "share": 1, | ||||
|      "write": 1 | ||||
|     }, | ||||
|     { | ||||
|      "read": 1, | ||||
|      "role": "Sales User" | ||||
|     }, | ||||
|     { | ||||
|      "read": 1, | ||||
|      "role": "Purchase User" | ||||
|     } | ||||
|    ], | ||||
|    "quick_entry": 1, | ||||
|    "sort_order": "ASC", | ||||
|    "track_changes": 1 | ||||
|   } | ||||
|  ], | ||||
|  "icon": "icon-cog", | ||||
|  "idx": 1, | ||||
|  "issingle": 1, | ||||
|  "modified": "2019-04-28 18:20:55.789946", | ||||
|  "modified_by": "Administrator", | ||||
|  "module": "Accounts", | ||||
|  "name": "Accounts Settings", | ||||
|  "owner": "Administrator", | ||||
|  "permissions": [ | ||||
|   { | ||||
|    "create": 1, | ||||
|    "email": 1, | ||||
|    "print": 1, | ||||
|    "read": 1, | ||||
|    "role": "Accounts Manager", | ||||
|    "share": 1, | ||||
|    "write": 1 | ||||
|   }, | ||||
|   { | ||||
|    "read": 1, | ||||
|    "role": "Sales User" | ||||
|   }, | ||||
|   { | ||||
|    "read": 1, | ||||
|    "role": "Purchase User" | ||||
|   } | ||||
|  ], | ||||
|  "quick_entry": 1, | ||||
|  "sort_order": "ASC", | ||||
|  "track_changes": 1 | ||||
| } | ||||
| @ -2,7 +2,29 @@ | ||||
| // For license information, please see license.txt
 | ||||
| 
 | ||||
| frappe.ui.form.on('Bank', { | ||||
| 	onload: function(frm) { | ||||
| 		add_fields_to_mapping_table(frm); | ||||
| 	}, | ||||
| 	refresh: function(frm) { | ||||
| 
 | ||||
| 		add_fields_to_mapping_table(frm); | ||||
| 	} | ||||
| }); | ||||
| 
 | ||||
| 
 | ||||
| let add_fields_to_mapping_table = function (frm) { | ||||
| 	let options = []; | ||||
| 
 | ||||
| 	frappe.model.with_doctype("Bank Transaction", function() { | ||||
| 		let meta = frappe.get_meta("Bank Transaction"); | ||||
| 		meta.fields.forEach(value => { | ||||
| 			if (!["Section Break", "Column Break"].includes(value.fieldtype)) { | ||||
| 				options.push(value.fieldname); | ||||
| 			} | ||||
| 		}); | ||||
| 	}); | ||||
| 
 | ||||
| 	frappe.meta.get_docfield("Bank Transaction Mapping", "bank_transaction_field", | ||||
| 		frm.doc.name).options = options; | ||||
| 
 | ||||
| 	frm.fields_dict.bank_transaction_mapping.grid.refresh(); | ||||
| }; | ||||
| @ -1,5 +1,6 @@ | ||||
| { | ||||
|  "allow_copy": 0,  | ||||
|  "allow_events_in_timeline": 0,  | ||||
|  "allow_guest_to_view": 0,  | ||||
|  "allow_import": 0,  | ||||
|  "allow_rename": 0,  | ||||
| @ -15,6 +16,7 @@ | ||||
|  "fields": [ | ||||
|   { | ||||
|    "allow_bulk_edit": 0,  | ||||
|    "allow_in_quick_entry": 0,  | ||||
|    "allow_on_submit": 0,  | ||||
|    "bold": 0,  | ||||
|    "collapsible": 0,  | ||||
| @ -42,6 +44,134 @@ | ||||
|    "search_index": 0,  | ||||
|    "set_only_once": 0,  | ||||
|    "translatable": 0,  | ||||
|    "unique": 1 | ||||
|   },  | ||||
|   { | ||||
|    "allow_bulk_edit": 0,  | ||||
|    "allow_in_quick_entry": 0,  | ||||
|    "allow_on_submit": 0,  | ||||
|    "bold": 0,  | ||||
|    "collapsible": 1,  | ||||
|    "columns": 0,  | ||||
|    "fieldname": "data_import_configuration_section",  | ||||
|    "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": "Data Import Configuration",  | ||||
|    "length": 0,  | ||||
|    "no_copy": 0,  | ||||
|    "permlevel": 0,  | ||||
|    "precision": "",  | ||||
|    "print_hide": 0,  | ||||
|    "print_hide_if_no_value": 0,  | ||||
|    "read_only": 0,  | ||||
|    "remember_last_selected_value": 0,  | ||||
|    "report_hide": 0,  | ||||
|    "reqd": 0,  | ||||
|    "search_index": 0,  | ||||
|    "set_only_once": 0,  | ||||
|    "translatable": 0,  | ||||
|    "unique": 0 | ||||
|   },  | ||||
|   { | ||||
|    "allow_bulk_edit": 0,  | ||||
|    "allow_in_quick_entry": 0,  | ||||
|    "allow_on_submit": 0,  | ||||
|    "bold": 0,  | ||||
|    "collapsible": 0,  | ||||
|    "columns": 0,  | ||||
|    "fieldname": "bank_transaction_mapping",  | ||||
|    "fieldtype": "Table",  | ||||
|    "hidden": 0,  | ||||
|    "ignore_user_permissions": 0,  | ||||
|    "ignore_xss_filter": 0,  | ||||
|    "in_filter": 0,  | ||||
|    "in_global_search": 0,  | ||||
|    "in_list_view": 0,  | ||||
|    "in_standard_filter": 0,  | ||||
|    "label": "Bank Transaction Mapping",  | ||||
|    "length": 0,  | ||||
|    "no_copy": 0,  | ||||
|    "options": "Bank Transaction Mapping",  | ||||
|    "permlevel": 0,  | ||||
|    "precision": "",  | ||||
|    "print_hide": 0,  | ||||
|    "print_hide_if_no_value": 0,  | ||||
|    "read_only": 0,  | ||||
|    "remember_last_selected_value": 0,  | ||||
|    "report_hide": 0,  | ||||
|    "reqd": 0,  | ||||
|    "search_index": 0,  | ||||
|    "set_only_once": 0,  | ||||
|    "translatable": 0,  | ||||
|    "unique": 0 | ||||
|   },  | ||||
|   { | ||||
|    "allow_bulk_edit": 0,  | ||||
|    "allow_in_quick_entry": 0,  | ||||
|    "allow_on_submit": 0,  | ||||
|    "bold": 0,  | ||||
|    "collapsible": 0,  | ||||
|    "columns": 0,  | ||||
|    "fieldname": "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_in_quick_entry": 0,  | ||||
|    "allow_on_submit": 0,  | ||||
|    "bold": 0,  | ||||
|    "collapsible": 0,  | ||||
|    "columns": 0,  | ||||
|    "fieldname": "plaid_access_token",  | ||||
|    "fieldtype": "Data",  | ||||
|    "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": "Plaid Access Token",  | ||||
|    "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,  | ||||
|    "translatable": 0,  | ||||
|    "unique": 0 | ||||
|   } | ||||
|  ],  | ||||
| @ -55,7 +185,7 @@ | ||||
|  "issingle": 0,  | ||||
|  "istable": 0,  | ||||
|  "max_attachments": 0,  | ||||
|  "modified": "2018-04-07 17:00:21.246202",  | ||||
|  "modified": "2018-11-27 16:12:13.938776",  | ||||
|  "modified_by": "Administrator",  | ||||
|  "module": "Accounts",  | ||||
|  "name": "Bank",  | ||||
| @ -64,7 +194,6 @@ | ||||
|  "permissions": [ | ||||
|   { | ||||
|    "amend": 0,  | ||||
|    "apply_user_permissions": 0,  | ||||
|    "cancel": 0,  | ||||
|    "create": 1,  | ||||
|    "delete": 1,  | ||||
| @ -90,5 +219,6 @@ | ||||
|  "sort_field": "modified",  | ||||
|  "sort_order": "DESC",  | ||||
|  "track_changes": 1,  | ||||
|  "track_seen": 0 | ||||
|  "track_seen": 0,  | ||||
|  "track_views": 0 | ||||
| } | ||||
| @ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
 | ||||
| // Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
 | ||||
| // For license information, please see license.txt
 | ||||
| 
 | ||||
| frappe.ui.form.on('Bank Account', { | ||||
| @ -29,5 +29,13 @@ frappe.ui.form.on('Bank Account', { | ||||
| 		else { | ||||
| 			frappe.contacts.render_address_and_contact(frm); | ||||
| 		} | ||||
| 
 | ||||
| 		if (frm.doc.integration_id) { | ||||
| 			frm.add_custom_button(__("Unlink external integrations"), function() { | ||||
| 				frappe.confirm(__("This action will unlink this account from any external service integrating ERPNext with your bank accounts. It cannot be undone. Are you certain ?"), function() { | ||||
| 					frm.set_value("integration_id", ""); | ||||
| 				}); | ||||
| 			}); | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -13,16 +13,47 @@ class BankAccount(Document): | ||||
| 		"""Load address and contacts in `__onload`""" | ||||
| 		load_address_and_contact(self) | ||||
| 
 | ||||
| 	def autoname(self): | ||||
| 		self.name = self.account_name + " - " + self.bank | ||||
| 
 | ||||
| 	def on_trash(self): | ||||
| 		delete_contact_and_address('BankAccount', self.name) | ||||
| 
 | ||||
| 	def validate(self): | ||||
| 		self.validate_company() | ||||
| 		self.validate_iban() | ||||
| 
 | ||||
| 	def validate_company(self): | ||||
| 		if self.is_company_account and not self.company: | ||||
| 			frappe.throw(_("Company is manadatory for company account")) | ||||
| 
 | ||||
| 	def validate_iban(self): | ||||
| 		''' | ||||
| 		Algorithm: https://en.wikipedia.org/wiki/International_Bank_Account_Number#Validating_the_IBAN | ||||
| 		''' | ||||
| 		# IBAN field is optional | ||||
| 		if not self.iban: | ||||
| 			return | ||||
| 
 | ||||
| 		def encode_char(c): | ||||
| 			# Position in the alphabet (A=1, B=2, ...) plus nine | ||||
| 			return str(9 + ord(c) - 64) | ||||
| 
 | ||||
| 		# remove whitespaces, upper case to get the right number from ord() | ||||
| 		iban = ''.join(self.iban.split(' ')).upper() | ||||
| 
 | ||||
| 		# Move country code and checksum from the start to the end | ||||
| 		flipped = iban[4:] + iban[:4] | ||||
| 
 | ||||
| 		# Encode characters as numbers | ||||
| 		encoded = [encode_char(c) if ord(c) >= 65 and ord(c) <= 90 else c for c in flipped] | ||||
| 
 | ||||
| 		to_check = int(''.join(encoded)) | ||||
| 
 | ||||
| 		if to_check % 97 != 1: | ||||
| 			frappe.throw(_('IBAN is not valid')) | ||||
| 
 | ||||
| 
 | ||||
| @frappe.whitelist() | ||||
| def make_bank_account(doctype, docname): | ||||
| 	doc = frappe.new_doc("Bank Account") | ||||
|  | ||||
| @ -4,9 +4,46 @@ | ||||
| from __future__ import unicode_literals | ||||
| 
 | ||||
| import frappe | ||||
| from  frappe import _ | ||||
| from  frappe import ValidationError | ||||
| import unittest | ||||
| 
 | ||||
| # test_records = frappe.get_test_records('Bank Account') | ||||
| 
 | ||||
| class TestBankAccount(unittest.TestCase): | ||||
| 	pass | ||||
| 
 | ||||
| 	def test_validate_iban(self): | ||||
| 		valid_ibans = [ | ||||
| 			'GB82 WEST 1234 5698 7654 32', | ||||
| 			'DE91 1000 0000 0123 4567 89', | ||||
| 			'FR76 3000 6000 0112 3456 7890 189' | ||||
| 		] | ||||
| 
 | ||||
| 		invalid_ibans = [ | ||||
| 			# wrong checksum (3rd place) | ||||
| 			'GB72 WEST 1234 5698 7654 32', | ||||
| 			'DE81 1000 0000 0123 4567 89', | ||||
| 			'FR66 3000 6000 0112 3456 7890 189' | ||||
| 		] | ||||
| 
 | ||||
| 		bank_account = frappe.get_doc({'doctype':'Bank Account'}) | ||||
| 
 | ||||
| 		try: | ||||
| 			bank_account.validate_iban() | ||||
| 		except AttributeError: | ||||
| 			msg = _('BankAccount.validate_iban() failed for empty IBAN') | ||||
| 			self.fail(msg=msg) | ||||
| 
 | ||||
| 		for iban in valid_ibans: | ||||
| 			bank_account.iban = iban | ||||
| 			try: | ||||
| 				bank_account.validate_iban() | ||||
| 			except ValidationError: | ||||
| 				msg = _('BankAccount.validate_iban() failed for valid IBAN {}'.format(iban)) | ||||
| 				self.fail(msg=msg) | ||||
| 
 | ||||
| 		for not_iban in invalid_ibans: | ||||
| 			bank_account.iban = not_iban | ||||
| 			msg = _('BankAccount.validate_iban() accepted invalid IBAN {}'.format(not_iban)) | ||||
| 			with self.assertRaises(ValidationError, msg=msg): | ||||
| 				bank_account.validate_iban() | ||||
|  | ||||
| @ -48,7 +48,7 @@ class BankStatementTransactionEntry(Document): | ||||
| 
 | ||||
| 	def get_statement_headers(self): | ||||
| 		if not self.bank_settings: | ||||
| 			frappe.throw("Bank Data mapper doesn't exist") | ||||
| 			frappe.throw(_("Bank Data mapper doesn't exist")) | ||||
| 		mapper_doc = frappe.get_doc("Bank Statement Settings", self.bank_settings) | ||||
| 		headers = {entry.mapped_header:entry.stmt_header for entry in mapper_doc.header_items} | ||||
| 		return headers | ||||
| @ -57,7 +57,7 @@ class BankStatementTransactionEntry(Document): | ||||
| 		if self.bank_statement is None: return | ||||
| 		filename = self.bank_statement.split("/")[-1] | ||||
| 		if (len(self.new_transaction_items + self.reconciled_transaction_items) > 0): | ||||
| 			frappe.throw("Transactions already retreived from the statement") | ||||
| 			frappe.throw(_("Transactions already retreived from the statement")) | ||||
| 
 | ||||
| 		date_format = frappe.get_value("Bank Statement Settings", self.bank_settings, "date_format") | ||||
| 		if (date_format is None): | ||||
| @ -314,7 +314,7 @@ class BankStatementTransactionEntry(Document): | ||||
| 			try: | ||||
| 				reconcile_against_document(lst) | ||||
| 			except: | ||||
| 				frappe.throw("Exception occurred while reconciling {0}".format(payment.reference_name)) | ||||
| 				frappe.throw(_("Exception occurred while reconciling {0}".format(payment.reference_name))) | ||||
| 
 | ||||
| 	def submit_payment_entries(self): | ||||
| 		for payment in self.new_transaction_items: | ||||
| @ -414,7 +414,7 @@ def get_transaction_entries(filename, headers): | ||||
| 	elif (filename.lower().endswith("xls")): | ||||
| 		rows = get_rows_from_xls_file(filename) | ||||
| 	else: | ||||
| 		frappe.throw("Only .csv and .xlsx files are supported currently") | ||||
| 		frappe.throw(_("Only .csv and .xlsx files are supported currently")) | ||||
| 
 | ||||
| 	stmt_headers = headers.values() | ||||
| 	for row in rows: | ||||
|  | ||||
| @ -0,0 +1,32 @@ | ||||
| // Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
 | ||||
| // For license information, please see license.txt
 | ||||
| 
 | ||||
| frappe.ui.form.on('Bank Transaction', { | ||||
| 	onload(frm) { | ||||
| 		frm.set_query('payment_document', 'payment_entries', function() { | ||||
| 			return { | ||||
| 				"filters": { | ||||
| 					"name": ["in", ["Payment Entry", "Journal Entry", "Sales Invoice", "Purchase Invoice", "Expense Claim"]] | ||||
| 				} | ||||
| 			}; | ||||
| 		}); | ||||
| 	} | ||||
| }); | ||||
| 
 | ||||
| frappe.ui.form.on('Bank Transaction Payments', { | ||||
| 	payment_entries_remove: function(frm, cdt, cdn) { | ||||
| 		update_clearance_date(frm, cdt, cdn); | ||||
| 	} | ||||
| }); | ||||
| 
 | ||||
| const update_clearance_date = (frm, cdt, cdn) => { | ||||
| 	if (frm.doc.docstatus === 1) { | ||||
| 		frappe.xcall('erpnext.accounts.doctype.bank_transaction.bank_transaction.unclear_reference_payment', | ||||
| 			{doctype: cdt, docname: cdn}) | ||||
| 			.then(e => { | ||||
| 				if (e == "success") { | ||||
| 					frappe.show_alert({message:__("Document {0} successfully uncleared", [e]), indicator:'green'}); | ||||
| 				} | ||||
| 			}); | ||||
| 	} | ||||
| }; | ||||
							
								
								
									
										833
									
								
								erpnext/accounts/doctype/bank_transaction/bank_transaction.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										833
									
								
								erpnext/accounts/doctype/bank_transaction/bank_transaction.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,833 @@ | ||||
| { | ||||
|  "allow_copy": 0, | ||||
|  "allow_events_in_timeline": 0, | ||||
|  "allow_guest_to_view": 0, | ||||
|  "allow_import": 1, | ||||
|  "allow_rename": 0, | ||||
|  "autoname": "naming_series:", | ||||
|  "beta": 0, | ||||
|  "creation": "2018-10-22 18:19:02.784533", | ||||
|  "custom": 0, | ||||
|  "docstatus": 0, | ||||
|  "doctype": "DocType", | ||||
|  "document_type": "", | ||||
|  "editable_grid": 1, | ||||
|  "engine": "InnoDB", | ||||
|  "fields": [ | ||||
|   { | ||||
|    "allow_bulk_edit": 0, | ||||
|    "allow_in_quick_entry": 0, | ||||
|    "allow_on_submit": 0, | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "default": "ACC-BTN-.YYYY.-", | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "naming_series", | ||||
|    "fieldtype": "Select", | ||||
|    "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": "Series", | ||||
|    "length": 0, | ||||
|    "no_copy": 1, | ||||
|    "options": "ACC-BTN-.YYYY.-", | ||||
|    "permlevel": 0, | ||||
|    "precision": "", | ||||
|    "print_hide": 1, | ||||
|    "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": 1, | ||||
|    "translatable": 0, | ||||
|    "unique": 0 | ||||
|   }, | ||||
|   { | ||||
|    "allow_bulk_edit": 0, | ||||
|    "allow_in_quick_entry": 0, | ||||
|    "allow_on_submit": 0, | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "date", | ||||
|    "fieldtype": "Date", | ||||
|    "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, | ||||
|    "translatable": 0, | ||||
|    "unique": 0 | ||||
|   }, | ||||
|   { | ||||
|    "allow_bulk_edit": 0, | ||||
|    "allow_in_quick_entry": 0, | ||||
|    "allow_on_submit": 0, | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 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_in_quick_entry": 0, | ||||
|    "allow_on_submit": 0, | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "default": "Pending", | ||||
|    "fetch_if_empty": 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": 1, | ||||
|    "label": "Status", | ||||
|    "length": 0, | ||||
|    "no_copy": 0, | ||||
|    "options": "\nPending\nSettled\nUnreconciled\nReconciled", | ||||
|    "permlevel": 0, | ||||
|    "precision": "", | ||||
|    "print_hide": 0, | ||||
|    "print_hide_if_no_value": 0, | ||||
|    "read_only": 0, | ||||
|    "remember_last_selected_value": 0, | ||||
|    "report_hide": 0, | ||||
|    "reqd": 0, | ||||
|    "search_index": 0, | ||||
|    "set_only_once": 0, | ||||
|    "translatable": 0, | ||||
|    "unique": 0 | ||||
|   }, | ||||
|   { | ||||
|    "allow_bulk_edit": 0, | ||||
|    "allow_in_quick_entry": 0, | ||||
|    "allow_on_submit": 0, | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "bank_account", | ||||
|    "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": 1, | ||||
|    "label": "Bank Account", | ||||
|    "length": 0, | ||||
|    "no_copy": 0, | ||||
|    "options": "Bank 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, | ||||
|    "translatable": 0, | ||||
|    "unique": 0 | ||||
|   }, | ||||
|   { | ||||
|    "allow_bulk_edit": 0, | ||||
|    "allow_in_quick_entry": 0, | ||||
|    "allow_on_submit": 0, | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "default": "", | ||||
|    "fetch_from": "bank_account.company", | ||||
|    "fetch_if_empty": 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": 1, | ||||
|    "label": "Company", | ||||
|    "length": 0, | ||||
|    "no_copy": 0, | ||||
|    "options": "Company", | ||||
|    "permlevel": 0, | ||||
|    "precision": "", | ||||
|    "print_hide": 0, | ||||
|    "print_hide_if_no_value": 0, | ||||
|    "read_only": 1, | ||||
|    "remember_last_selected_value": 0, | ||||
|    "report_hide": 0, | ||||
|    "reqd": 0, | ||||
|    "search_index": 0, | ||||
|    "set_only_once": 0, | ||||
|    "translatable": 0, | ||||
|    "unique": 0 | ||||
|   }, | ||||
|   { | ||||
|    "allow_bulk_edit": 0, | ||||
|    "allow_in_quick_entry": 0, | ||||
|    "allow_on_submit": 0, | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 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_in_quick_entry": 0, | ||||
|    "allow_on_submit": 0, | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "debit", | ||||
|    "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": "Debit", | ||||
|    "length": 0, | ||||
|    "no_copy": 0, | ||||
|    "permlevel": 0, | ||||
|    "precision": "", | ||||
|    "print_hide": 0, | ||||
|    "print_hide_if_no_value": 0, | ||||
|    "read_only": 0, | ||||
|    "remember_last_selected_value": 0, | ||||
|    "report_hide": 0, | ||||
|    "reqd": 0, | ||||
|    "search_index": 0, | ||||
|    "set_only_once": 0, | ||||
|    "translatable": 0, | ||||
|    "unique": 0 | ||||
|   }, | ||||
|   { | ||||
|    "allow_bulk_edit": 0, | ||||
|    "allow_in_quick_entry": 0, | ||||
|    "allow_on_submit": 0, | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "credit", | ||||
|    "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": "Credit", | ||||
|    "length": 0, | ||||
|    "no_copy": 0, | ||||
|    "permlevel": 0, | ||||
|    "precision": "", | ||||
|    "print_hide": 0, | ||||
|    "print_hide_if_no_value": 0, | ||||
|    "read_only": 0, | ||||
|    "remember_last_selected_value": 0, | ||||
|    "report_hide": 0, | ||||
|    "reqd": 0, | ||||
|    "search_index": 0, | ||||
|    "set_only_once": 0, | ||||
|    "translatable": 0, | ||||
|    "unique": 0 | ||||
|   }, | ||||
|   { | ||||
|    "allow_bulk_edit": 0, | ||||
|    "allow_in_quick_entry": 0, | ||||
|    "allow_on_submit": 0, | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "column_break_7", | ||||
|    "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_in_quick_entry": 0, | ||||
|    "allow_on_submit": 0, | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "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": "Currency", | ||||
|    "length": 0, | ||||
|    "no_copy": 0, | ||||
|    "options": "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, | ||||
|    "translatable": 0, | ||||
|    "unique": 0 | ||||
|   }, | ||||
|   { | ||||
|    "allow_bulk_edit": 0, | ||||
|    "allow_in_quick_entry": 0, | ||||
|    "allow_on_submit": 0, | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "section_break_10", | ||||
|    "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_in_quick_entry": 0, | ||||
|    "allow_on_submit": 0, | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "description", | ||||
|    "fieldtype": "Small Text", | ||||
|    "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": "Description", | ||||
|    "length": 0, | ||||
|    "no_copy": 0, | ||||
|    "permlevel": 0, | ||||
|    "precision": "", | ||||
|    "print_hide": 0, | ||||
|    "print_hide_if_no_value": 0, | ||||
|    "read_only": 0, | ||||
|    "remember_last_selected_value": 0, | ||||
|    "report_hide": 0, | ||||
|    "reqd": 0, | ||||
|    "search_index": 0, | ||||
|    "set_only_once": 0, | ||||
|    "translatable": 0, | ||||
|    "unique": 0 | ||||
|   }, | ||||
|   { | ||||
|    "allow_bulk_edit": 0, | ||||
|    "allow_in_quick_entry": 0, | ||||
|    "allow_on_submit": 0, | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "section_break_14", | ||||
|    "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_in_quick_entry": 0, | ||||
|    "allow_on_submit": 0, | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "reference_number", | ||||
|    "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": "Reference Number", | ||||
|    "length": 0, | ||||
|    "no_copy": 0, | ||||
|    "permlevel": 0, | ||||
|    "precision": "", | ||||
|    "print_hide": 0, | ||||
|    "print_hide_if_no_value": 0, | ||||
|    "read_only": 0, | ||||
|    "remember_last_selected_value": 0, | ||||
|    "report_hide": 0, | ||||
|    "reqd": 0, | ||||
|    "search_index": 0, | ||||
|    "set_only_once": 0, | ||||
|    "translatable": 0, | ||||
|    "unique": 0 | ||||
|   }, | ||||
|   { | ||||
|    "allow_bulk_edit": 0, | ||||
|    "allow_in_quick_entry": 0, | ||||
|    "allow_on_submit": 0, | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "transaction_id", | ||||
|    "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": "Transaction ID", | ||||
|    "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": 1 | ||||
|   }, | ||||
|   { | ||||
|    "allow_bulk_edit": 0, | ||||
|    "allow_in_quick_entry": 0, | ||||
|    "allow_on_submit": 1, | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "payment_entries", | ||||
|    "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": "Payment Entries", | ||||
|    "length": 0, | ||||
|    "no_copy": 0, | ||||
|    "options": "Bank Transaction Payments", | ||||
|    "permlevel": 0, | ||||
|    "precision": "", | ||||
|    "print_hide": 0, | ||||
|    "print_hide_if_no_value": 0, | ||||
|    "read_only": 0, | ||||
|    "remember_last_selected_value": 0, | ||||
|    "report_hide": 0, | ||||
|    "reqd": 0, | ||||
|    "search_index": 0, | ||||
|    "set_only_once": 0, | ||||
|    "translatable": 0, | ||||
|    "unique": 0 | ||||
|   }, | ||||
|   { | ||||
|    "allow_bulk_edit": 0, | ||||
|    "allow_in_quick_entry": 0, | ||||
|    "allow_on_submit": 0, | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "section_break_18", | ||||
|    "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_in_quick_entry": 0, | ||||
|    "allow_on_submit": 0, | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "allocated_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": "Allocated Amount", | ||||
|    "length": 0, | ||||
|    "no_copy": 0, | ||||
|    "permlevel": 0, | ||||
|    "precision": "", | ||||
|    "print_hide": 0, | ||||
|    "print_hide_if_no_value": 0, | ||||
|    "read_only": 0, | ||||
|    "remember_last_selected_value": 0, | ||||
|    "report_hide": 0, | ||||
|    "reqd": 0, | ||||
|    "search_index": 0, | ||||
|    "set_only_once": 0, | ||||
|    "translatable": 0, | ||||
|    "unique": 0 | ||||
|   }, | ||||
|   { | ||||
|    "allow_bulk_edit": 0, | ||||
|    "allow_in_quick_entry": 0, | ||||
|    "allow_on_submit": 0, | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 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": "Bank Transaction", | ||||
|    "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 | ||||
|   }, | ||||
|   { | ||||
|    "allow_bulk_edit": 0, | ||||
|    "allow_in_quick_entry": 0, | ||||
|    "allow_on_submit": 0, | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "column_break_17", | ||||
|    "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_in_quick_entry": 0, | ||||
|    "allow_on_submit": 0, | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "depends_on": "", | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "unallocated_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": "Unallocated Amount", | ||||
|    "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": 1, | ||||
|  "issingle": 0, | ||||
|  "istable": 0, | ||||
|  "max_attachments": 0, | ||||
|  "modified": "2019-05-11 05:27:55.244721", | ||||
|  "modified_by": "Administrator", | ||||
|  "module": "Accounts", | ||||
|  "name": "Bank Transaction", | ||||
|  "name_case": "", | ||||
|  "owner": "Administrator", | ||||
|  "permissions": [ | ||||
|   { | ||||
|    "amend": 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": 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 | ||||
|   }, | ||||
|   { | ||||
|    "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": 1, | ||||
|    "write": 1 | ||||
|   } | ||||
|  ], | ||||
|  "quick_entry": 0, | ||||
|  "read_only": 0, | ||||
|  "read_only_onload": 0, | ||||
|  "show_name_in_global_search": 0, | ||||
|  "sort_field": "date", | ||||
|  "sort_order": "DESC", | ||||
|  "title_field": "bank_account", | ||||
|  "track_changes": 0, | ||||
|  "track_seen": 0, | ||||
|  "track_views": 0 | ||||
| } | ||||
							
								
								
									
										106
									
								
								erpnext/accounts/doctype/bank_transaction/bank_transaction.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								erpnext/accounts/doctype/bank_transaction/bank_transaction.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,106 @@ | ||||
| # -*- coding: utf-8 -*- | ||||
| # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors | ||||
| # For license information, please see license.txt | ||||
| 
 | ||||
| from __future__ import unicode_literals | ||||
| import frappe | ||||
| from erpnext.controllers.status_updater import StatusUpdater | ||||
| from frappe.utils import flt | ||||
| from six.moves import reduce | ||||
| from frappe import _ | ||||
| 
 | ||||
| class BankTransaction(StatusUpdater): | ||||
| 	def after_insert(self): | ||||
| 		self.unallocated_amount = abs(flt(self.credit) - flt(self.debit)) | ||||
| 
 | ||||
| 	def on_submit(self): | ||||
| 		self.clear_linked_payment_entries() | ||||
| 		self.set_status() | ||||
| 
 | ||||
| 	def on_update_after_submit(self): | ||||
| 		self.update_allocations() | ||||
| 		self.clear_linked_payment_entries() | ||||
| 		self.set_status(update=True) | ||||
| 
 | ||||
| 	def update_allocations(self): | ||||
| 		if self.payment_entries: | ||||
| 			allocated_amount = reduce(lambda x, y: flt(x) + flt(y), [x.allocated_amount for x in self.payment_entries]) | ||||
| 		else: | ||||
| 			allocated_amount = 0 | ||||
| 
 | ||||
| 		if allocated_amount: | ||||
| 			frappe.db.set_value(self.doctype, self.name, "allocated_amount", flt(allocated_amount)) | ||||
| 			frappe.db.set_value(self.doctype, self.name, "unallocated_amount", abs(flt(self.credit) - flt(self.debit)) - flt(allocated_amount)) | ||||
| 
 | ||||
| 		else: | ||||
| 			frappe.db.set_value(self.doctype, self.name, "allocated_amount", 0) | ||||
| 			frappe.db.set_value(self.doctype, self.name, "unallocated_amount", abs(flt(self.credit) - flt(self.debit))) | ||||
| 
 | ||||
| 		amount = self.debit or self.credit | ||||
| 		if amount == self.allocated_amount: | ||||
| 			frappe.db.set_value(self.doctype, self.name, "status", "Reconciled") | ||||
| 
 | ||||
| 		self.reload() | ||||
| 
 | ||||
| 	def clear_linked_payment_entries(self): | ||||
| 		for payment_entry in self.payment_entries: | ||||
| 			allocated_amount = get_total_allocated_amount(payment_entry) | ||||
| 			paid_amount = get_paid_amount(payment_entry) | ||||
| 
 | ||||
| 			if paid_amount and allocated_amount: | ||||
| 				if  flt(allocated_amount[0]["allocated_amount"]) > flt(paid_amount): | ||||
| 					frappe.throw(_("The total allocated amount ({0}) is greated than the paid amount ({1}).".format(flt(allocated_amount[0]["allocated_amount"]), flt(paid_amount)))) | ||||
| 				elif flt(allocated_amount[0]["allocated_amount"]) == flt(paid_amount): | ||||
| 					if payment_entry.payment_document in ["Payment Entry", "Journal Entry", "Purchase Invoice", "Expense Claim"]: | ||||
| 						self.clear_simple_entry(payment_entry) | ||||
| 
 | ||||
| 					elif payment_entry.payment_document == "Sales Invoice": | ||||
| 						self.clear_sales_invoice(payment_entry) | ||||
| 
 | ||||
| 	def clear_simple_entry(self, payment_entry): | ||||
| 		frappe.db.set_value(payment_entry.payment_document, payment_entry.payment_entry, "clearance_date", self.date) | ||||
| 
 | ||||
| 	def clear_sales_invoice(self, payment_entry): | ||||
| 		frappe.db.set_value("Sales Invoice Payment", dict(parenttype=payment_entry.payment_document, | ||||
| 			parent=payment_entry.payment_entry), "clearance_date", self.date) | ||||
| 
 | ||||
| def get_total_allocated_amount(payment_entry): | ||||
| 	return frappe.db.sql(""" | ||||
| 		SELECT | ||||
| 			SUM(btp.allocated_amount) as allocated_amount, | ||||
| 			bt.name | ||||
| 		FROM | ||||
| 			`tabBank Transaction Payments` as btp | ||||
| 		LEFT JOIN | ||||
| 			`tabBank Transaction` bt ON bt.name=btp.parent | ||||
| 		WHERE | ||||
| 			btp.payment_document = %s | ||||
| 		AND | ||||
| 			btp.payment_entry = %s | ||||
| 		AND | ||||
| 			bt.docstatus = 1""", (payment_entry.payment_document, payment_entry.payment_entry), as_dict=True) | ||||
| 
 | ||||
| def get_paid_amount(payment_entry): | ||||
| 	if payment_entry.payment_document in ["Payment Entry", "Sales Invoice", "Purchase Invoice"]: | ||||
| 		return frappe.db.get_value(payment_entry.payment_document, payment_entry.payment_entry, "paid_amount") | ||||
| 
 | ||||
| 	elif payment_entry.payment_document == "Journal Entry": | ||||
| 		return frappe.db.get_value(payment_entry.payment_document, payment_entry.payment_entry, "total_credit") | ||||
| 
 | ||||
| 	elif payment_entry.payment_document == "Expense Claim": | ||||
| 		return frappe.db.get_value(payment_entry.payment_document, payment_entry.payment_entry, "total_amount_reimbursed") | ||||
| 
 | ||||
| 	else: | ||||
| 		frappe.throw("Please reconcile {0}: {1} manually".format(payment_entry.payment_document, payment_entry.payment_entry)) | ||||
| 
 | ||||
| @frappe.whitelist() | ||||
| def unclear_reference_payment(doctype, docname): | ||||
| 	if frappe.db.exists(doctype, docname): | ||||
| 		doc = frappe.get_doc(doctype, docname) | ||||
| 		if doctype == "Sales Invoice": | ||||
| 			frappe.db.set_value("Sales Invoice Payment", dict(parenttype=doc.payment_document, | ||||
| 				parent=doc.payment_entry), "clearance_date", None) | ||||
| 		else: | ||||
| 			frappe.db.set_value(doc.payment_document, doc.payment_entry, "clearance_date", None) | ||||
| 
 | ||||
| 		return doc.payment_entry | ||||
| @ -0,0 +1,13 @@ | ||||
| // Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
 | ||||
| // License: GNU General Public License v3. See license.txt
 | ||||
| 
 | ||||
| frappe.listview_settings['Bank Transaction'] = { | ||||
| 	add_fields: ["unallocated_amount"], | ||||
| 	get_indicator: function(doc) { | ||||
| 		if(flt(doc.unallocated_amount)>0) { | ||||
| 			return [__("Unreconciled"), "orange", "unallocated_amount,>,0"]; | ||||
| 		} else if(flt(doc.unallocated_amount)<=0) { | ||||
| 			return [__("Reconciled"), "green", "unallocated_amount,=,0"]; | ||||
| 		} | ||||
| 	} | ||||
| }; | ||||
| @ -0,0 +1,80 @@ | ||||
| # -*- 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 | ||||
| import json | ||||
| from frappe.utils import getdate | ||||
| from frappe.utils.dateutils import parse_date | ||||
| from six import iteritems | ||||
| 
 | ||||
| @frappe.whitelist() | ||||
| def upload_bank_statement(): | ||||
| 	if getattr(frappe, "uploaded_file", None): | ||||
| 		with open(frappe.uploaded_file, "rb") as upfile: | ||||
| 			fcontent = upfile.read() | ||||
| 	else: | ||||
| 		from frappe.utils.file_manager import get_uploaded_content | ||||
| 		fname, fcontent = get_uploaded_content() | ||||
| 
 | ||||
| 	if frappe.safe_encode(fname).lower().endswith("csv".encode('utf-8')): | ||||
| 		from frappe.utils.csvutils import read_csv_content | ||||
| 		rows = read_csv_content(fcontent, False) | ||||
| 
 | ||||
| 	elif frappe.safe_encode(fname).lower().endswith("xlsx".encode('utf-8')): | ||||
| 		from frappe.utils.xlsxutils import read_xlsx_file_from_attached_file | ||||
| 		rows = read_xlsx_file_from_attached_file(fcontent=fcontent) | ||||
| 
 | ||||
| 	columns = rows[0] | ||||
| 	rows.pop(0) | ||||
| 	data = rows | ||||
| 	return {"columns": columns, "data": data} | ||||
| 
 | ||||
| 
 | ||||
| @frappe.whitelist() | ||||
| def create_bank_entries(columns, data, bank_account): | ||||
| 	header_map = get_header_mapping(columns, bank_account) | ||||
| 
 | ||||
| 	success = 0 | ||||
| 	errors = 0 | ||||
| 	for d in json.loads(data): | ||||
| 		if all(item is None for item in d) is True: | ||||
| 			continue | ||||
| 		fields = {} | ||||
| 		for key, value in iteritems(header_map): | ||||
| 			fields.update({key: d[int(value)-1]}) | ||||
| 
 | ||||
| 		try: | ||||
| 			bank_transaction = frappe.get_doc({ | ||||
| 				"doctype": "Bank Transaction" | ||||
| 			}) | ||||
| 			bank_transaction.update(fields) | ||||
| 			bank_transaction.date = getdate(parse_date(bank_transaction.date)) | ||||
| 			bank_transaction.bank_account = bank_account | ||||
| 			bank_transaction.insert() | ||||
| 			bank_transaction.submit() | ||||
| 			success += 1 | ||||
| 		except Exception: | ||||
| 			frappe.log_error(frappe.get_traceback()) | ||||
| 			errors += 1 | ||||
| 
 | ||||
| 	return {"success": success, "errors": errors} | ||||
| 
 | ||||
| def get_header_mapping(columns, bank_account): | ||||
| 	mapping = get_bank_mapping(bank_account) | ||||
| 
 | ||||
| 	header_map = {} | ||||
| 	for column in json.loads(columns): | ||||
| 		if column["content"] in mapping: | ||||
| 			header_map.update({mapping[column["content"]]: column["colIndex"]}) | ||||
| 
 | ||||
| 	return header_map | ||||
| 
 | ||||
| def get_bank_mapping(bank_account): | ||||
| 	bank_name = frappe.db.get_value("Bank Account", bank_account, "bank") | ||||
| 	bank = frappe.get_doc("Bank", bank_name) | ||||
| 
 | ||||
| 	mapping = {row.file_field:row.bank_transaction_field for row in bank.bank_transaction_mapping} | ||||
| 
 | ||||
| 	return mapping | ||||
| @ -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: Bank Transaction", function (assert) { | ||||
| 	let done = assert.async(); | ||||
| 
 | ||||
| 	// number of asserts
 | ||||
| 	assert.expect(1); | ||||
| 
 | ||||
| 	frappe.run_serially([ | ||||
| 		// insert a new Bank Transaction
 | ||||
| 		() => frappe.tests.make('Bank Transaction', [ | ||||
| 			// values to be set
 | ||||
| 			{key: 'value'} | ||||
| 		]), | ||||
| 		() => { | ||||
| 			assert.equal(cur_frm.doc.key, 'value'); | ||||
| 		}, | ||||
| 		() => done() | ||||
| 	]); | ||||
| 
 | ||||
| }); | ||||
| @ -0,0 +1,290 @@ | ||||
| # -*- coding: utf-8 -*- | ||||
| # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors | ||||
| # See license.txt | ||||
| from __future__ import unicode_literals | ||||
| 
 | ||||
| import frappe | ||||
| import unittest | ||||
| from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice | ||||
| from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice | ||||
| from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry | ||||
| from erpnext.accounts.page.bank_reconciliation.bank_reconciliation import reconcile, get_linked_payments | ||||
| 
 | ||||
| test_dependencies = ["Item", "Cost Center"] | ||||
| 
 | ||||
| class TestBankTransaction(unittest.TestCase): | ||||
| 	def setUp(self): | ||||
| 		add_transactions() | ||||
| 		add_payments() | ||||
| 
 | ||||
| 	def tearDown(self): | ||||
| 		for bt in frappe.get_all("Bank Transaction"): | ||||
| 			doc = frappe.get_doc("Bank Transaction", bt.name) | ||||
| 			doc.cancel() | ||||
| 			doc.delete() | ||||
| 
 | ||||
| 		# Delete directly in DB to avoid validation errors for countries not allowing deletion | ||||
| 		frappe.db.sql("""delete from `tabPayment Entry Reference`""") | ||||
| 		frappe.db.sql("""delete from `tabPayment Entry`""") | ||||
| 
 | ||||
| 		frappe.flags.test_bank_transactions_created = False | ||||
| 		frappe.flags.test_payments_created = False | ||||
| 
 | ||||
| 	# This test checks if ERPNext is able to provide a linked payment for a bank transaction based on the amount of the bank transaction. | ||||
| 	def test_linked_payments(self): | ||||
| 		bank_transaction = frappe.get_doc("Bank Transaction", dict(description="Re 95282925234 FE/000002917 AT171513000281183046 Conrad Electronic")) | ||||
| 		linked_payments = get_linked_payments(bank_transaction.name) | ||||
| 		self.assertTrue(linked_payments[0].party == "Conrad Electronic") | ||||
| 
 | ||||
| 	# This test validates a simple reconciliation leading to the clearance of the bank transaction and the payment | ||||
| 	def test_reconcile(self): | ||||
| 		bank_transaction = frappe.get_doc("Bank Transaction", dict(description="1512567 BG/000002918 OPSKATTUZWXXX AT776000000098709837 Herr G")) | ||||
| 		payment = frappe.get_doc("Payment Entry", dict(party="Mr G", paid_amount=1200)) | ||||
| 		reconcile(bank_transaction.name, "Payment Entry", payment.name) | ||||
| 
 | ||||
| 		unallocated_amount = frappe.db.get_value("Bank Transaction", bank_transaction.name, "unallocated_amount") | ||||
| 		self.assertTrue(unallocated_amount == 0) | ||||
| 
 | ||||
| 		clearance_date = frappe.db.get_value("Payment Entry", payment.name, "clearance_date") | ||||
| 		self.assertTrue(clearance_date is not None) | ||||
| 
 | ||||
| 	# Check if ERPNext can correctly fetch a linked payment based on the party | ||||
| 	def test_linked_payments_based_on_party(self): | ||||
| 		bank_transaction = frappe.get_doc("Bank Transaction", dict(description="1512567 BG/000003025 OPSKATTUZWXXX AT776000000098709849 Herr G")) | ||||
| 		linked_payments = get_linked_payments(bank_transaction.name) | ||||
| 		self.assertTrue(len(linked_payments)==1) | ||||
| 
 | ||||
| 	# Check if ERPNext can correctly filter a linked payments based on the debit/credit amount | ||||
| 	def test_debit_credit_output(self): | ||||
| 		bank_transaction = frappe.get_doc("Bank Transaction", dict(description="Auszahlung Karte MC/000002916 AUTOMAT 698769 K002 27.10. 14:07")) | ||||
| 		linked_payments = get_linked_payments(bank_transaction.name) | ||||
| 		self.assertTrue(linked_payments[0].payment_type == "Pay") | ||||
| 
 | ||||
| 	# Check error if already reconciled | ||||
| 	def test_already_reconciled(self): | ||||
| 		bank_transaction = frappe.get_doc("Bank Transaction", dict(description="1512567 BG/000002918 OPSKATTUZWXXX AT776000000098709837 Herr G")) | ||||
| 		payment = frappe.get_doc("Payment Entry", dict(party="Mr G", paid_amount=1200)) | ||||
| 		reconcile(bank_transaction.name, "Payment Entry", payment.name) | ||||
| 
 | ||||
| 		bank_transaction = frappe.get_doc("Bank Transaction", dict(description="1512567 BG/000002918 OPSKATTUZWXXX AT776000000098709837 Herr G")) | ||||
| 		payment = frappe.get_doc("Payment Entry", dict(party="Mr G", paid_amount=1200)) | ||||
| 		self.assertRaises(frappe.ValidationError, reconcile, bank_transaction=bank_transaction.name, payment_doctype="Payment Entry", payment_name=payment.name) | ||||
| 
 | ||||
| 	# Raise an error if creditor transaction vs creditor payment | ||||
| 	def test_invalid_creditor_reconcilation(self): | ||||
| 		bank_transaction = frappe.get_doc("Bank Transaction", dict(description="I2015000011 VD/000002514 ATWWXXX AT4701345000003510057 Bio")) | ||||
| 		payment = frappe.get_doc("Payment Entry", dict(party="Conrad Electronic", paid_amount=690)) | ||||
| 		self.assertRaises(frappe.ValidationError, reconcile, bank_transaction=bank_transaction.name, payment_doctype="Payment Entry", payment_name=payment.name) | ||||
| 
 | ||||
| 	# Raise an error if debitor transaction vs debitor payment | ||||
| 	def test_invalid_debitor_reconcilation(self): | ||||
| 		bank_transaction = frappe.get_doc("Bank Transaction", dict(description="Auszahlung Karte MC/000002916 AUTOMAT 698769 K002 27.10. 14:07")) | ||||
| 		payment = frappe.get_doc("Payment Entry", dict(party="Fayva", paid_amount=109080)) | ||||
| 		self.assertRaises(frappe.ValidationError, reconcile, bank_transaction=bank_transaction.name, payment_doctype="Payment Entry", payment_name=payment.name) | ||||
| 
 | ||||
| 	# Raise an error if debitor transaction vs debitor payment | ||||
| 	def test_clear_sales_invoice(self): | ||||
| 		bank_transaction = frappe.get_doc("Bank Transaction", dict(description="I2015000011 VD/000002514 ATWWXXX AT4701345000003510057 Bio")) | ||||
| 		payment = frappe.get_doc("Sales Invoice", dict(customer="Fayva", status=["=", "Paid"])) | ||||
| 		reconcile(bank_transaction.name, "Sales Invoice", payment.name) | ||||
| 
 | ||||
| 		self.assertEqual(frappe.db.get_value("Bank Transaction", bank_transaction.name, "unallocated_amount"), 0) | ||||
| 		self.assertTrue(frappe.db.get_value("Sales Invoice Payment", dict(parent=payment.name), "clearance_date") is not None) | ||||
| 
 | ||||
| def add_transactions(): | ||||
| 	if frappe.flags.test_bank_transactions_created: | ||||
| 		return | ||||
| 
 | ||||
| 	frappe.set_user("Administrator") | ||||
| 	try: | ||||
| 		frappe.get_doc({ | ||||
| 			"doctype": "Bank", | ||||
| 			"bank_name":"Citi Bank", | ||||
| 		}).insert() | ||||
| 	except frappe.DuplicateEntryError: | ||||
| 		pass | ||||
| 
 | ||||
| 	try: | ||||
| 		frappe.get_doc({ | ||||
| 			"doctype": "Bank Account", | ||||
| 			"account_name":"Checking Account", | ||||
| 			"bank": "Citi Bank", | ||||
| 			"account": "_Test Bank - _TC" | ||||
| 		}).insert() | ||||
| 	except frappe.DuplicateEntryError: | ||||
| 		pass | ||||
| 
 | ||||
| 	doc = frappe.get_doc({ | ||||
| 		"doctype": "Bank Transaction", | ||||
| 		"description":"1512567 BG/000002918 OPSKATTUZWXXX AT776000000098709837 Herr G", | ||||
| 		"date": "2018-10-23", | ||||
| 		"debit": 1200, | ||||
| 		"currency": "INR", | ||||
| 		"bank_account": "Checking Account - Citi Bank" | ||||
| 	}).insert() | ||||
| 	doc.submit() | ||||
| 
 | ||||
| 	doc = frappe.get_doc({ | ||||
| 		"doctype": "Bank Transaction", | ||||
| 		"description":"1512567 BG/000003025 OPSKATTUZWXXX AT776000000098709849 Herr G", | ||||
| 		"date": "2018-10-23", | ||||
| 		"debit": 1700, | ||||
| 		"currency": "INR", | ||||
| 		"bank_account": "Checking Account - Citi Bank" | ||||
| 	}).insert() | ||||
| 	doc.submit() | ||||
| 
 | ||||
| 	doc = frappe.get_doc({ | ||||
| 		"doctype": "Bank Transaction", | ||||
| 		"description":"Re 95282925234 FE/000002917 AT171513000281183046 Conrad Electronic", | ||||
| 		"date": "2018-10-26", | ||||
| 		"debit": 690, | ||||
| 		"currency": "INR", | ||||
| 		"bank_account": "Checking Account - Citi Bank" | ||||
| 	}).insert() | ||||
| 	doc.submit() | ||||
| 
 | ||||
| 	doc = frappe.get_doc({ | ||||
| 		"doctype": "Bank Transaction", | ||||
| 		"description":"Auszahlung Karte MC/000002916 AUTOMAT 698769 K002 27.10. 14:07", | ||||
| 		"date": "2018-10-27", | ||||
| 		"debit": 3900, | ||||
| 		"currency": "INR", | ||||
| 		"bank_account": "Checking Account - Citi Bank" | ||||
| 	}).insert() | ||||
| 	doc.submit() | ||||
| 
 | ||||
| 	doc = frappe.get_doc({ | ||||
| 		"doctype": "Bank Transaction", | ||||
| 		"description":"I2015000011 VD/000002514 ATWWXXX AT4701345000003510057 Bio", | ||||
| 		"date": "2018-10-27", | ||||
| 		"credit": 109080, | ||||
| 		"currency": "INR", | ||||
| 		"bank_account": "Checking Account - Citi Bank" | ||||
| 	}).insert() | ||||
| 	doc.submit() | ||||
| 
 | ||||
| 	frappe.flags.test_bank_transactions_created = True | ||||
| 
 | ||||
| def add_payments(): | ||||
| 	if frappe.flags.test_payments_created: | ||||
| 		return | ||||
| 
 | ||||
| 	frappe.set_user("Administrator") | ||||
| 
 | ||||
| 	try: | ||||
| 		frappe.get_doc({ | ||||
| 			"doctype": "Supplier", | ||||
| 			"supplier_group":"All Supplier Groups", | ||||
| 			"supplier_type": "Company", | ||||
| 			"supplier_name": "Conrad Electronic" | ||||
| 		}).insert() | ||||
| 
 | ||||
| 	except frappe.DuplicateEntryError: | ||||
| 		pass | ||||
| 
 | ||||
| 	pi = make_purchase_invoice(supplier="Conrad Electronic", qty=1, rate=690) | ||||
| 	pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC") | ||||
| 	pe.reference_no = "Conrad Oct 18" | ||||
| 	pe.reference_date = "2018-10-24" | ||||
| 	pe.insert() | ||||
| 	pe.submit() | ||||
| 
 | ||||
| 	try: | ||||
| 		frappe.get_doc({ | ||||
| 			"doctype": "Supplier", | ||||
| 			"supplier_group":"All Supplier Groups", | ||||
| 			"supplier_type": "Company", | ||||
| 			"supplier_name": "Mr G" | ||||
| 		}).insert() | ||||
| 	except frappe.DuplicateEntryError: | ||||
| 		pass | ||||
| 
 | ||||
| 	pi = make_purchase_invoice(supplier="Mr G", qty=1, rate=1200) | ||||
| 	pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC") | ||||
| 	pe.reference_no = "Herr G Oct 18" | ||||
| 	pe.reference_date = "2018-10-24" | ||||
| 	pe.insert() | ||||
| 	pe.submit() | ||||
| 
 | ||||
| 	pi = make_purchase_invoice(supplier="Mr G", qty=1, rate=1700) | ||||
| 	pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC") | ||||
| 	pe.reference_no = "Herr G Nov 18" | ||||
| 	pe.reference_date = "2018-11-01" | ||||
| 	pe.insert() | ||||
| 	pe.submit() | ||||
| 
 | ||||
| 	try: | ||||
| 		frappe.get_doc({ | ||||
| 			"doctype": "Supplier", | ||||
| 			"supplier_group":"All Supplier Groups", | ||||
| 			"supplier_type": "Company", | ||||
| 			"supplier_name": "Poore Simon's" | ||||
| 		}).insert() | ||||
| 	except frappe.DuplicateEntryError: | ||||
| 		pass | ||||
| 
 | ||||
| 	try: | ||||
| 		frappe.get_doc({ | ||||
| 			"doctype": "Customer", | ||||
| 			"customer_group":"All Customer Groups", | ||||
| 			"customer_type": "Company", | ||||
| 			"customer_name": "Poore Simon's" | ||||
| 		}).insert() | ||||
| 	except frappe.DuplicateEntryError: | ||||
| 		pass | ||||
| 
 | ||||
| 	pi = make_purchase_invoice(supplier="Poore Simon's", qty=1, rate=3900) | ||||
| 	pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC") | ||||
| 	pe.reference_no = "Poore Simon's Oct 18" | ||||
| 	pe.reference_date = "2018-10-28" | ||||
| 	pe.insert() | ||||
| 	pe.submit() | ||||
| 
 | ||||
| 	si = create_sales_invoice(customer="Poore Simon's", qty=1, rate=3900) | ||||
| 	pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank - _TC") | ||||
| 	pe.reference_no = "Poore Simon's Oct 18" | ||||
| 	pe.reference_date = "2018-10-28" | ||||
| 	pe.insert() | ||||
| 	pe.submit() | ||||
| 
 | ||||
| 	try: | ||||
| 		frappe.get_doc({ | ||||
| 			"doctype": "Customer", | ||||
| 			"customer_group":"All Customer Groups", | ||||
| 			"customer_type": "Company", | ||||
| 			"customer_name": "Fayva" | ||||
| 		}).insert() | ||||
| 	except frappe.DuplicateEntryError: | ||||
| 		pass | ||||
| 
 | ||||
| 	si = create_sales_invoice(customer="Fayva", qty=1, rate=109080) | ||||
| 	pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank - _TC") | ||||
| 	pe.reference_no = "Fayva Oct 18" | ||||
| 	pe.reference_date = "2018-10-29" | ||||
| 	pe.insert() | ||||
| 	pe.submit() | ||||
| 
 | ||||
| 	mode_of_payment = frappe.get_doc({ | ||||
| 		"doctype": "Mode of Payment", | ||||
| 		"name": "Cash" | ||||
| 	}) | ||||
| 
 | ||||
| 	if not frappe.db.get_value('Mode of Payment Account', {'company': "_Test Company", 'parent': "Cash"}): | ||||
| 		mode_of_payment.append("accounts", { | ||||
| 			"company": "_Test Company", | ||||
| 			"default_account": "_Test Bank - _TC" | ||||
| 		}) | ||||
| 		mode_of_payment.save() | ||||
| 
 | ||||
| 	si = create_sales_invoice(customer="Fayva", qty=1, rate=109080, do_not_submit=1) | ||||
| 	si.is_pos = 1 | ||||
| 	si.append("payments", { | ||||
| 		"mode_of_payment": "Cash", | ||||
| 		"account": "_Test Bank - _TC", | ||||
| 		"amount": 109080 | ||||
| 	}) | ||||
| 	si.save() | ||||
| 	si.submit() | ||||
| 
 | ||||
| 	frappe.flags.test_payments_created = True | ||||
| @ -0,0 +1,107 @@ | ||||
| { | ||||
|  "allow_copy": 0,  | ||||
|  "allow_events_in_timeline": 0,  | ||||
|  "allow_guest_to_view": 0,  | ||||
|  "allow_import": 0,  | ||||
|  "allow_rename": 0,  | ||||
|  "beta": 0,  | ||||
|  "creation": "2018-10-24 15:24:56.713277",  | ||||
|  "custom": 0,  | ||||
|  "docstatus": 0,  | ||||
|  "doctype": "DocType",  | ||||
|  "document_type": "",  | ||||
|  "editable_grid": 1,  | ||||
|  "engine": "InnoDB",  | ||||
|  "fields": [ | ||||
|   { | ||||
|    "allow_bulk_edit": 0,  | ||||
|    "allow_in_quick_entry": 0,  | ||||
|    "allow_on_submit": 0,  | ||||
|    "bold": 0,  | ||||
|    "collapsible": 0,  | ||||
|    "columns": 0,  | ||||
|    "fieldname": "bank_transaction_field",  | ||||
|    "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": "Field in Bank Transaction",  | ||||
|    "length": 0,  | ||||
|    "no_copy": 0,  | ||||
|    "permlevel": 0,  | ||||
|    "precision": "",  | ||||
|    "print_hide": 0,  | ||||
|    "print_hide_if_no_value": 0,  | ||||
|    "read_only": 0,  | ||||
|    "remember_last_selected_value": 0,  | ||||
|    "report_hide": 0,  | ||||
|    "reqd": 1,  | ||||
|    "search_index": 0,  | ||||
|    "set_only_once": 0,  | ||||
|    "translatable": 0,  | ||||
|    "unique": 0 | ||||
|   },  | ||||
|   { | ||||
|    "allow_bulk_edit": 0,  | ||||
|    "allow_in_quick_entry": 0,  | ||||
|    "allow_on_submit": 0,  | ||||
|    "bold": 0,  | ||||
|    "collapsible": 0,  | ||||
|    "columns": 0,  | ||||
|    "fieldname": "file_field",  | ||||
|    "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": "Column in Bank File",  | ||||
|    "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 | ||||
|   } | ||||
|  ],  | ||||
|  "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-10-24 15:24:56.713277",  | ||||
|  "modified_by": "Administrator",  | ||||
|  "module": "Accounts",  | ||||
|  "name": "Bank Transaction Mapping",  | ||||
|  "name_case": "",  | ||||
|  "owner": "Administrator",  | ||||
|  "permissions": [],  | ||||
|  "quick_entry": 0,  | ||||
|  "read_only": 0,  | ||||
|  "read_only_onload": 0,  | ||||
|  "show_name_in_global_search": 0,  | ||||
|  "sort_field": "modified",  | ||||
|  "sort_order": "DESC",  | ||||
|  "track_changes": 0,  | ||||
|  "track_seen": 0,  | ||||
|  "track_views": 0 | ||||
| } | ||||
| @ -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 BankTransactionMapping(Document): | ||||
| 	pass | ||||
| @ -0,0 +1,141 @@ | ||||
| { | ||||
|  "allow_copy": 0,  | ||||
|  "allow_events_in_timeline": 0,  | ||||
|  "allow_guest_to_view": 0,  | ||||
|  "allow_import": 0,  | ||||
|  "allow_rename": 0,  | ||||
|  "beta": 0,  | ||||
|  "creation": "2018-11-28 08:55:40.815355",  | ||||
|  "custom": 0,  | ||||
|  "docstatus": 0,  | ||||
|  "doctype": "DocType",  | ||||
|  "document_type": "",  | ||||
|  "editable_grid": 1,  | ||||
|  "engine": "InnoDB",  | ||||
|  "fields": [ | ||||
|   { | ||||
|    "allow_bulk_edit": 0,  | ||||
|    "allow_in_quick_entry": 0,  | ||||
|    "allow_on_submit": 0,  | ||||
|    "bold": 0,  | ||||
|    "collapsible": 0,  | ||||
|    "columns": 0,  | ||||
|    "fieldname": "payment_document",  | ||||
|    "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": "Payment Document",  | ||||
|    "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_in_quick_entry": 0,  | ||||
|    "allow_on_submit": 0,  | ||||
|    "bold": 0,  | ||||
|    "collapsible": 0,  | ||||
|    "columns": 0,  | ||||
|    "fieldname": "payment_entry",  | ||||
|    "fieldtype": "Dynamic 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": "Payment Entry",  | ||||
|    "length": 0,  | ||||
|    "no_copy": 0,  | ||||
|    "options": "payment_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 | ||||
|   },  | ||||
|   { | ||||
|    "allow_bulk_edit": 0,  | ||||
|    "allow_in_quick_entry": 0,  | ||||
|    "allow_on_submit": 0,  | ||||
|    "bold": 0,  | ||||
|    "collapsible": 0,  | ||||
|    "columns": 0,  | ||||
|    "fieldname": "allocated_amount",  | ||||
|    "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": "Allocated Amount",  | ||||
|    "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 | ||||
|   } | ||||
|  ],  | ||||
|  "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-12-06 10:57:02.635141",  | ||||
|  "modified_by": "Administrator",  | ||||
|  "module": "Accounts",  | ||||
|  "name": "Bank Transaction Payments",  | ||||
|  "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,  | ||||
|  "track_views": 0 | ||||
| } | ||||
| @ -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 BankTransactionPayments(Document): | ||||
| 	pass | ||||
| @ -24,7 +24,6 @@ class PaymentReconciliation(Document): | ||||
| 
 | ||||
| 	def get_payment_entries(self): | ||||
| 		order_doctype = "Sales Order" if self.party_type=="Customer" else "Purchase Order" | ||||
| 
 | ||||
| 		payment_entries = get_advance_payment_entries(self.party_type, self.party, | ||||
| 			self.receivable_payable_account, order_doctype, against_all_orders=True, limit=self.limit) | ||||
| 
 | ||||
| @ -37,7 +36,7 @@ class PaymentReconciliation(Document): | ||||
| 		bank_account_condition = "t2.against_account like %(bank_cash_account)s" \ | ||||
| 				if self.bank_cash_account else "1=1" | ||||
| 
 | ||||
| 		limit_cond = "limit %s" % (self.limit or 1000) | ||||
| 		limit_cond = "limit %s" % self.limit if self.limit else "" | ||||
| 
 | ||||
| 		journal_entries = frappe.db.sql(""" | ||||
| 			select | ||||
| @ -84,7 +83,10 @@ class PaymentReconciliation(Document): | ||||
| 		condition = self.check_condition() | ||||
| 
 | ||||
| 		non_reconciled_invoices = get_outstanding_invoices(self.party_type, self.party, | ||||
| 			self.receivable_payable_account, condition=condition, limit=self.limit) | ||||
| 			self.receivable_payable_account, condition=condition) | ||||
| 
 | ||||
| 		if self.limit: | ||||
| 			non_reconciled_invoices = non_reconciled_invoices[:self.limit] | ||||
| 
 | ||||
| 		self.add_invoice_entries(non_reconciled_invoices) | ||||
| 
 | ||||
|  | ||||
| @ -220,7 +220,12 @@ def get_pricing_rule_for_item(args, price_list_rate=0, doc=None): | ||||
| 
 | ||||
| 	if args.transaction_type=="selling": | ||||
| 		if args.customer and not (args.customer_group and args.territory): | ||||
| 			customer = frappe.get_cached_value("Customer", args.customer, ["customer_group", "territory"]) | ||||
| 
 | ||||
| 			if args.quotation_to and args.quotation_to != 'Customer': | ||||
| 				customer = frappe._dict() | ||||
| 			else: | ||||
| 				customer = frappe.get_cached_value("Customer", args.customer, ["customer_group", "territory"]) | ||||
| 
 | ||||
| 			if customer: | ||||
| 				args.customer_group, args.territory = customer | ||||
| 
 | ||||
|  | ||||
| @ -157,7 +157,7 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({ | ||||
| 	can_change_release_date: function(date) { | ||||
| 		const diff = frappe.datetime.get_diff(date, frappe.datetime.nowdate()); | ||||
| 		if (diff < 0) { | ||||
| 			frappe.throw('New release date should be in the future'); | ||||
| 			frappe.throw(__('New release date should be in the future')); | ||||
| 			return false; | ||||
| 		} else { | ||||
| 			return true; | ||||
| @ -523,8 +523,13 @@ frappe.ui.form.on("Purchase Invoice", { | ||||
| 	}, | ||||
| 
 | ||||
| 	onload: function(frm) { | ||||
| 		if(frm.doc.__onload && !frm.doc.__onload.supplier_tds) { | ||||
| 			me.frm.set_df_property("apply_tds", "read_only", 1); | ||||
| 		if(frm.doc.__onload) { | ||||
| 			if(frm.doc.supplier) { | ||||
| 				frm.doc.apply_tds = frm.doc.__onload.supplier_tds ? 1 : 0; | ||||
| 			} | ||||
| 			if(!frm.doc.__onload.supplier_tds) { | ||||
| 				frm.set_df_property("apply_tds", "read_only", 1); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		erpnext.queries.setup_queries(frm, "Warehouse", function() { | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -105,7 +105,7 @@ class PurchaseInvoice(BuyingController): | ||||
| 
 | ||||
| 	def validate_release_date(self): | ||||
| 		if self.release_date and getdate(nowdate()) >= getdate(self.release_date): | ||||
| 			frappe.msgprint('Release date must be in the future', raise_exception=True) | ||||
| 			frappe.throw(_('Release date must be in the future')) | ||||
| 
 | ||||
| 	def validate_cash(self): | ||||
| 		if not self.cash_bank_account and flt(self.paid_amount): | ||||
| @ -787,9 +787,8 @@ class PurchaseInvoice(BuyingController): | ||||
| 		for d in self.items: | ||||
| 			if d.project and d.project not in project_list: | ||||
| 				project = frappe.get_doc("Project", d.project) | ||||
| 				project.flags.dont_sync_tasks = True | ||||
| 				project.update_purchase_costing() | ||||
| 				project.save() | ||||
| 				project.db_update() | ||||
| 				project_list.append(d.project) | ||||
| 
 | ||||
| 	def validate_supplier_invoice(self): | ||||
|  | ||||
| @ -6,8 +6,8 @@ frappe.listview_settings['Purchase Invoice'] = { | ||||
| 	add_fields: ["supplier", "supplier_name", "base_grand_total", "outstanding_amount", "due_date", "company", | ||||
| 		"currency", "is_return", "release_date", "on_hold"], | ||||
| 	get_indicator: function(doc) { | ||||
| 		if(cint(doc.is_return)==1) { | ||||
| 			return [__("Return"), "darkgrey", "is_return,=,Yes"]; | ||||
| 		if(flt(doc.outstanding_amount) < 0 && doc.docstatus == 1) { | ||||
| 			return [__("Debit Note Issued"), "darkgrey", "outstanding_amount,<,0"] | ||||
| 		} else if(flt(doc.outstanding_amount) > 0 && doc.docstatus==1) { | ||||
| 			if(cint(doc.on_hold) && !doc.release_date) { | ||||
| 				return [__("On Hold"), "darkgrey"]; | ||||
| @ -18,9 +18,9 @@ frappe.listview_settings['Purchase Invoice'] = { | ||||
| 			} else { | ||||
| 				return [__("Unpaid"), "orange", "outstanding_amount,>,0|due,>=,Today"]; | ||||
| 			} | ||||
| 		} else if(flt(doc.outstanding_amount) < 0 && doc.docstatus == 1) { | ||||
| 			return [__("Debit Note Issued"), "darkgrey", "outstanding_amount,<,0"] | ||||
| 		}else if(flt(doc.outstanding_amount)==0 && doc.docstatus==1) { | ||||
| 		} else if(cint(doc.is_return)) { | ||||
| 			return [__("Return"), "darkgrey", "is_return,=,Yes"]; | ||||
| 		} else if(flt(doc.outstanding_amount)==0 && doc.docstatus==1) { | ||||
| 			return [__("Paid"), "green", "outstanding_amount,=,0"]; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
							
								
								
									
										38
									
								
								erpnext/accounts/doctype/sales_invoice/regional/india.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								erpnext/accounts/doctype/sales_invoice/regional/india.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,38 @@ | ||||
| frappe.ui.form.on("Sales Invoice", { | ||||
| 	setup: function(frm) { | ||||
| 		frm.set_query('transporter', function() { | ||||
| 			return { | ||||
| 				filters: { | ||||
| 					'is_transporter': 1 | ||||
| 				} | ||||
| 			}; | ||||
| 		}); | ||||
| 
 | ||||
| 		frm.set_query('driver', function(doc) { | ||||
| 			return { | ||||
| 				filters: { | ||||
| 					'transporter': doc.transporter | ||||
| 				} | ||||
| 			}; | ||||
| 		}); | ||||
| 	}, | ||||
| 
 | ||||
| 	refresh: function(frm) { | ||||
| 		if(frm.doc.docstatus == 1 && !frm.is_dirty() | ||||
| 			&& !frm.doc.is_return && !frm.doc.ewaybill) { | ||||
| 
 | ||||
| 			frm.add_custom_button('e-Way Bill JSON', () => { | ||||
| 				var w = window.open( | ||||
| 					frappe.urllib.get_full_url( | ||||
| 						"/api/method/erpnext.regional.india.utils.generate_ewb_json?" | ||||
| 						+ "dt=" + encodeURIComponent(frm.doc.doctype) | ||||
| 						+ "&dn=" + encodeURIComponent(frm.doc.name) | ||||
| 					) | ||||
| 				); | ||||
| 				if (!w) { | ||||
| 					frappe.msgprint(__("Please enable pop-ups")); return; | ||||
| 				} | ||||
| 			}, __("Make")); | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
| @ -0,0 +1,33 @@ | ||||
| var globalOnload = frappe.listview_settings['Sales Invoice'].onload; | ||||
| frappe.listview_settings['Sales Invoice'].onload = function (doclist) { | ||||
| 
 | ||||
| 	// Provision in case onload event is added to sales_invoice.js in future
 | ||||
| 	if (globalOnload) { | ||||
| 		globalOnload(doclist); | ||||
| 	} | ||||
| 
 | ||||
| 	const action = () => { | ||||
| 		const selected_docs = doclist.get_checked_items(); | ||||
| 		const docnames = doclist.get_checked_items(true); | ||||
| 
 | ||||
| 		for (let doc of selected_docs) { | ||||
| 			if (doc.docstatus !== 1) { | ||||
| 				frappe.throw(__("e-Way Bill JSON can only be generated from a submitted document")); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		var w = window.open( | ||||
| 			frappe.urllib.get_full_url( | ||||
| 				"/api/method/erpnext.regional.india.utils.generate_ewb_json?" | ||||
| 				+ "dt=" + encodeURIComponent(doclist.doctype) | ||||
| 				+ "&dn=" + encodeURIComponent(docnames) | ||||
| 			) | ||||
| 		); | ||||
| 		if (!w) { | ||||
| 			frappe.msgprint(__("Please enable pop-ups")); return; | ||||
| 		} | ||||
| 
 | ||||
| 	}; | ||||
| 
 | ||||
| 	doclist.page.add_actions_menu_item(__('Generate e-Way Bill JSON'), action, false); | ||||
| }; | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -54,8 +54,8 @@ class SalesInvoice(SellingController): | ||||
| 
 | ||||
| 	def set_indicator(self): | ||||
| 		"""Set indicator for portal""" | ||||
| 		if cint(self.is_return) == 1: | ||||
| 			self.indicator_title = _("Return") | ||||
| 		if self.outstanding_amount < 0: | ||||
| 			self.indicator_title = _("Credit Note Issued") | ||||
| 			self.indicator_color = "darkgrey" | ||||
| 		elif self.outstanding_amount > 0 and getdate(self.due_date) >= getdate(nowdate()): | ||||
| 			self.indicator_color = "orange" | ||||
| @ -63,8 +63,8 @@ class SalesInvoice(SellingController): | ||||
| 		elif self.outstanding_amount > 0 and getdate(self.due_date) < getdate(nowdate()): | ||||
| 			self.indicator_color = "red" | ||||
| 			self.indicator_title = _("Overdue") | ||||
| 		elif self.outstanding_amount < 0: | ||||
| 			self.indicator_title = _("Credit Note Issued") | ||||
| 		elif cint(self.is_return) == 1: | ||||
| 			self.indicator_title = _("Return") | ||||
| 			self.indicator_color = "darkgrey" | ||||
| 		else: | ||||
| 			self.indicator_color = "green" | ||||
| @ -508,8 +508,8 @@ class SalesInvoice(SellingController): | ||||
| 			if frappe.db.get_single_value('Selling Settings', dic[i][0]) == 'Yes': | ||||
| 				for d in self.get('items'): | ||||
| 					is_stock_item = frappe.get_cached_value('Item', d.item_code, 'is_stock_item') | ||||
| 					if d.item_code and is_stock_item == 1\ | ||||
| 						and not d.get(i.lower().replace(' ','_')) and not self.get(dic[i][1]): | ||||
| 					if  (d.item_code and is_stock_item == 1\ | ||||
| 						and not d.get(i.lower().replace(' ','_')) and not self.get(dic[i][1])): | ||||
| 						msgprint(_("{0} is mandatory for Item {1}").format(i,d.item_code), raise_exception=1) | ||||
| 
 | ||||
| 
 | ||||
| @ -1029,9 +1029,8 @@ class SalesInvoice(SellingController): | ||||
| 	def update_project(self): | ||||
| 		if self.project: | ||||
| 			project = frappe.get_doc("Project", self.project) | ||||
| 			project.flags.dont_sync_tasks = True | ||||
| 			project.update_billed_amount() | ||||
| 			project.save() | ||||
| 			project.db_update() | ||||
| 
 | ||||
| 
 | ||||
| 	def verify_payment_amount_is_positive(self): | ||||
|  | ||||
| @ -6,16 +6,16 @@ frappe.listview_settings['Sales Invoice'] = { | ||||
| 	add_fields: ["customer", "customer_name", "base_grand_total", "outstanding_amount", "due_date", "company", | ||||
| 		"currency", "is_return"], | ||||
| 	get_indicator: function(doc) { | ||||
| 		if(cint(doc.is_return)==1) { | ||||
| 			return [__("Return"), "darkgrey", "is_return,=,Yes"]; | ||||
| 		} else if(flt(doc.outstanding_amount)==0) { | ||||
| 			return [__("Paid"), "green", "outstanding_amount,=,0"] | ||||
| 		} else if(flt(doc.outstanding_amount) < 0) { | ||||
| 		if(flt(doc.outstanding_amount) < 0) { | ||||
| 			return [__("Credit Note Issued"), "darkgrey", "outstanding_amount,<,0"] | ||||
| 		}else if (flt(doc.outstanding_amount) > 0 && doc.due_date >= frappe.datetime.get_today()) { | ||||
| 		} else if (flt(doc.outstanding_amount) > 0 && doc.due_date >= frappe.datetime.get_today()) { | ||||
| 			return [__("Unpaid"), "orange", "outstanding_amount,>,0|due_date,>,Today"] | ||||
| 		} else if (flt(doc.outstanding_amount) > 0 && doc.due_date < frappe.datetime.get_today()) { | ||||
| 			return [__("Overdue"), "red", "outstanding_amount,>,0|due_date,<=,Today"] | ||||
| 		} else if(cint(doc.is_return)) { | ||||
| 			return [__("Return"), "darkgrey", "is_return,=,Yes"]; | ||||
| 		} else if(flt(doc.outstanding_amount)==0) { | ||||
| 			return [__("Paid"), "green", "outstanding_amount,=,0"] | ||||
| 		} | ||||
| 	}, | ||||
| 	right_column: "grand_total" | ||||
|  | ||||
| @ -19,6 +19,8 @@ from erpnext.controllers.taxes_and_totals import get_itemised_tax_breakup_data | ||||
| from erpnext.stock.doctype.item.test_item import create_item | ||||
| from six import iteritems | ||||
| from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_inter_company_transaction | ||||
| from erpnext.regional.india.utils import get_ewb_data | ||||
| 
 | ||||
| class TestSalesInvoice(unittest.TestCase): | ||||
| 	def make(self): | ||||
| 		w = frappe.copy_doc(test_records[0]) | ||||
| @ -1421,7 +1423,7 @@ class TestSalesInvoice(unittest.TestCase): | ||||
| 				"included_in_print_rate": 1 | ||||
| 			}) | ||||
| 		si.save() | ||||
| 
 | ||||
| 		si.submit() | ||||
| 		self.assertEqual(si.net_total, 19453.13) | ||||
| 		self.assertEqual(si.grand_total, 24900) | ||||
| 		self.assertEqual(si.total_taxes_and_charges, 5446.88) | ||||
| @ -1443,6 +1445,50 @@ class TestSalesInvoice(unittest.TestCase): | ||||
| 			self.assertEqual(expected_values[gle.account][1], gle.debit) | ||||
| 			self.assertEqual(expected_values[gle.account][2], gle.credit) | ||||
| 
 | ||||
| 	def test_rounding_adjustment_2(self): | ||||
| 		si = create_sales_invoice(rate=400, do_not_save=True) | ||||
| 		for rate in [400, 600, 100]: | ||||
| 			si.append("items", { | ||||
| 				"item_code": "_Test Item", | ||||
| 				"gst_hsn_code": "999800", | ||||
| 				"warehouse": "_Test Warehouse - _TC", | ||||
| 				"qty": 1, | ||||
| 				"rate": rate, | ||||
| 				"income_account": "Sales - _TC", | ||||
| 				"cost_center": "_Test Cost Center - _TC" | ||||
| 			}) | ||||
| 		for tax_account in ["_Test Account VAT - _TC", "_Test Account Service Tax - _TC"]: | ||||
| 			si.append("taxes", { | ||||
| 				"charge_type": "On Net Total", | ||||
| 				"account_head": tax_account, | ||||
| 				"description": tax_account, | ||||
| 				"rate": 9, | ||||
| 				"cost_center": "_Test Cost Center - _TC", | ||||
| 				"included_in_print_rate": 1 | ||||
| 			}) | ||||
| 		si.save() | ||||
| 		si.submit() | ||||
| 		self.assertEqual(si.net_total, 1271.19) | ||||
| 		self.assertEqual(si.grand_total, 1500) | ||||
| 		self.assertEqual(si.total_taxes_and_charges, 228.82) | ||||
| 		self.assertEqual(si.rounding_adjustment, -0.01) | ||||
| 
 | ||||
| 		expected_values = dict((d[0], d) for d in [ | ||||
| 			[si.debit_to, 1500, 0.0], | ||||
| 			["_Test Account Service Tax - _TC", 0.0, 114.41], | ||||
| 			["_Test Account VAT - _TC", 0.0, 114.41], | ||||
| 			["Sales - _TC", 0.0, 1271.18] | ||||
| 		]) | ||||
| 
 | ||||
| 		gl_entries = frappe.db.sql("""select account, debit, credit | ||||
| 			from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s | ||||
| 			order by account asc""", si.name, as_dict=1) | ||||
| 
 | ||||
| 		for gle in gl_entries: | ||||
| 			self.assertEqual(expected_values[gle.account][0], gle.account) | ||||
| 			self.assertEqual(expected_values[gle.account][1], gle.debit) | ||||
| 			self.assertEqual(expected_values[gle.account][2], gle.credit) | ||||
| 
 | ||||
| 	def test_sales_invoice_with_shipping_rule(self): | ||||
| 		from erpnext.accounts.doctype.shipping_rule.test_shipping_rule \ | ||||
| 			import create_shipping_rule | ||||
| @ -1681,6 +1727,111 @@ class TestSalesInvoice(unittest.TestCase): | ||||
| 		self.assertEqual(target_doc.company, "_Test Company 1") | ||||
| 		self.assertEqual(target_doc.supplier, "_Test Internal Supplier") | ||||
| 
 | ||||
| 	def test_eway_bill_json(self): | ||||
| 		if not frappe.db.exists('Address', '_Test Address for Eway bill-Billing'): | ||||
| 			address = frappe.get_doc({ | ||||
| 				"address_line1": "_Test Address Line 1", | ||||
| 				"address_title": "_Test Address for Eway bill", | ||||
| 				"address_type": "Billing", | ||||
| 				"city": "_Test City", | ||||
| 				"state": "Test State", | ||||
| 				"country": "India", | ||||
| 				"doctype": "Address", | ||||
| 				"is_primary_address": 1, | ||||
| 				"phone": "+91 0000000000", | ||||
| 				"gstin": "27AAECE4835E1ZR", | ||||
| 				"gst_state": "Maharashtra", | ||||
| 				"gst_state_number": "27", | ||||
| 				"pincode": "401108" | ||||
| 			}).insert() | ||||
| 
 | ||||
| 			address.append("links", { | ||||
| 				"link_doctype": "Company", | ||||
| 				"link_name": "_Test Company" | ||||
| 			}) | ||||
| 
 | ||||
| 			address.save() | ||||
| 
 | ||||
| 		if not frappe.db.exists('Address', '_Test Customer-Address for Eway bill-Shipping'): | ||||
| 			address = frappe.get_doc({ | ||||
| 				"address_line1": "_Test Address Line 1", | ||||
| 				"address_title": "_Test Customer-Address for Eway bill", | ||||
| 				"address_type": "Shipping", | ||||
| 				"city": "_Test City", | ||||
| 				"state": "Test State", | ||||
| 				"country": "India", | ||||
| 				"doctype": "Address", | ||||
| 				"is_primary_address": 1, | ||||
| 				"phone": "+91 0000000000", | ||||
| 				"gst_state": "Maharashtra", | ||||
| 				"gst_state_number": "27", | ||||
| 				"pincode": "410038" | ||||
| 			}).insert() | ||||
| 
 | ||||
| 			address.append("links", { | ||||
| 				"link_doctype": "Customer", | ||||
| 				"link_name": "_Test Customer" | ||||
| 			}) | ||||
| 
 | ||||
| 			address.save() | ||||
| 
 | ||||
| 		gst_settings = frappe.get_doc("GST Settings") | ||||
| 
 | ||||
| 		gst_account = frappe.get_all( | ||||
| 			"GST Account", | ||||
| 			fields=["cgst_account", "sgst_account", "igst_account"], | ||||
| 			filters = {"company": "_Test Company"}) | ||||
| 
 | ||||
| 		if not gst_account: | ||||
| 			gst_settings.append("gst_accounts", { | ||||
| 				"company": "_Test Company", | ||||
| 				"cgst_account": "CGST - _TC", | ||||
| 				"sgst_account": "SGST - _TC", | ||||
| 				"igst_account": "IGST - _TC", | ||||
| 			}) | ||||
| 
 | ||||
| 		gst_settings.save() | ||||
| 
 | ||||
| 		si = create_sales_invoice(do_not_save =1, rate = '60000') | ||||
| 
 | ||||
| 		si.distance = 2000 | ||||
| 		si.company_address = "_Test Address for Eway bill-Billing" | ||||
| 		si.customer_address = "_Test Customer-Address for Eway bill-Shipping" | ||||
| 		si.vehicle_no = "KA12KA1234" | ||||
| 		si.gst_category = "Registered Regular" | ||||
| 
 | ||||
| 		si.append("taxes", { | ||||
| 			"charge_type": "On Net Total", | ||||
| 			"account_head": "CGST - _TC", | ||||
| 			"cost_center": "Main - _TC", | ||||
| 			"description": "CGST @ 9.0", | ||||
| 			"rate": 9 | ||||
| 		}) | ||||
| 
 | ||||
| 		si.append("taxes", { | ||||
| 			"charge_type": "On Net Total", | ||||
| 			"account_head": "SGST - _TC", | ||||
| 			"cost_center": "Main - _TC", | ||||
| 			"description": "SGST @ 9.0", | ||||
| 			"rate": 9 | ||||
| 		}) | ||||
| 
 | ||||
| 		si.submit() | ||||
| 
 | ||||
| 		data = get_ewb_data("Sales Invoice", si.name) | ||||
| 
 | ||||
| 		self.assertEqual(data['version'], '1.0.1118') | ||||
| 		self.assertEqual(data['billLists'][0]['fromGstin'], '27AAECE4835E1ZR') | ||||
| 		self.assertEqual(data['billLists'][0]['fromTrdName'], '_Test Company') | ||||
| 		self.assertEqual(data['billLists'][0]['toTrdName'], '_Test Customer') | ||||
| 		self.assertEqual(data['billLists'][0]['vehicleType'], 'R') | ||||
| 		self.assertEqual(data['billLists'][0]['totalValue'], 60000) | ||||
| 		self.assertEqual(data['billLists'][0]['cgstValue'], 5400) | ||||
| 		self.assertEqual(data['billLists'][0]['sgstValue'], 5400) | ||||
| 		self.assertEqual(data['billLists'][0]['vehicleNo'], 'KA12KA1234') | ||||
| 		self.assertEqual(data['billLists'][0]['itemList'][0]['taxableAmount'], 60000) | ||||
| 
 | ||||
| 
 | ||||
| def create_sales_invoice(**args): | ||||
| 	si = frappe.new_doc("Sales Invoice") | ||||
| 	args = frappe._dict(args) | ||||
|  | ||||
| @ -295,7 +295,7 @@ | ||||
|  "issingle": 0,  | ||||
|  "istable": 1,  | ||||
|  "max_attachments": 0,  | ||||
|  "modified": "2019-03-06 15:58:37.839241",  | ||||
|  "modified": "2019-03-19 14:54:56.524556",  | ||||
|  "modified_by": "Administrator",  | ||||
|  "module": "Accounts",  | ||||
|  "name": "Sales Invoice Payment",  | ||||
|  | ||||
| @ -4,6 +4,7 @@ | ||||
| 
 | ||||
| from __future__ import unicode_literals | ||||
| import frappe | ||||
| from frappe import _ | ||||
| from frappe.model.document import Document | ||||
| from erpnext.utilities.product import get_price | ||||
| 
 | ||||
| @ -13,7 +14,7 @@ class SubscriptionPlan(Document): | ||||
| 
 | ||||
| 	def validate_interval_count(self): | ||||
| 		if self.billing_interval_count < 1: | ||||
| 			frappe.throw('Billing Interval Count cannot be less than 1') | ||||
| 			frappe.throw(_('Billing Interval Count cannot be less than 1')) | ||||
| 
 | ||||
| @frappe.whitelist() | ||||
| def get_plan_rate(plan, quantity=1, customer=None): | ||||
|  | ||||
| @ -145,9 +145,9 @@ def round_off_debit_credit(gl_map): | ||||
| 			.format(gl_map[0].voucher_type, gl_map[0].voucher_no, debit_credit_diff)) | ||||
| 
 | ||||
| 	elif abs(debit_credit_diff) >= (1.0 / (10**precision)): | ||||
| 		make_round_off_gle(gl_map, debit_credit_diff) | ||||
| 		make_round_off_gle(gl_map, debit_credit_diff, precision) | ||||
| 
 | ||||
| def make_round_off_gle(gl_map, debit_credit_diff): | ||||
| def make_round_off_gle(gl_map, debit_credit_diff, precision): | ||||
| 	round_off_account, round_off_cost_center = get_round_off_account_and_cost_center(gl_map[0].company) | ||||
| 	round_off_account_exists = False | ||||
| 	round_off_gle = frappe._dict() | ||||
| @ -160,6 +160,10 @@ def make_round_off_gle(gl_map, debit_credit_diff): | ||||
| 				debit_credit_diff += flt(d.credit_in_account_currency) | ||||
| 			round_off_account_exists = True | ||||
| 
 | ||||
| 	if round_off_account_exists and abs(debit_credit_diff) <= (1.0 / (10**precision)): | ||||
| 		gl_map.remove(round_off_gle) | ||||
| 		return | ||||
| 
 | ||||
| 	if not round_off_gle: | ||||
| 		for k in ["voucher_type", "voucher_no", "company", | ||||
| 			"posting_date", "remarks", "is_opening"]: | ||||
|  | ||||
							
								
								
									
										578
									
								
								erpnext/accounts/page/bank_reconciliation/bank_reconciliation.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										578
									
								
								erpnext/accounts/page/bank_reconciliation/bank_reconciliation.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,578 @@ | ||||
| frappe.provide("erpnext.accounts"); | ||||
| 
 | ||||
| frappe.pages['bank-reconciliation'].on_page_load = function(wrapper) { | ||||
| 	new erpnext.accounts.bankReconciliation(wrapper); | ||||
| } | ||||
| 
 | ||||
| erpnext.accounts.bankReconciliation = class BankReconciliation { | ||||
| 	constructor(wrapper) { | ||||
| 		this.page = frappe.ui.make_app_page({ | ||||
| 			parent: wrapper, | ||||
| 			title: __("Bank Reconciliation"), | ||||
| 			single_column: true | ||||
| 		}); | ||||
| 		this.parent = wrapper; | ||||
| 		this.page = this.parent.page; | ||||
| 
 | ||||
| 		this.check_plaid_status(); | ||||
| 		this.make(); | ||||
| 	} | ||||
| 
 | ||||
| 	make() { | ||||
| 		const me = this; | ||||
| 
 | ||||
| 		me.$main_section = $(`<div class="reconciliation page-main-content"></div>`).appendTo(me.page.main); | ||||
| 		const empty_state = __("Upload a bank statement, link or reconcile a bank account") | ||||
| 		me.$main_section.append(`<div class="flex justify-center align-center text-muted"
 | ||||
| 			style="height: 50vh; display: flex;"><h5 class="text-muted">${empty_state}</h5></div>`) | ||||
| 
 | ||||
| 		me.page.add_field({ | ||||
| 			fieldtype: 'Link', | ||||
| 			label: __('Company'), | ||||
| 			fieldname: 'company', | ||||
| 			options: "Company", | ||||
| 			onchange: function() { | ||||
| 				if (this.value) { | ||||
| 					me.company = this.value; | ||||
| 				} else { | ||||
| 					me.company = null; | ||||
| 					me.bank_account = null; | ||||
| 				} | ||||
| 			} | ||||
| 		}) | ||||
| 		me.page.add_field({ | ||||
| 			fieldtype: 'Link', | ||||
| 			label: __('Bank Account'), | ||||
| 			fieldname: 'bank_account', | ||||
| 			options: "Bank Account", | ||||
| 			get_query: function() { | ||||
| 				if(!me.company) { | ||||
| 					frappe.throw(__("Please select company first")); | ||||
| 					return | ||||
| 				} | ||||
| 
 | ||||
| 				return { | ||||
| 					filters: { | ||||
| 						"company": me.company | ||||
| 					} | ||||
| 				} | ||||
| 			}, | ||||
| 			onchange: function() { | ||||
| 				if (this.value) { | ||||
| 					me.bank_account = this.value; | ||||
| 					me.add_actions(); | ||||
| 				} else { | ||||
| 					me.bank_account = null; | ||||
| 					me.page.hide_actions_menu(); | ||||
| 				} | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
| 
 | ||||
| 	check_plaid_status() { | ||||
| 		const me = this; | ||||
| 		frappe.db.get_value("Plaid Settings", "Plaid Settings", "enabled", (r) => { | ||||
| 			if (r && r.enabled == "1") { | ||||
| 				me.plaid_status = "active" | ||||
| 			} else { | ||||
| 				me.plaid_status = "inactive" | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
| 
 | ||||
| 	add_actions() { | ||||
| 		const me = this; | ||||
| 
 | ||||
| 		me.page.show_menu() | ||||
| 
 | ||||
| 		me.page.add_menu_item(__("Upload a statement"), function() { | ||||
| 			me.clear_page_content(); | ||||
| 			new erpnext.accounts.bankTransactionUpload(me); | ||||
| 		}, true) | ||||
| 
 | ||||
| 		if (me.plaid_status==="active") { | ||||
| 			me.page.add_menu_item(__("Synchronize this account"), function() { | ||||
| 				me.clear_page_content(); | ||||
| 				new erpnext.accounts.bankTransactionSync(me); | ||||
| 			}, true) | ||||
| 		} | ||||
| 
 | ||||
| 		me.page.add_menu_item(__("Reconcile this account"), function() { | ||||
| 			me.clear_page_content(); | ||||
| 			me.make_reconciliation_tool(); | ||||
| 		}, true) | ||||
| 	} | ||||
| 
 | ||||
| 	clear_page_content() { | ||||
| 		const me = this; | ||||
| 		$(me.page.body).find('.frappe-list').remove(); | ||||
| 		me.$main_section.empty(); | ||||
| 	} | ||||
| 
 | ||||
| 	make_reconciliation_tool() { | ||||
| 		const me = this; | ||||
| 		frappe.model.with_doctype("Bank Transaction", () => { | ||||
| 			erpnext.accounts.ReconciliationList = new erpnext.accounts.ReconciliationTool({ | ||||
| 				parent: me.parent, | ||||
| 				doctype: "Bank Transaction" | ||||
| 			}); | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| erpnext.accounts.bankTransactionUpload = class bankTransactionUpload { | ||||
| 	constructor(parent) { | ||||
| 		this.parent = parent; | ||||
| 		this.data = []; | ||||
| 
 | ||||
| 		const assets = [ | ||||
| 			"/assets/frappe/css/frappe-datatable.css", | ||||
| 			"/assets/frappe/js/lib/clusterize.min.js", | ||||
| 			"/assets/frappe/js/lib/Sortable.min.js", | ||||
| 			"/assets/frappe/js/lib/frappe-datatable.js" | ||||
| 		]; | ||||
| 
 | ||||
| 		frappe.require(assets, () => { | ||||
| 			this.make(); | ||||
| 		}); | ||||
| 	} | ||||
| 
 | ||||
| 	make() { | ||||
| 		const me = this; | ||||
| 		frappe.upload.make({ | ||||
| 			args: { | ||||
| 				method: 'erpnext.accounts.doctype.bank_transaction.bank_transaction_upload.upload_bank_statement', | ||||
| 				allow_multiple: 0 | ||||
| 			}, | ||||
| 			no_socketio: true, | ||||
| 			sample_url: "e.g. http://example.com/somefile.csv", | ||||
| 			callback: function(attachment, r) { | ||||
| 				if (!r.exc && r.message) { | ||||
| 					me.data = r.message; | ||||
| 					me.setup_transactions_dom(); | ||||
| 					me.create_datatable(); | ||||
| 					me.add_primary_action(); | ||||
| 				} | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
| 
 | ||||
| 	setup_transactions_dom() { | ||||
| 		const me = this; | ||||
| 		me.parent.$main_section.append(`<div class="transactions-table"></div>`) | ||||
| 	} | ||||
| 
 | ||||
| 	create_datatable() { | ||||
| 		try { | ||||
| 			this.datatable = new DataTable('.transactions-table', { | ||||
| 				columns: this.data.columns, | ||||
| 				data: this.data.data | ||||
| 			}) | ||||
| 		} | ||||
| 		catch(err) { | ||||
| 			let msg = __(`Your file could not be processed by ERPNext.
 | ||||
| 						<br>It should be a standard CSV or XLSX file. | ||||
| 						<br>The headers should be in the first row.`)
 | ||||
| 			frappe.throw(msg) | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	add_primary_action() { | ||||
| 		const me = this; | ||||
| 		me.parent.page.set_primary_action(__("Submit"), function() { | ||||
| 			me.add_bank_entries() | ||||
| 		}, null, __("Creating bank entries...")) | ||||
| 	} | ||||
| 
 | ||||
| 	add_bank_entries() { | ||||
| 		const me = this; | ||||
| 		frappe.xcall('erpnext.accounts.doctype.bank_transaction.bank_transaction_upload.create_bank_entries', | ||||
| 			{columns: this.datatable.datamanager.columns, data: this.datatable.datamanager.data, bank_account: me.parent.bank_account} | ||||
| 		).then((result) => { | ||||
| 			let result_title = result.errors == 0 ? __("{0} bank transaction(s) created", [result.success]) : __("{0} bank transaction(s) created and {1} errors", [result.success, result.errors]) | ||||
| 			let result_msg = ` | ||||
| 				<div class="flex justify-center align-center text-muted" style="height: 50vh; display: flex;"> | ||||
| 					<h5 class="text-muted">${result_title}</h5> | ||||
| 				</div>` | ||||
| 			me.parent.page.clear_primary_action(); | ||||
| 			me.parent.$main_section.empty(); | ||||
| 			me.parent.$main_section.append(result_msg); | ||||
| 			if (result.errors == 0) { | ||||
| 				frappe.show_alert({message:__("All bank transactions have been created"), indicator:'green'}); | ||||
| 			} else { | ||||
| 				frappe.show_alert({message:__("Please check the error log for details about the import errors"), indicator:'red'}); | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| erpnext.accounts.bankTransactionSync = class bankTransactionSync { | ||||
| 	constructor(parent) { | ||||
| 		this.parent = parent; | ||||
| 		this.data = []; | ||||
| 
 | ||||
| 		this.init_config() | ||||
| 	} | ||||
| 
 | ||||
| 	init_config() { | ||||
| 		const me = this; | ||||
| 		frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.plaid_configuration') | ||||
| 		.then(result => { | ||||
| 			me.plaid_env = result.plaid_env; | ||||
| 			me.plaid_public_key = result.plaid_public_key; | ||||
| 			me.client_name = result.client_name; | ||||
| 			me.sync_transactions() | ||||
| 		}) | ||||
| 	} | ||||
| 
 | ||||
| 	sync_transactions() { | ||||
| 		const me = this; | ||||
| 		frappe.db.get_value("Bank Account", me.parent.bank_account, "bank", (v) => { | ||||
| 			frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.sync_transactions', { | ||||
| 				bank: v['bank'], | ||||
| 				bank_account: me.parent.bank_account, | ||||
| 				freeze: true | ||||
| 			}) | ||||
| 			.then((result) => { | ||||
| 				let result_title = (result.length > 0) ? __("{0} bank transaction(s) created", [result.length]) : __("This bank account is already synchronized") | ||||
| 				let result_msg = ` | ||||
| 					<div class="flex justify-center align-center text-muted" style="height: 50vh; display: flex;"> | ||||
| 						<h5 class="text-muted">${result_title}</h5> | ||||
| 					</div>` | ||||
| 				this.parent.$main_section.append(result_msg) | ||||
| 				frappe.show_alert({message:__("Bank account '{0}' has been synchronized", [me.parent.bank_account]), indicator:'green'}); | ||||
| 			}) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| erpnext.accounts.ReconciliationTool = class ReconciliationTool extends frappe.views.BaseList { | ||||
| 	constructor(opts) { | ||||
| 		super(opts); | ||||
| 		this.show(); | ||||
| 	} | ||||
| 
 | ||||
| 	setup_defaults() { | ||||
| 		super.setup_defaults(); | ||||
| 
 | ||||
| 		this.page_title = __("Bank Reconciliation"); | ||||
| 		this.doctype = 'Bank Transaction'; | ||||
| 		this.fields = ['date', 'description', 'debit', 'credit', 'currency'] | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	setup_view() { | ||||
| 		this.render_header(); | ||||
| 	} | ||||
| 
 | ||||
| 	setup_side_bar() { | ||||
| 		//
 | ||||
| 	} | ||||
| 
 | ||||
| 	make_standard_filters() { | ||||
| 		//
 | ||||
| 	} | ||||
| 
 | ||||
| 	freeze() { | ||||
| 		this.$result.find('.list-count').html(`<span>${__('Refreshing')}...</span>`); | ||||
| 	} | ||||
| 
 | ||||
| 	get_args() { | ||||
| 		const args = super.get_args(); | ||||
| 
 | ||||
| 		return Object.assign({}, args, { | ||||
| 			...args.filters.push(["Bank Transaction", "docstatus", "=", 1], | ||||
| 				["Bank Transaction", "unallocated_amount", ">", 0]) | ||||
| 		}); | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	update_data(r) { | ||||
| 		let data = r.message || []; | ||||
| 
 | ||||
| 		if (this.start === 0) { | ||||
| 			this.data = data; | ||||
| 		} else { | ||||
| 			this.data = this.data.concat(data); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	render() { | ||||
| 		const me = this; | ||||
| 		this.$result.find('.list-row-container').remove(); | ||||
| 		$('[data-fieldname="name"]').remove(); | ||||
| 		me.data.map((value) => { | ||||
| 			const row = $('<div class="list-row-container">').data("data", value).appendTo(me.$result).get(0); | ||||
| 			new erpnext.accounts.ReconciliationRow(row, value); | ||||
| 		}) | ||||
| 	} | ||||
| 
 | ||||
| 	render_header() { | ||||
| 		const me = this; | ||||
| 		if ($(this.wrapper).find('.transaction-header').length === 0) { | ||||
| 			me.$result.append(frappe.render_template("bank_transaction_header")); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| erpnext.accounts.ReconciliationRow = class ReconciliationRow { | ||||
| 	constructor(row, data) { | ||||
| 		this.data = data; | ||||
| 		this.row = row; | ||||
| 		this.make(); | ||||
| 		this.bind_events(); | ||||
| 	} | ||||
| 
 | ||||
| 	make() { | ||||
| 		$(this.row).append(frappe.render_template("bank_transaction_row", this.data)) | ||||
| 	} | ||||
| 
 | ||||
| 	bind_events() { | ||||
| 		const me = this; | ||||
| 		$(me.row).on('click', '.clickable-section', function() { | ||||
| 			me.bank_entry = $(this).attr("data-name"); | ||||
| 			me.show_dialog($(this).attr("data-name")); | ||||
| 		}) | ||||
| 
 | ||||
| 		$(me.row).on('click', '.new-reconciliation', function() { | ||||
| 			me.bank_entry = $(this).attr("data-name"); | ||||
| 			me.show_dialog($(this).attr("data-name")); | ||||
| 		}) | ||||
| 
 | ||||
| 		$(me.row).on('click', '.new-payment', function() { | ||||
| 			me.bank_entry = $(this).attr("data-name"); | ||||
| 			me.new_payment(); | ||||
| 		}) | ||||
| 
 | ||||
| 		$(me.row).on('click', '.new-invoice', function() { | ||||
| 			me.bank_entry = $(this).attr("data-name"); | ||||
| 			me.new_invoice(); | ||||
| 		}) | ||||
| 
 | ||||
| 		$(me.row).on('click', '.new-expense', function() { | ||||
| 			me.bank_entry = $(this).attr("data-name"); | ||||
| 			me.new_expense(); | ||||
| 		}) | ||||
| 	} | ||||
| 
 | ||||
| 	new_payment() { | ||||
| 		const me = this; | ||||
| 		const paid_amount = me.data.credit > 0 ? me.data.credit : me.data.debit; | ||||
| 		const payment_type = me.data.credit > 0 ? "Receive": "Pay"; | ||||
| 		const party_type = me.data.credit > 0 ? "Customer": "Supplier"; | ||||
| 
 | ||||
| 		frappe.new_doc("Payment Entry", {"payment_type": payment_type, "paid_amount": paid_amount, | ||||
| 			"party_type": party_type, "paid_from": me.data.bank_account}) | ||||
| 	} | ||||
| 
 | ||||
| 	new_invoice() { | ||||
| 		const me = this; | ||||
| 		const invoice_type = me.data.credit > 0 ? "Sales Invoice" : "Purchase Invoice"; | ||||
| 
 | ||||
| 		frappe.new_doc(invoice_type) | ||||
| 	} | ||||
| 
 | ||||
| 	new_expense() { | ||||
| 		frappe.new_doc("Expense Claim") | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	show_dialog(data) { | ||||
| 		const me = this; | ||||
| 
 | ||||
| 		frappe.db.get_value("Bank Account", me.data.bank_account, "account", (r) => { | ||||
| 			me.gl_account = r.account; | ||||
| 		}) | ||||
| 
 | ||||
| 		frappe.xcall('erpnext.accounts.page.bank_reconciliation.bank_reconciliation.get_linked_payments', | ||||
| 			{bank_transaction: data, freeze:true, freeze_message:__("Finding linked payments")} | ||||
| 		).then((result) => { | ||||
| 			me.make_dialog(result) | ||||
| 		}) | ||||
| 	} | ||||
| 
 | ||||
| 	make_dialog(data) { | ||||
| 		const me = this; | ||||
| 		me.selected_payment = null; | ||||
| 
 | ||||
| 		const fields = [ | ||||
| 			{ | ||||
| 				fieldtype: 'Section Break', | ||||
| 				fieldname: 'section_break_1', | ||||
| 				label: __('Automatic Reconciliation') | ||||
| 			}, | ||||
| 			{ | ||||
| 				fieldtype: 'HTML', | ||||
| 				fieldname: 'payment_proposals' | ||||
| 			}, | ||||
| 			{ | ||||
| 				fieldtype: 'Section Break', | ||||
| 				fieldname: 'section_break_2', | ||||
| 				label: __('Search for a payment') | ||||
| 			}, | ||||
| 			{ | ||||
| 				fieldtype: 'Link', | ||||
| 				fieldname: 'payment_doctype', | ||||
| 				options: 'DocType', | ||||
| 				label: 'Payment DocType', | ||||
| 				get_query: () => { | ||||
| 					return { | ||||
| 						filters : { | ||||
| 							"name": ["in", ["Payment Entry", "Journal Entry", "Sales Invoice", "Purchase Invoice", "Expense Claim"]] | ||||
| 						} | ||||
| 					} | ||||
| 				}, | ||||
| 			}, | ||||
| 			{ | ||||
| 				fieldtype: 'Column Break', | ||||
| 				fieldname: 'column_break_1', | ||||
| 			}, | ||||
| 			{ | ||||
| 				fieldtype: 'Dynamic Link', | ||||
| 				fieldname: 'payment_entry', | ||||
| 				options: 'payment_doctype', | ||||
| 				label: 'Payment Document', | ||||
| 				get_query: () => { | ||||
| 					let dt = this.dialog.fields_dict.payment_doctype.value; | ||||
| 					if (dt === "Payment Entry") { | ||||
| 						return { | ||||
| 							query: "erpnext.accounts.page.bank_reconciliation.bank_reconciliation.payment_entry_query", | ||||
| 							filters : { | ||||
| 								"bank_account": this.data.bank_account, | ||||
| 								"company": this.data.company | ||||
| 							} | ||||
| 						} | ||||
| 					} else if (dt === "Journal Entry") { | ||||
| 						return { | ||||
| 							query: "erpnext.accounts.page.bank_reconciliation.bank_reconciliation.journal_entry_query", | ||||
| 							filters : { | ||||
| 								"bank_account": this.data.bank_account, | ||||
| 								"company": this.data.company | ||||
| 							} | ||||
| 						} | ||||
| 					} else if (dt === "Sales Invoice") { | ||||
| 						return { | ||||
| 							query: "erpnext.accounts.page.bank_reconciliation.bank_reconciliation.sales_invoices_query" | ||||
| 						} | ||||
| 					} else if (dt === "Purchase Invoice") { | ||||
| 						return { | ||||
| 							filters : [ | ||||
| 								["Purchase Invoice", "ifnull(clearance_date, '')", "=", ""], | ||||
| 								["Purchase Invoice", "docstatus", "=", 1], | ||||
| 								["Purchase Invoice", "company", "=", this.data.company] | ||||
| 							] | ||||
| 						} | ||||
| 					} else if (dt === "Expense Claim") { | ||||
| 						return { | ||||
| 							filters : [ | ||||
| 								["Expense Claim", "ifnull(clearance_date, '')", "=", ""], | ||||
| 								["Expense Claim", "docstatus", "=", 1], | ||||
| 								["Expense Claim", "company", "=", this.data.company] | ||||
| 							] | ||||
| 						} | ||||
| 					} | ||||
| 				}, | ||||
| 				onchange: function() { | ||||
| 					if (me.selected_payment !== this.value) { | ||||
| 						me.selected_payment = this.value; | ||||
| 						me.display_payment_details(this); | ||||
| 					} | ||||
| 				} | ||||
| 			}, | ||||
| 			{ | ||||
| 				fieldtype: 'Section Break', | ||||
| 				fieldname: 'section_break_3' | ||||
| 			}, | ||||
| 			{ | ||||
| 				fieldtype: 'HTML', | ||||
| 				fieldname: 'payment_details' | ||||
| 			}, | ||||
| 		]; | ||||
| 
 | ||||
| 		me.dialog = new frappe.ui.Dialog({ | ||||
| 			title: __("Choose a corresponding payment"), | ||||
| 			fields: fields, | ||||
| 			size: "large" | ||||
| 		}); | ||||
| 
 | ||||
| 		const proposals_wrapper = me.dialog.fields_dict.payment_proposals.$wrapper; | ||||
| 		if (data && data.length > 0) { | ||||
| 			proposals_wrapper.append(frappe.render_template("linked_payment_header")); | ||||
| 			data.map(value => { | ||||
| 				proposals_wrapper.append(frappe.render_template("linked_payment_row", value)) | ||||
| 			}) | ||||
| 		} else { | ||||
| 			const empty_data_msg = __("ERPNext could not find any matching payment entry") | ||||
| 			proposals_wrapper.append(`<div class="text-center"><h5 class="text-muted">${empty_data_msg}</h5></div>`) | ||||
| 		} | ||||
| 
 | ||||
| 		$(me.dialog.body).on('click', '.reconciliation-btn', (e) => { | ||||
| 			const payment_entry = $(e.target).attr('data-name'); | ||||
| 			const payment_doctype = $(e.target).attr('data-doctype'); | ||||
| 			frappe.xcall('erpnext.accounts.page.bank_reconciliation.bank_reconciliation.reconcile', | ||||
| 				{bank_transaction: me.bank_entry, payment_doctype: payment_doctype, payment_name: payment_entry}) | ||||
| 			.then((result) => { | ||||
| 				setTimeout(function(){ | ||||
| 					erpnext.accounts.ReconciliationList.refresh(); | ||||
| 				}, 2000); | ||||
| 				me.dialog.hide(); | ||||
| 			}) | ||||
| 		}) | ||||
| 
 | ||||
| 		me.dialog.show(); | ||||
| 	} | ||||
| 
 | ||||
| 	display_payment_details(event) { | ||||
| 		const me = this; | ||||
| 		if (event.value) { | ||||
| 			let dt = me.dialog.fields_dict.payment_doctype.value; | ||||
| 			me.dialog.fields_dict['payment_details'].$wrapper.empty(); | ||||
| 			frappe.db.get_doc(dt, event.value) | ||||
| 			.then(doc => { | ||||
| 				let displayed_docs = [] | ||||
| 				if (dt === "Payment Entry") { | ||||
| 					payment.currency = doc.payment_type == "Receive" ? doc.paid_to_account_currency : doc.paid_from_account_currency; | ||||
| 					payment.doctype = dt | ||||
| 					displayed_docs.push(payment); | ||||
| 				} else if (dt === "Journal Entry") { | ||||
| 					doc.accounts.forEach(payment => { | ||||
| 						if (payment.account === me.gl_account) { | ||||
| 							payment.doctype = dt; | ||||
| 							payment.posting_date = doc.posting_date; | ||||
| 							payment.party = doc.pay_to_recd_from; | ||||
| 							payment.reference_no = doc.cheque_no; | ||||
| 							payment.reference_date = doc.cheque_date; | ||||
| 							payment.currency = payment.account_currency; | ||||
| 							payment.paid_amount = payment.credit > 0 ? payment.credit : payment.debit; | ||||
| 							payment.name = doc.name; | ||||
| 							displayed_docs.push(payment); | ||||
| 						} | ||||
| 					}) | ||||
| 				} else if (dt === "Sales Invoice") { | ||||
| 					doc.payments.forEach(payment => { | ||||
| 						if (payment.clearance_date === null || payment.clearance_date === "") { | ||||
| 							payment.doctype = dt; | ||||
| 							payment.posting_date = doc.posting_date; | ||||
| 							payment.party = doc.customer; | ||||
| 							payment.reference_no = doc.remarks; | ||||
| 							payment.currency = doc.currency; | ||||
| 							payment.paid_amount = payment.amount; | ||||
| 							payment.name = doc.name; | ||||
| 							displayed_docs.push(payment); | ||||
| 						} | ||||
| 					}) | ||||
| 				} | ||||
| 
 | ||||
| 				const details_wrapper = me.dialog.fields_dict.payment_details.$wrapper; | ||||
| 				details_wrapper.append(frappe.render_template("linked_payment_header")); | ||||
| 				displayed_docs.forEach(values => { | ||||
| 					details_wrapper.append(frappe.render_template("linked_payment_row", values)); | ||||
| 				}) | ||||
| 			}) | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| } | ||||
| @ -0,0 +1,29 @@ | ||||
| { | ||||
|  "content": null,  | ||||
|  "creation": "2018-11-24 12:03:14.646669",  | ||||
|  "docstatus": 0,  | ||||
|  "doctype": "Page",  | ||||
|  "idx": 0,  | ||||
|  "modified": "2018-11-24 12:03:14.646669",  | ||||
|  "modified_by": "Administrator",  | ||||
|  "module": "Accounts",  | ||||
|  "name": "bank-reconciliation",  | ||||
|  "owner": "Administrator",  | ||||
|  "page_name": "bank-reconciliation",  | ||||
|  "roles": [ | ||||
|   { | ||||
|    "role": "System Manager" | ||||
|   },  | ||||
|   { | ||||
|    "role": "Accounts Manager" | ||||
|   },  | ||||
|   { | ||||
|    "role": "Accounts User" | ||||
|   } | ||||
|  ],  | ||||
|  "script": null,  | ||||
|  "standard": "Yes",  | ||||
|  "style": null,  | ||||
|  "system_page": 0,  | ||||
|  "title": "Bank Reconciliation" | ||||
| } | ||||
							
								
								
									
										378
									
								
								erpnext/accounts/page/bank_reconciliation/bank_reconciliation.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										378
									
								
								erpnext/accounts/page/bank_reconciliation/bank_reconciliation.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,378 @@ | ||||
| # -*- 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 _ | ||||
| import difflib | ||||
| from frappe.utils import flt | ||||
| from six import iteritems | ||||
| from erpnext import get_company_currency | ||||
| 
 | ||||
| @frappe.whitelist() | ||||
| def reconcile(bank_transaction, payment_doctype, payment_name): | ||||
| 	transaction = frappe.get_doc("Bank Transaction", bank_transaction) | ||||
| 	payment_entry = frappe.get_doc(payment_doctype, payment_name) | ||||
| 
 | ||||
| 	account = frappe.db.get_value("Bank Account", transaction.bank_account, "account") | ||||
| 	gl_entry = frappe.get_doc("GL Entry", dict(account=account, voucher_type=payment_doctype, voucher_no=payment_name)) | ||||
| 
 | ||||
| 	if transaction.unallocated_amount == 0: | ||||
| 		frappe.throw(_("This bank transaction is already fully reconciled")) | ||||
| 
 | ||||
| 	if transaction.credit > 0 and gl_entry.credit > 0: | ||||
| 		frappe.throw(_("The selected payment entry should be linked with a debtor bank transaction")) | ||||
| 
 | ||||
| 	if transaction.debit > 0 and gl_entry.debit > 0: | ||||
| 		frappe.throw(_("The selected payment entry should be linked with a creditor bank transaction")) | ||||
| 
 | ||||
| 	add_payment_to_transaction(transaction, payment_entry, gl_entry) | ||||
| 
 | ||||
| 	return 'reconciled' | ||||
| 
 | ||||
| def add_payment_to_transaction(transaction, payment_entry, gl_entry): | ||||
| 	gl_amount, transaction_amount = (gl_entry.credit, transaction.debit) if gl_entry.credit > 0 else (gl_entry.debit, transaction.credit) | ||||
| 	allocated_amount = gl_amount if gl_amount <= transaction_amount else transaction_amount | ||||
| 	transaction.append("payment_entries", { | ||||
| 		"payment_document": payment_entry.doctype, | ||||
| 		"payment_entry": payment_entry.name, | ||||
| 		"allocated_amount": allocated_amount | ||||
| 	}) | ||||
| 
 | ||||
| 	transaction.save() | ||||
| 	transaction.update_allocations() | ||||
| 
 | ||||
| @frappe.whitelist() | ||||
| def get_linked_payments(bank_transaction): | ||||
| 	transaction = frappe.get_doc("Bank Transaction", bank_transaction) | ||||
| 	bank_account = frappe.db.get_values("Bank Account", transaction.bank_account, ["account", "company"], as_dict=True) | ||||
| 
 | ||||
| 	# Get all payment entries with a matching amount | ||||
| 	amount_matching = check_matching_amount(bank_account[0].account, bank_account[0].company, transaction) | ||||
| 
 | ||||
| 	# Get some data from payment entries linked to a corresponding bank transaction | ||||
| 	description_matching = get_matching_descriptions_data(bank_account[0].company, transaction) | ||||
| 
 | ||||
| 	if amount_matching: | ||||
| 		return check_amount_vs_description(amount_matching, description_matching) | ||||
| 
 | ||||
| 	elif description_matching: | ||||
| 		description_matching = filter(lambda x: not x.get('clearance_date'), description_matching) | ||||
| 		if not description_matching: | ||||
| 			return [] | ||||
| 
 | ||||
| 		return sorted(list(description_matching), key = lambda x: x["posting_date"], reverse=True) | ||||
| 
 | ||||
| 	else: | ||||
| 		return [] | ||||
| 
 | ||||
| def check_matching_amount(bank_account, company, transaction): | ||||
| 	payments = [] | ||||
| 	amount = transaction.credit if transaction.credit > 0 else transaction.debit | ||||
| 
 | ||||
| 	payment_type = "Receive" if transaction.credit > 0 else "Pay" | ||||
| 	account_from_to = "paid_to" if transaction.credit > 0 else "paid_from" | ||||
| 	currency_field = "paid_to_account_currency as currency" if transaction.credit > 0 else "paid_from_account_currency as currency" | ||||
| 
 | ||||
| 	payment_entries = frappe.get_all("Payment Entry", fields=["'Payment Entry' as doctype", "name", "paid_amount", "payment_type", "reference_no", "reference_date", | ||||
| 		"party", "party_type", "posting_date", "{0}".format(currency_field)], filters=[["paid_amount", "like", "{0}%".format(amount)], | ||||
| 		["docstatus", "=", "1"], ["payment_type", "=", [payment_type, "Internal Transfer"]], ["ifnull(clearance_date, '')", "=", ""], ["{0}".format(account_from_to), "=", "{0}".format(bank_account)]]) | ||||
| 
 | ||||
| 	if transaction.credit > 0: | ||||
| 		journal_entries = frappe.db.sql(""" | ||||
| 			SELECT | ||||
| 				'Journal Entry' as doctype, je.name, je.posting_date, je.cheque_no as reference_no, | ||||
| 				je.pay_to_recd_from as party, je.cheque_date as reference_date, jea.debit_in_account_currency as paid_amount | ||||
| 			FROM | ||||
| 				`tabJournal Entry Account` as jea | ||||
| 			JOIN | ||||
| 				`tabJournal Entry` as je | ||||
| 			ON | ||||
| 				jea.parent = je.name | ||||
| 			WHERE | ||||
| 				(je.clearance_date is null or je.clearance_date='0000-00-00') | ||||
| 			AND | ||||
| 				jea.account = %s | ||||
| 			AND | ||||
| 				jea.debit_in_account_currency like %s | ||||
| 			AND | ||||
| 				je.docstatus = 1 | ||||
| 		""", (bank_account, amount), as_dict=True) | ||||
| 	else: | ||||
| 		journal_entries = frappe.db.sql(""" | ||||
| 			SELECT | ||||
| 				'Journal Entry' as doctype, je.name, je.posting_date, je.cheque_no as reference_no, | ||||
| 				jea.account_currency as currency, je.pay_to_recd_from as party, je.cheque_date as reference_date, | ||||
| 				jea.credit_in_account_currency as paid_amount | ||||
| 			FROM | ||||
| 				`tabJournal Entry Account` as jea | ||||
| 			JOIN | ||||
| 				`tabJournal Entry` as je | ||||
| 			ON | ||||
| 				jea.parent = je.name | ||||
| 			WHERE | ||||
| 				(je.clearance_date is null or je.clearance_date='0000-00-00') | ||||
| 			AND | ||||
| 				jea.account = %(bank_account)s | ||||
| 			AND | ||||
| 				jea.credit_in_account_currency like %(txt)s | ||||
| 			AND | ||||
| 				je.docstatus = 1 | ||||
| 		""", { | ||||
| 			'bank_account': bank_account, | ||||
| 			'txt': '%%%s%%' % amount | ||||
| 		}, as_dict=True) | ||||
| 
 | ||||
| 		frappe.errprint(journal_entries) | ||||
| 
 | ||||
| 	if transaction.credit > 0: | ||||
| 		sales_invoices = frappe.db.sql(""" | ||||
| 			SELECT | ||||
| 				'Sales Invoice' as doctype, si.name, si.customer as party, | ||||
| 				si.posting_date, sip.amount as paid_amount | ||||
| 			FROM | ||||
| 				`tabSales Invoice Payment` as sip | ||||
| 			JOIN | ||||
| 				`tabSales Invoice` as si | ||||
| 			ON | ||||
| 				sip.parent = si.name | ||||
| 			WHERE | ||||
| 				(sip.clearance_date is null or sip.clearance_date='0000-00-00') | ||||
| 			AND | ||||
| 				sip.account = %s | ||||
| 			AND | ||||
| 				sip.amount like %s | ||||
| 			AND | ||||
| 				si.docstatus = 1 | ||||
| 		""", (bank_account, amount), as_dict=True) | ||||
| 	else: | ||||
| 		sales_invoices = [] | ||||
| 
 | ||||
| 	if transaction.debit > 0: | ||||
| 		purchase_invoices = frappe.get_all("Purchase Invoice", | ||||
| 			fields = ["'Purchase Invoice' as doctype", "name", "paid_amount", "supplier as party", "posting_date", "currency"], | ||||
| 			filters=[ | ||||
| 				["paid_amount", "like", "{0}%".format(amount)], | ||||
| 				["docstatus", "=", "1"], | ||||
| 				["is_paid", "=", "1"], | ||||
| 				["ifnull(clearance_date, '')", "=", ""], | ||||
| 				["cash_bank_account", "=", "{0}".format(bank_account)] | ||||
| 			] | ||||
| 		) | ||||
| 
 | ||||
| 		mode_of_payments = [x["parent"] for x in frappe.db.get_list("Mode of Payment Account", | ||||
| 			filters={"default_account": bank_account}, fields=["parent"])] | ||||
| 
 | ||||
| 		company_currency = get_company_currency(company) | ||||
| 
 | ||||
| 		expense_claims = frappe.get_all("Expense Claim", | ||||
| 			fields=["'Expense Claim' as doctype", "name", "total_sanctioned_amount as paid_amount", | ||||
| 				"employee as party", "posting_date", "'{0}' as currency".format(company_currency)], | ||||
| 			filters=[ | ||||
| 				["total_sanctioned_amount", "like", "{0}%".format(amount)], | ||||
| 				["docstatus", "=", "1"], | ||||
| 				["is_paid", "=", "1"], | ||||
| 				["ifnull(clearance_date, '')", "=", ""], | ||||
| 				["mode_of_payment", "in", "{0}".format(tuple(mode_of_payments))] | ||||
| 			] | ||||
| 		) | ||||
| 	else: | ||||
| 		purchase_invoices = expense_claims = [] | ||||
| 
 | ||||
| 	for data in [payment_entries, journal_entries, sales_invoices, purchase_invoices, expense_claims]: | ||||
| 		if data: | ||||
| 			payments.extend(data) | ||||
| 
 | ||||
| 	return payments | ||||
| 
 | ||||
| def get_matching_descriptions_data(company, transaction): | ||||
| 	if not transaction.description : | ||||
| 		return [] | ||||
| 
 | ||||
| 	bank_transactions = frappe.db.sql(""" | ||||
| 		SELECT | ||||
| 			bt.name, bt.description, bt.date, btp.payment_document, btp.payment_entry | ||||
| 		FROM | ||||
| 			`tabBank Transaction` as bt | ||||
| 		LEFT JOIN | ||||
| 			`tabBank Transaction Payments` as btp | ||||
| 		ON | ||||
| 			bt.name = btp.parent | ||||
| 		WHERE | ||||
| 			bt.allocated_amount > 0 | ||||
| 		AND | ||||
| 			bt.docstatus = 1 | ||||
| 		""", as_dict=True) | ||||
| 
 | ||||
| 	selection = [] | ||||
| 	for bank_transaction in bank_transactions: | ||||
| 		if bank_transaction.description: | ||||
| 			seq=difflib.SequenceMatcher(lambda x: x == " ", transaction.description, bank_transaction.description) | ||||
| 
 | ||||
| 			if seq.ratio() > 0.6: | ||||
| 				bank_transaction["ratio"] = seq.ratio() | ||||
| 				selection.append(bank_transaction) | ||||
| 
 | ||||
| 	document_types = set([x["payment_document"] for x in selection]) | ||||
| 
 | ||||
| 	links = {} | ||||
| 	for document_type in document_types: | ||||
| 		links[document_type] = [x["payment_entry"] for x in selection if x["payment_document"]==document_type] | ||||
| 
 | ||||
| 
 | ||||
| 	data = [] | ||||
| 	company_currency = get_company_currency(company) | ||||
| 	for key, value in iteritems(links): | ||||
| 		if key == "Payment Entry": | ||||
| 			data.extend(frappe.get_all("Payment Entry", filters=[["name", "in", value]], | ||||
| 				fields=["'Payment Entry' as doctype", "posting_date", "party", "reference_no", | ||||
| 					"reference_date", "paid_amount", "paid_to_account_currency as currency", "clearance_date"])) | ||||
| 		if key == "Journal Entry": | ||||
| 			journal_entries = frappe.get_all("Journal Entry", filters=[["name", "in", value]], | ||||
| 				fields=["name", "'Journal Entry' as doctype", "posting_date", | ||||
| 					"pay_to_recd_from as party", "cheque_no as reference_no", "cheque_date as reference_date", | ||||
| 					"total_credit as paid_amount", "clearance_date"]) | ||||
| 			for journal_entry in journal_entries: | ||||
| 				journal_entry_accounts = frappe.get_all("Journal Entry Account", filters={"parenttype": journal_entry["doctype"], "parent": journal_entry["name"]}, fields=["account_currency"]) | ||||
| 				journal_entry["currency"] = journal_entry_accounts[0]["account_currency"] if journal_entry_accounts else company_currency | ||||
| 			data.extend(journal_entries) | ||||
| 		if key == "Sales Invoice": | ||||
| 			data.extend(frappe.get_all("Sales Invoice", filters=[["name", "in", value]], fields=["'Sales Invoice' as doctype", "posting_date", "customer_name as party", "paid_amount", "currency"])) | ||||
| 		if key == "Purchase Invoice": | ||||
| 			data.extend(frappe.get_all("Purchase Invoice", filters=[["name", "in", value]], fields=["'Purchase Invoice' as doctype", "posting_date", "supplier_name as party", "paid_amount", "currency"])) | ||||
| 		if key == "Expense Claim": | ||||
| 			expense_claims = frappe.get_all("Expense Claim", filters=[["name", "in", value]], fields=["'Expense Claim' as doctype", "posting_date", "employee_name as party", "total_amount_reimbursed as paid_amount"]) | ||||
| 			data.extend([dict(x,**{"currency": company_currency}) for x in expense_claims]) | ||||
| 
 | ||||
| 	return data | ||||
| 
 | ||||
| def check_amount_vs_description(amount_matching, description_matching): | ||||
| 	result = [] | ||||
| 
 | ||||
| 	if description_matching: | ||||
| 		for am_match in amount_matching: | ||||
| 			for des_match in description_matching: | ||||
| 				if des_match.get("clearance_date"): | ||||
| 					continue | ||||
| 
 | ||||
| 				if am_match["party"] == des_match["party"]: | ||||
| 					if am_match not in result: | ||||
| 						result.append(am_match) | ||||
| 						continue | ||||
| 
 | ||||
| 				if "reference_no" in am_match and "reference_no" in des_match: | ||||
| 					if difflib.SequenceMatcher(lambda x: x == " ", am_match["reference_no"], des_match["reference_no"]).ratio() > 70: | ||||
| 						if am_match not in result: | ||||
| 							result.append(am_match) | ||||
| 		if result: | ||||
| 			return sorted(result, key = lambda x: x["posting_date"], reverse=True) | ||||
| 		else: | ||||
| 			return sorted(amount_matching, key = lambda x: x["posting_date"], reverse=True) | ||||
| 
 | ||||
| 	else: | ||||
| 		return sorted(amount_matching, key = lambda x: x["posting_date"], reverse=True) | ||||
| 
 | ||||
| def get_matching_transactions_payments(description_matching): | ||||
| 	payments = [x["payment_entry"] for x in description_matching] | ||||
| 
 | ||||
| 	payment_by_ratio = {x["payment_entry"]: x["ratio"] for x in description_matching} | ||||
| 
 | ||||
| 	if payments: | ||||
| 		reference_payment_list = frappe.get_all("Payment Entry", fields=["name", "paid_amount", "payment_type", "reference_no", "reference_date", | ||||
| 			"party", "party_type", "posting_date", "paid_to_account_currency"], filters=[["name", "in", payments]]) | ||||
| 
 | ||||
| 		return sorted(reference_payment_list, key=lambda x: payment_by_ratio[x["name"]]) | ||||
| 
 | ||||
| 	else: | ||||
| 		return [] | ||||
| 
 | ||||
| def payment_entry_query(doctype, txt, searchfield, start, page_len, filters): | ||||
| 	account = frappe.db.get_value("Bank Account", filters.get("bank_account"), "account") | ||||
| 	if not account: | ||||
| 		return | ||||
| 
 | ||||
| 	return frappe.db.sql(""" | ||||
| 		SELECT | ||||
| 			name, party, paid_amount, received_amount, reference_no | ||||
| 		FROM | ||||
| 			`tabPayment Entry` | ||||
| 		WHERE | ||||
| 			(clearance_date is null or clearance_date='0000-00-00') | ||||
| 			AND (paid_from = %(account)s or paid_to = %(account)s) | ||||
| 			AND (name like %(txt)s or party like %(txt)s) | ||||
| 			AND docstatus = 1 | ||||
| 		ORDER BY | ||||
| 			if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999), name | ||||
| 		LIMIT | ||||
| 			%(start)s, %(page_len)s""", | ||||
| 		{ | ||||
| 			'txt': "%%%s%%" % txt, | ||||
| 			'_txt': txt.replace("%", ""), | ||||
| 			'start': start, | ||||
| 			'page_len': page_len, | ||||
| 			'account': account | ||||
| 		} | ||||
| 	) | ||||
| 
 | ||||
| def journal_entry_query(doctype, txt, searchfield, start, page_len, filters): | ||||
| 	account = frappe.db.get_value("Bank Account", filters.get("bank_account"), "account") | ||||
| 
 | ||||
| 	return frappe.db.sql(""" | ||||
| 		SELECT | ||||
| 			jea.parent, je.pay_to_recd_from, | ||||
| 			if(jea.debit_in_account_currency > 0, jea.debit_in_account_currency, jea.credit_in_account_currency) | ||||
| 		FROM | ||||
| 			`tabJournal Entry Account` as jea | ||||
| 		LEFT JOIN | ||||
| 			`tabJournal Entry` as je | ||||
| 		ON | ||||
| 			jea.parent = je.name | ||||
| 		WHERE | ||||
| 			(je.clearance_date is null or je.clearance_date='0000-00-00') | ||||
| 		AND | ||||
| 			jea.account = %(account)s | ||||
| 		AND | ||||
| 			(jea.parent like %(txt)s or je.pay_to_recd_from like %(txt)s) | ||||
| 		AND | ||||
| 			je.docstatus = 1 | ||||
| 		ORDER BY | ||||
| 			if(locate(%(_txt)s, jea.parent), locate(%(_txt)s, jea.parent), 99999), | ||||
| 			jea.parent | ||||
| 		LIMIT | ||||
| 			%(start)s, %(page_len)s""", | ||||
| 		{ | ||||
| 			'txt': "%%%s%%" % txt, | ||||
| 			'_txt': txt.replace("%", ""), | ||||
| 			'start': start, | ||||
| 			'page_len': page_len, | ||||
| 			'account': account | ||||
| 		} | ||||
| 	) | ||||
| 
 | ||||
| def sales_invoices_query(doctype, txt, searchfield, start, page_len, filters): | ||||
| 	return frappe.db.sql(""" | ||||
| 		SELECT | ||||
| 			sip.parent, si.customer, sip.amount, sip.mode_of_payment | ||||
| 		FROM | ||||
| 			`tabSales Invoice Payment` as sip | ||||
| 		LEFT JOIN | ||||
| 			`tabSales Invoice` as si | ||||
| 		ON | ||||
| 			sip.parent = si.name | ||||
| 		WHERE | ||||
| 			(sip.clearance_date is null or sip.clearance_date='0000-00-00') | ||||
| 		AND | ||||
| 			(sip.parent like %(txt)s or si.customer like %(txt)s) | ||||
| 		ORDER BY | ||||
| 			if(locate(%(_txt)s, sip.parent), locate(%(_txt)s, sip.parent), 99999), | ||||
| 			sip.parent | ||||
| 		LIMIT | ||||
| 			%(start)s, %(page_len)s""", | ||||
| 		{ | ||||
| 			'txt': "%%%s%%" % txt, | ||||
| 			'_txt': txt.replace("%", ""), | ||||
| 			'start': start, | ||||
| 			'page_len': page_len | ||||
| 		} | ||||
| 	) | ||||
| @ -0,0 +1,21 @@ | ||||
| <div class="transaction-header"> | ||||
| 	<div class="level list-row list-row-head text-muted small"> | ||||
| 		<div class="col-sm-2 ellipsis hidden-xs"> | ||||
| 			{{ __("Date") }} | ||||
| 		</div> | ||||
| 		<div class="col-xs-11 col-sm-4 ellipsis list-subject"> | ||||
| 			{{ __("Description") }} | ||||
| 		</div> | ||||
| 		<div class="col-sm-2 ellipsis hidden-xs"> | ||||
| 			{{ __("Debit") }} | ||||
| 		</div> | ||||
| 		<div class="col-sm-2 ellipsis hidden-xs"> | ||||
| 			{{ __("Credit") }} | ||||
| 		</div> | ||||
| 		<div class="col-sm-1 ellipsis hidden-xs"> | ||||
| 			{{ __("Currency") }} | ||||
| 		</div> | ||||
| 		<div class="col-sm-1 ellipsis"> | ||||
| 		</div> | ||||
| 	</div> | ||||
| </div> | ||||
| @ -0,0 +1,36 @@ | ||||
| <div class="list-row transaction-item"> | ||||
| 	<div> | ||||
| 		<div class="clickable-section" data-name={{ name }}> | ||||
| 			<div class="col-sm-2 ellipsis hidden-xs"> | ||||
| 				{%= frappe.datetime.str_to_user(date) %} | ||||
| 			</div> | ||||
| 			<div class="col-xs-8 col-sm-4 ellipsis list-subject"> | ||||
| 				{{ description }} | ||||
| 			</div> | ||||
| 			<div class="col-sm-2 ellipsis hidden-xs"> | ||||
| 				{%= format_currency(debit, currency) %} | ||||
| 			</div> | ||||
| 			<div class="col-sm-2 ellipsis hidden-xs"> | ||||
| 				{%= format_currency(credit, currency) %} | ||||
| 			</div> | ||||
| 			<div class="col-sm-1 ellipsis hidden-xs"> | ||||
| 				{{ currency }} | ||||
| 			</div> | ||||
| 		</div> | ||||
| 		<div class="col-xs-3 col-sm-1"> | ||||
| 			<div class="btn-group"> | ||||
| 				<a class="dropdown-toggle btn btn-default btn-xs" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> | ||||
| 					<span>Actions </span> | ||||
| 					<span class="caret"></span> | ||||
| 				</a> | ||||
| 				<ul class="dropdown-menu reports-dropdown" style="max-height: 300px; overflow-y: auto; right: 0px; left: auto;"> | ||||
| 					<li><a class="new-reconciliation" data-name={{ name }}>{{ __("Reconcile") }}</a></li> | ||||
| 					<li class="divider"></li> | ||||
| 					<li><a class="new-payment" data-name={{ name }}>{{ __("New Payment") }}</a></li> | ||||
| 					<li><a class="new-invoice" data-name={{ name }}>{{ __("New Invoice") }}</a></li> | ||||
| 					<li><a class="new-expense" data-name={{ name }}>{{ __("New Expense") }}</a></li> | ||||
| 				</ul> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 	</div> | ||||
| </div> | ||||
| @ -0,0 +1,21 @@ | ||||
| <div class="transaction-header"> | ||||
| 	<div class="level list-row list-row-head text-muted small"> | ||||
| 		<div class="col-xs-3 col-sm-2 ellipsis"> | ||||
| 			{{ __("Payment Name") }} | ||||
| 		</div> | ||||
| 		<div class="col-xs-3 col-sm-2 ellipsis"> | ||||
| 			{{ __("Reference Date") }} | ||||
| 		</div> | ||||
| 		<div class="col-sm-2 ellipsis hidden-xs"> | ||||
| 			{{ __("Amount") }} | ||||
| 		</div> | ||||
| 		<div class="col-sm-2 ellipsis hidden-xs"> | ||||
| 			{{ __("Party") }} | ||||
| 		</div> | ||||
| 		<div class="col-xs-3 col-sm-2 ellipsis"> | ||||
| 			{{ __("Reference Number") }} | ||||
| 		</div> | ||||
| 		<div class="col-xs-2 col-sm-2"> | ||||
| 		</div> | ||||
| 	</div> | ||||
| </div> | ||||
| @ -0,0 +1,36 @@ | ||||
| <div class="list-row"> | ||||
| 	<div> | ||||
| 		<div class="col-xs-3 col-sm-2 ellipsis"> | ||||
| 			{{ name }} | ||||
| 		</div> | ||||
| 		<div class="col-xs-3 col-sm-2 ellipsis"> | ||||
| 			{% if (typeof reference_date !== "undefined") %} | ||||
| 				{%= frappe.datetime.str_to_user(reference_date) %} | ||||
| 			{% else %} | ||||
| 				{% if (typeof posting_date !== "undefined") %} | ||||
| 					{%= frappe.datetime.str_to_user(posting_date) %} | ||||
| 				{% endif %} | ||||
| 			{% endif %} | ||||
| 		</div> | ||||
| 		<div class="col-sm-2 ellipsis hidden-xs"> | ||||
| 			{{ format_currency(paid_amount, currency) }} | ||||
| 		</div> | ||||
| 		<div class="col-sm-2 ellipsis hidden-xs"> | ||||
| 			{% if (typeof party !== "undefined") %} | ||||
| 				{{ party }} | ||||
| 			{% endif %} | ||||
| 		</div> | ||||
| 		<div class="col-xs-3 col-sm-2 ellipsis"> | ||||
| 			{% if (typeof reference_no !== "undefined") %} | ||||
| 				{{ reference_no }} | ||||
| 			{% else %} | ||||
| 				{{ "" }} | ||||
| 			{% endif %} | ||||
| 		</div> | ||||
| 		<div class="col-xs-2 col-sm-2"> | ||||
| 			<div class="text-right margin-bottom"> | ||||
| 				<button class="btn btn-primary btn-xs reconciliation-btn" data-doctype="{{ doctype }}" data-name="{{ name }}">{{ __("Reconcile") }}</button> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 	</div> | ||||
| </div> | ||||
| @ -1957,6 +1957,12 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ | ||||
| 			}], | ||||
| 			function(values){ | ||||
| 				me.item_batch_no[me.items[0].item_code] = values.batch; | ||||
| 				const item = me.frm.doc.items.find( | ||||
| 					({ item_code }) => item_code === me.items[0].item_code | ||||
| 				); | ||||
| 				if (item) { | ||||
| 					item.batch_no = values.batch; | ||||
| 				} | ||||
| 			}, | ||||
| 			__('Select Batch No')) | ||||
| 		} | ||||
|  | ||||
| @ -44,7 +44,7 @@ def _get_party_details(party=None, account=None, party_type="Customer", company= | ||||
| 		frappe.throw(_("Not permitted for {0}").format(party), frappe.PermissionError) | ||||
| 
 | ||||
| 	party = frappe.get_doc(party_type, party) | ||||
| 	currency = party.default_currency if party.default_currency else get_company_currency(company) | ||||
| 	currency = party.default_currency if party.get("default_currency") else get_company_currency(company) | ||||
| 
 | ||||
| 	party_address, shipping_address = set_address_details(out, party, party_type, doctype, company, party_address, shipping_address) | ||||
| 	set_contact_details(out, party, party_type) | ||||
| @ -144,7 +144,7 @@ def set_other_values(out, party, party_type): | ||||
| 
 | ||||
| def get_default_price_list(party): | ||||
| 	"""Return default price list for party (Document object)""" | ||||
| 	if party.default_price_list: | ||||
| 	if party.get("default_price_list"): | ||||
| 		return party.default_price_list | ||||
| 
 | ||||
| 	if party.doctype == "Customer": | ||||
|  | ||||
| @ -1,19 +1,23 @@ | ||||
| { | ||||
|  "align_labels_right": 0, | ||||
|  "creation": "2014-08-28 11:11:39.796473", | ||||
|  "custom_format": 0, | ||||
|  "disabled": 0, | ||||
|  "doc_type": "Journal Entry", | ||||
|  "docstatus": 0, | ||||
|  "doctype": "Print Format", | ||||
|  "format_data": "[{\"fieldname\": \"print_heading_template\", \"fieldtype\": \"Custom HTML\", \"options\": \"<div class=\\\"print-heading\\\">\\t\\t\\t\\t<h2>Journal Entry<br><small>{{ doc.name }}</small>\\t\\t\\t\\t</h2></div>\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"voucher_type\", \"print_hide\": 0, \"label\": \"Entry Type\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"posting_date\", \"print_hide\": 0, \"label\": \"Posting Date\"}, {\"fieldname\": \"finance_book\", \"print_hide\": 0, \"label\": \"Finance Book\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"accounts\", \"print_hide\": 0, \"label\": \"Accounting Entries\", \"visible_columns\": [{\"fieldname\": \"account\", \"print_width\": \"250px\", \"print_hide\": 0}, {\"fieldname\": \"bank_account_no\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"party_type\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"party\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"debit_in_account_currency\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"credit_in_account_currency\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"reference_type\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"reference_name\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"reference_due_date\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"project\", \"print_width\": \"\", \"print_hide\": 0}]}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"cheque_no\", \"print_hide\": 0, \"label\": \"Reference Number\"}, {\"fieldname\": \"cheque_date\", \"print_hide\": 0, \"label\": \"Reference Date\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"get_balance\", \"print_hide\": 0, \"label\": \"Make Difference Entry\"}, {\"fieldname\": \"total_amount\", \"print_hide\": 0, \"label\": \"Total Amount\"}, {\"fieldtype\": \"Section Break\", \"label\": \"Reference\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"clearance_date\", \"print_hide\": 0, \"label\": \"Clearance Date\"}, {\"fieldname\": \"remark\", \"print_hide\": 0, \"label\": \"Remark\"}, {\"fieldname\": \"inter_company_journal_entry_reference\", \"print_hide\": 0, \"label\": \"Inter Company Journal Entry Reference\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"due_date\", \"print_hide\": 0, \"label\": \"Due Date\"}, {\"fieldtype\": \"Section Break\", \"label\": \"Printing Settings\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"pay_to_recd_from\", \"print_hide\": 0, \"label\": \"Pay To / Recd From\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"letter_head\", \"print_hide\": 0, \"label\": \"Letter Head\"}, {\"fieldtype\": \"Section Break\", \"label\": \"More Information\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"mode_of_payment\", \"print_hide\": 0, \"label\": \"Mode of Payment\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"stock_entry\", \"print_hide\": 0, \"label\": \"Stock Entry\"}]", | ||||
|  "html": "{%- from \"templates/print_formats/standard_macros.html\" import add_header -%}\n\n<div class=\"page-break\">\n    {%- if not doc.get(\"print_heading\") and not doc.get(\"select_print_heading\") \n        and doc.set(\"select_print_heading\", _(\"Credit Note\")) -%}{%- endif -%}\n    {{ add_header(0, 1, doc, letter_head, no_letterhead) }}\n\n    {%- for label, value in (\n        (_(\"Credit To\"), doc.pay_to_recd_from),\n        (_(\"Date\"), frappe.utils.formatdate(doc.voucher_date)),\n        (_(\"Amount\"), \"<strong>\" + doc.get_formatted(\"total_amount\") + \"</strong><br>\" + (doc.total_amount_in_words or \"\") + \"<br>\"),\n        (_(\"Remarks\"), doc.remark)\n    ) -%}\n\n    <div class=\"row\">\n        <div class=\"col-xs-3\"><label class=\"text-right\">{{ label }}</label></div>\n        <div class=\"col-xs-9\">{{ value }}</div>\n    </div>\n\n    {%- endfor -%}\n\n    <hr>\n    <br>\n    <p class=\"strong\">\n        {{ _(\"For\") }} {{ doc.company }},<br>\n        <br>\n        <br>\n        <br>\n        {{ _(\"Authorized Signatory\") }}\n    </p>\n</div>\n\n\n", | ||||
|  "idx": 2, | ||||
|  "modified": "2015-07-22 17:42:01.560817",  | ||||
|  "line_breaks": 0, | ||||
|  "modified": "2019-04-18 12:10:14.732269", | ||||
|  "modified_by": "Administrator", | ||||
|  "module": "Accounts", | ||||
|  "name": "Credit Note", | ||||
|  "owner": "Administrator", | ||||
|  "parent": "Journal Entry",  | ||||
|  "parentfield": "__print_formats", | ||||
|  "parenttype": "DocType",  | ||||
|  "print_format_builder": 0, | ||||
|  "print_format_type": "Server", | ||||
|  "show_section_headings": 0, | ||||
|  "standard": "Yes" | ||||
| } | ||||
| @ -197,10 +197,9 @@ class ReceivablePayableReport(object): | ||||
| 			self.payment_term_map = self.get_payment_term_detail(voucher_nos) | ||||
| 
 | ||||
| 		for gle in gl_entries_data: | ||||
| 			if self.is_receivable_or_payable(gle, self.dr_or_cr, future_vouchers): | ||||
| 			if self.is_receivable_or_payable(gle, self.dr_or_cr, future_vouchers, return_entries): | ||||
| 				outstanding_amount, credit_note_amount, payment_amount = self.get_outstanding_amount( | ||||
| 					gle,self.filters.report_date, self.dr_or_cr, return_entries) | ||||
| 
 | ||||
| 				temp_outstanding_amt = outstanding_amount | ||||
| 				temp_credit_note_amt = credit_note_amount | ||||
| 
 | ||||
| @ -379,7 +378,7 @@ class ReceivablePayableReport(object): | ||||
| 		# returns a generator | ||||
| 		return self.get_gl_entries(party_type, report_date) | ||||
| 
 | ||||
| 	def is_receivable_or_payable(self, gle, dr_or_cr, future_vouchers): | ||||
| 	def is_receivable_or_payable(self, gle, dr_or_cr, future_vouchers, return_entries): | ||||
| 		return ( | ||||
| 			# advance | ||||
| 			(not gle.against_voucher) or | ||||
| @ -390,30 +389,37 @@ class ReceivablePayableReport(object): | ||||
| 			# sales invoice/purchase invoice | ||||
| 			(gle.against_voucher==gle.voucher_no and gle.get(dr_or_cr) > 0) or | ||||
| 
 | ||||
| 			# standalone credit notes | ||||
| 			(gle.against_voucher==gle.voucher_no and gle.voucher_no in return_entries and not return_entries.get(gle.voucher_no)) or | ||||
| 
 | ||||
| 			# entries adjusted with future vouchers | ||||
| 			((gle.against_voucher_type, gle.against_voucher) in future_vouchers) | ||||
| 		) | ||||
| 
 | ||||
| 	def get_return_entries(self, party_type): | ||||
| 		doctype = "Sales Invoice" if party_type=="Customer" else "Purchase Invoice" | ||||
| 		return [d.name for d in frappe.get_all(doctype, filters={"is_return": 1, "docstatus": 1})] | ||||
| 		return_entries = frappe._dict(frappe.get_all(doctype, | ||||
| 			filters={"is_return": 1, "docstatus": 1}, fields=["name", "return_against"], as_list=1)) | ||||
| 		return return_entries | ||||
| 
 | ||||
| 	def get_outstanding_amount(self, gle, report_date, dr_or_cr, return_entries): | ||||
| 		payment_amount, credit_note_amount = 0.0, 0.0 | ||||
| 		reverse_dr_or_cr = "credit" if dr_or_cr=="debit" else "debit" | ||||
| 
 | ||||
| 		for e in self.get_gl_entries_for(gle.party, gle.party_type, gle.voucher_type, gle.voucher_no): | ||||
| 			if getdate(e.posting_date) <= report_date and e.name!=gle.name: | ||||
| 			if getdate(e.posting_date) <= report_date \ | ||||
| 				and (e.name!=gle.name or (e.voucher_no in return_entries and not return_entries.get(e.voucher_no))): | ||||
| 
 | ||||
| 				amount = flt(e.get(reverse_dr_or_cr), self.currency_precision) - flt(e.get(dr_or_cr), self.currency_precision) | ||||
| 				if e.voucher_no not in return_entries: | ||||
| 					payment_amount += amount | ||||
| 				else: | ||||
| 					credit_note_amount += amount | ||||
| 
 | ||||
| 		outstanding_amount = (flt((flt(gle.get(dr_or_cr), self.currency_precision) | ||||
| 			- flt(gle.get(reverse_dr_or_cr), self.currency_precision) | ||||
| 			- payment_amount - credit_note_amount), self.currency_precision)) | ||||
| 		voucher_amount = flt(gle.get(dr_or_cr), self.currency_precision) - flt(gle.get(reverse_dr_or_cr), self.currency_precision) | ||||
| 		if gle.voucher_no in return_entries and not return_entries.get(gle.voucher_no): | ||||
| 			voucher_amount = 0 | ||||
| 
 | ||||
| 		outstanding_amount = flt((voucher_amount - payment_amount - credit_note_amount), self.currency_precision) | ||||
| 		credit_note_amount = flt(credit_note_amount, self.currency_precision) | ||||
| 
 | ||||
| 		return outstanding_amount, credit_note_amount, payment_amount | ||||
|  | ||||
| @ -322,7 +322,10 @@ def sort_accounts(accounts, is_root=False, key="name"): | ||||
| 	"""Sort root types as Asset, Liability, Equity, Income, Expense""" | ||||
| 
 | ||||
| 	def compare_accounts(a, b): | ||||
| 		if is_root: | ||||
| 		if re.split('\W+', a[key])[0].isdigit(): | ||||
| 			# if chart of accounts is numbered, then sort by number | ||||
| 			return cmp(a[key], b[key]) | ||||
| 		elif is_root: | ||||
| 			if a.report_type != b.report_type and a.report_type == "Balance Sheet": | ||||
| 				return -1 | ||||
| 			if a.root_type != b.root_type and a.root_type == "Asset": | ||||
| @ -353,6 +356,7 @@ def set_gl_entries_by_account( | ||||
| 		"company": company, | ||||
| 		"from_date": from_date, | ||||
| 		"to_date": to_date, | ||||
| 		"finance_book": filters.get("finance_book") | ||||
| 	} | ||||
| 
 | ||||
| 	if filters.get("include_default_book_entries"): | ||||
|  | ||||
| @ -171,4 +171,3 @@ dimension_filters.then((dimensions) => { | ||||
| 		}); | ||||
| 	}); | ||||
| }); | ||||
| 
 | ||||
|  | ||||
| @ -65,7 +65,7 @@ def get_columns(group_wise_columns, filters): | ||||
| 		"warehouse": _("Warehouse") + ":Link/Warehouse", | ||||
| 		"qty": _("Qty") + ":Float", | ||||
| 		"base_rate": _("Avg. Selling Rate") + ":Currency/currency", | ||||
| 		"buying_rate": _("Avg. Buying Rate") + ":Currency/currency", | ||||
| 		"buying_rate": _("Valuation Rate") + ":Currency/currency", | ||||
| 		"base_amount": _("Selling Amount") + ":Currency/currency", | ||||
| 		"buying_amount": _("Buying Amount") + ":Currency/currency", | ||||
| 		"gross_profit": _("Gross Profit") + ":Currency/currency", | ||||
|  | ||||
| @ -1,14 +1,13 @@ | ||||
| { | ||||
|  "add_total_row": 0, | ||||
|  "creation": "2019-05-01 13:46:23.044979", | ||||
|  "creation": "2019-05-01 12:59:52.018850", | ||||
|  "disable_prepared_report": 0, | ||||
|  "disabled": 0, | ||||
|  "docstatus": 0, | ||||
|  "doctype": "Report", | ||||
|  "idx": 0, | ||||
|  "is_standard": "Yes", | ||||
|  "letter_head": "Test Letter Head 1", | ||||
|  "modified": "2019-05-01 13:46:23.044979", | ||||
|  "modified": "2019-05-01 13:00:26.545278", | ||||
|  "modified_by": "Administrator", | ||||
|  "module": "Accounts", | ||||
|  "name": "Inactive Sales Items", | ||||
| @ -17,5 +16,15 @@ | ||||
|  "ref_doctype": "Sales Invoice", | ||||
|  "report_name": "Inactive Sales Items", | ||||
|  "report_type": "Script Report", | ||||
|  "roles": [] | ||||
|  "roles": [ | ||||
|   { | ||||
|    "role": "Accounts User" | ||||
|   }, | ||||
|   { | ||||
|    "role": "Accounts Manager" | ||||
|   }, | ||||
|   { | ||||
|    "role": "Auditor" | ||||
|   } | ||||
|  ] | ||||
| } | ||||
| @ -102,9 +102,7 @@ def get_conditions(filters): | ||||
| 		("customer", " and `tabSales Invoice`.customer = %(customer)s"), | ||||
| 		("item_code", " and `tabSales Invoice Item`.item_code = %(item_code)s"), | ||||
| 		("from_date", " and `tabSales Invoice`.posting_date>=%(from_date)s"), | ||||
| 		("to_date", " and `tabSales Invoice`.posting_date<=%(to_date)s"), | ||||
| 		("company_gstin", " and `tabSales Invoice`.company_gstin = %(company_gstin)s"), | ||||
| 		("invoice_type", " and `tabSales Invoice`.invoice_type = %(invoice_type)s")): | ||||
| 		("to_date", " and `tabSales Invoice`.posting_date<=%(to_date)s")): | ||||
| 			if filters.get(opts[0]): | ||||
| 				conditions += opts[1] | ||||
| 
 | ||||
|  | ||||
| @ -618,7 +618,7 @@ def get_held_invoices(party_type, party): | ||||
| 	return held_invoices | ||||
| 
 | ||||
| 
 | ||||
| def get_outstanding_invoices(party_type, party, account, condition=None, limit=None): | ||||
| def get_outstanding_invoices(party_type, party, account, condition=None): | ||||
| 	outstanding_invoices = [] | ||||
| 	precision = frappe.get_precision("Sales Invoice", "outstanding_amount") or 2 | ||||
| 
 | ||||
| @ -631,7 +631,6 @@ def get_outstanding_invoices(party_type, party, account, condition=None, limit=N | ||||
| 
 | ||||
| 	invoice = 'Sales Invoice' if erpnext.get_party_account_type(party_type) == 'Receivable' else 'Purchase Invoice' | ||||
| 	held_invoices = get_held_invoices(party_type, party) | ||||
| 	limit_cond = "limit %s" % limit if limit else "" | ||||
| 
 | ||||
| 	invoice_list = frappe.db.sql(""" | ||||
| 		select | ||||
| @ -646,11 +645,10 @@ def get_outstanding_invoices(party_type, party, account, condition=None, limit=N | ||||
| 					and (against_voucher = '' or against_voucher is null)) | ||||
| 				or (voucher_type not in ('Journal Entry', 'Payment Entry'))) | ||||
| 		group by voucher_type, voucher_no | ||||
| 		order by posting_date, name {limit_cond}""".format( | ||||
| 		order by posting_date, name""".format( | ||||
| 			dr_or_cr=dr_or_cr, | ||||
| 			invoice = invoice, | ||||
| 			condition=condition or "", | ||||
| 			limit_cond = limit_cond | ||||
| 			condition=condition or "" | ||||
| 		), { | ||||
| 			"party_type": party_type, | ||||
| 			"party": party, | ||||
|  | ||||
| @ -1,497 +1,497 @@ | ||||
| { | ||||
|  "allow_import": 1, | ||||
|  "allow_rename": 1, | ||||
|  "autoname": "naming_series:", | ||||
|  "creation": "2016-03-01 17:01:27.920130", | ||||
|  "doctype": "DocType", | ||||
|  "document_type": "Document", | ||||
|  "field_order": [ | ||||
|   "naming_series", | ||||
|   "asset_name", | ||||
|   "item_code", | ||||
|   "item_name", | ||||
|   "asset_category", | ||||
|   "asset_owner", | ||||
|   "asset_owner_company", | ||||
|   "supplier", | ||||
|   "customer", | ||||
|   "image", | ||||
|   "column_break_3", | ||||
|   "company", | ||||
|   "location", | ||||
|   "custodian", | ||||
|   "department", | ||||
|   "purchase_date", | ||||
|   "disposal_date", | ||||
|   "journal_entry_for_scrap", | ||||
|   "accounting_dimensions_section", | ||||
|   "cost_center", | ||||
|   "dimension_col_break", | ||||
|   "section_break_5", | ||||
|   "gross_purchase_amount", | ||||
|   "available_for_use_date", | ||||
|   "column_break_18", | ||||
|   "calculate_depreciation", | ||||
|   "is_existing_asset", | ||||
|   "opening_accumulated_depreciation", | ||||
|   "number_of_depreciations_booked", | ||||
|   "section_break_23", | ||||
|   "finance_books", | ||||
|   "section_break_33", | ||||
|   "depreciation_method", | ||||
|   "value_after_depreciation", | ||||
|   "total_number_of_depreciations", | ||||
|   "column_break_24", | ||||
|   "frequency_of_depreciation", | ||||
|   "next_depreciation_date", | ||||
|   "section_break_14", | ||||
|   "schedules", | ||||
|   "insurance_details", | ||||
|   "policy_number", | ||||
|   "insurer", | ||||
|   "insured_value", | ||||
|   "column_break_48", | ||||
|   "insurance_start_date", | ||||
|   "insurance_end_date", | ||||
|   "comprehensive_insurance", | ||||
|   "section_break_31", | ||||
|   "maintenance_required", | ||||
|   "other_details", | ||||
|   "status", | ||||
|   "booked_fixed_asset", | ||||
|   "column_break_51", | ||||
|   "purchase_receipt", | ||||
|   "purchase_receipt_amount", | ||||
|   "purchase_invoice", | ||||
|   "default_finance_book", | ||||
|   "amended_from" | ||||
|  ], | ||||
|  "fields": [ | ||||
|   { | ||||
|    "fieldname": "naming_series", | ||||
|    "fieldtype": "Select", | ||||
|    "label": "Naming Series", | ||||
|    "options": "ACC-ASS-.YYYY.-" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "asset_name", | ||||
|    "fieldtype": "Data", | ||||
|    "in_list_view": 1, | ||||
|    "label": "Asset Name", | ||||
|    "reqd": 1 | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "item_code", | ||||
|    "fieldtype": "Link", | ||||
|    "in_standard_filter": 1, | ||||
|    "label": "Item Code", | ||||
|    "options": "Item", | ||||
|    "reqd": 1 | ||||
|   }, | ||||
|   { | ||||
|    "fetch_from": "item_code.item_name", | ||||
|    "fieldname": "item_name", | ||||
|    "fieldtype": "Read Only", | ||||
|    "label": "Item Name" | ||||
|   }, | ||||
|   { | ||||
|    "fetch_from": "item_code.asset_category", | ||||
|    "fieldname": "asset_category", | ||||
|    "fieldtype": "Link", | ||||
|    "in_global_search": 1, | ||||
|    "in_list_view": 1, | ||||
|    "in_standard_filter": 1, | ||||
|    "label": "Asset Category", | ||||
|    "options": "Asset Category", | ||||
|    "read_only": 1 | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "asset_owner", | ||||
|    "fieldtype": "Select", | ||||
|    "label": "Asset Owner", | ||||
|    "options": "\nCompany\nSupplier\nCustomer" | ||||
|   }, | ||||
|   { | ||||
|    "depends_on": "eval:doc.asset_owner == \"Company\"", | ||||
|    "fieldname": "asset_owner_company", | ||||
|    "fieldtype": "Link", | ||||
|    "label": "Asset Owner Company", | ||||
|    "options": "Company" | ||||
|   }, | ||||
|   { | ||||
|    "depends_on": "eval:doc.asset_owner == \"Supplier\"", | ||||
|    "fieldname": "supplier", | ||||
|    "fieldtype": "Link", | ||||
|    "label": "Supplier", | ||||
|    "options": "Supplier" | ||||
|   }, | ||||
|   { | ||||
|    "depends_on": "eval:doc.asset_owner == \"Customer\"", | ||||
|    "fieldname": "customer", | ||||
|    "fieldtype": "Link", | ||||
|    "label": "Customer", | ||||
|    "options": "Customer" | ||||
|   }, | ||||
|   { | ||||
|    "allow_on_submit": 1, | ||||
|    "fieldname": "image", | ||||
|    "fieldtype": "Attach Image", | ||||
|    "hidden": 1, | ||||
|    "label": "Image", | ||||
|    "no_copy": 1, | ||||
|    "print_hide": 1 | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "column_break_3", | ||||
|    "fieldtype": "Column Break" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "company", | ||||
|    "fieldtype": "Link", | ||||
|    "label": "Company", | ||||
|    "options": "Company", | ||||
|    "remember_last_selected_value": 1, | ||||
|    "reqd": 1 | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "location", | ||||
|    "fieldtype": "Link", | ||||
|    "in_list_view": 1, | ||||
|    "label": "Location", | ||||
|    "options": "Location", | ||||
|    "reqd": 1 | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "custodian", | ||||
|    "fieldtype": "Link", | ||||
|    "ignore_user_permissions": 1, | ||||
|    "label": "Custodian", | ||||
|    "options": "Employee" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "cost_center", | ||||
|    "fieldtype": "Link", | ||||
|    "label": "Cost Center", | ||||
|    "options": "Cost Center" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "department", | ||||
|    "fieldtype": "Link", | ||||
|    "label": "Department", | ||||
|    "options": "Department" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "purchase_date", | ||||
|    "fieldtype": "Date", | ||||
|    "label": "Purchase Date", | ||||
|    "reqd": 1 | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "disposal_date", | ||||
|    "fieldtype": "Date", | ||||
|    "label": "Disposal Date", | ||||
|    "read_only": 1 | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "journal_entry_for_scrap", | ||||
|    "fieldtype": "Link", | ||||
|    "label": "Journal Entry for Scrap", | ||||
|    "no_copy": 1, | ||||
|    "options": "Journal Entry", | ||||
|    "print_hide": 1, | ||||
|    "read_only": 1 | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "section_break_5", | ||||
|    "fieldtype": "Section Break" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "gross_purchase_amount", | ||||
|    "fieldtype": "Currency", | ||||
|    "label": "Gross Purchase Amount", | ||||
|    "options": "Company:company:default_currency", | ||||
|    "reqd": 1 | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "available_for_use_date", | ||||
|    "fieldtype": "Date", | ||||
|    "label": "Available-for-use Date" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "column_break_18", | ||||
|    "fieldtype": "Column Break" | ||||
|   }, | ||||
|   { | ||||
|    "default": "0", | ||||
|    "fieldname": "calculate_depreciation", | ||||
|    "fieldtype": "Check", | ||||
|    "label": "Calculate Depreciation" | ||||
|   }, | ||||
|   { | ||||
|    "default": "0", | ||||
|    "fieldname": "is_existing_asset", | ||||
|    "fieldtype": "Check", | ||||
|    "label": "Is Existing Asset" | ||||
|   }, | ||||
|   { | ||||
|    "depends_on": "is_existing_asset", | ||||
|    "fieldname": "opening_accumulated_depreciation", | ||||
|    "fieldtype": "Currency", | ||||
|    "label": "Opening Accumulated Depreciation", | ||||
|    "no_copy": 1, | ||||
|    "options": "Company:company:default_currency" | ||||
|   }, | ||||
|   { | ||||
|    "depends_on": "eval:(doc.is_existing_asset && doc.opening_accumulated_depreciation)", | ||||
|    "fieldname": "number_of_depreciations_booked", | ||||
|    "fieldtype": "Int", | ||||
|    "label": "Number of Depreciations Booked", | ||||
|    "no_copy": 1 | ||||
|   }, | ||||
|   { | ||||
|    "depends_on": "calculate_depreciation", | ||||
|    "fieldname": "section_break_23", | ||||
|    "fieldtype": "Section Break", | ||||
|    "label": "Depreciation" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "finance_books", | ||||
|    "fieldtype": "Table", | ||||
|    "label": "Finance Books", | ||||
|    "options": "Asset Finance Book" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "section_break_33", | ||||
|    "fieldtype": "Section Break", | ||||
|    "hidden": 1 | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "depreciation_method", | ||||
|    "fieldtype": "Select", | ||||
|    "label": "Depreciation Method", | ||||
|    "options": "\nStraight Line\nDouble Declining Balance\nManual" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "value_after_depreciation", | ||||
|    "fieldtype": "Currency", | ||||
|    "hidden": 1, | ||||
|    "label": "Value After Depreciation", | ||||
|    "options": "Company:company:default_currency", | ||||
|    "read_only": 1 | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "total_number_of_depreciations", | ||||
|    "fieldtype": "Int", | ||||
|    "label": "Total Number of Depreciations" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "column_break_24", | ||||
|    "fieldtype": "Column Break" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "frequency_of_depreciation", | ||||
|    "fieldtype": "Int", | ||||
|    "label": "Frequency of Depreciation (Months)" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "next_depreciation_date", | ||||
|    "fieldtype": "Date", | ||||
|    "label": "Next Depreciation Date", | ||||
|    "no_copy": 1 | ||||
|   }, | ||||
|   { | ||||
|    "depends_on": "calculate_depreciation", | ||||
|    "fieldname": "section_break_14", | ||||
|    "fieldtype": "Section Break", | ||||
|    "label": "Depreciation Schedule" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "schedules", | ||||
|    "fieldtype": "Table", | ||||
|    "label": "Depreciation Schedules", | ||||
|    "no_copy": 1, | ||||
|    "options": "Depreciation Schedule" | ||||
|   }, | ||||
|   { | ||||
|    "collapsible": 1, | ||||
|    "fieldname": "insurance_details", | ||||
|    "fieldtype": "Section Break", | ||||
|    "label": "Insurance details" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "policy_number", | ||||
|    "fieldtype": "Data", | ||||
|    "label": "Policy number" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "insurer", | ||||
|    "fieldtype": "Data", | ||||
|    "label": "Insurer" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "insured_value", | ||||
|    "fieldtype": "Data", | ||||
|    "label": "Insured value" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "column_break_48", | ||||
|    "fieldtype": "Column Break" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "insurance_start_date", | ||||
|    "fieldtype": "Date", | ||||
|    "label": "Insurance Start Date" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "insurance_end_date", | ||||
|    "fieldtype": "Date", | ||||
|    "label": "Insurance End Date" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "comprehensive_insurance", | ||||
|    "fieldtype": "Data", | ||||
|    "label": "Comprehensive Insurance" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "section_break_31", | ||||
|    "fieldtype": "Section Break", | ||||
|    "label": "Maintenance" | ||||
|   }, | ||||
|   { | ||||
|    "allow_on_submit": 1, | ||||
|    "default": "0", | ||||
|    "description": "Check if Asset requires Preventive Maintenance or Calibration", | ||||
|    "fieldname": "maintenance_required", | ||||
|    "fieldtype": "Check", | ||||
|    "label": "Maintenance Required" | ||||
|   }, | ||||
|   { | ||||
|    "collapsible": 1, | ||||
|    "fieldname": "other_details", | ||||
|    "fieldtype": "Section Break", | ||||
|    "label": "Other Details" | ||||
|   }, | ||||
|   { | ||||
|    "allow_on_submit": 1, | ||||
|    "default": "Draft", | ||||
|    "fieldname": "status", | ||||
|    "fieldtype": "Select", | ||||
|    "in_list_view": 1, | ||||
|    "in_standard_filter": 1, | ||||
|    "label": "Status", | ||||
|    "no_copy": 1, | ||||
|    "options": "Draft\nSubmitted\nPartially Depreciated\nFully Depreciated\nSold\nScrapped\nIn Maintenance\nOut of Order\nIssue\nReceipt", | ||||
|    "read_only": 1 | ||||
|   }, | ||||
|   { | ||||
|    "default": "0", | ||||
|    "fieldname": "booked_fixed_asset", | ||||
|    "fieldtype": "Check", | ||||
|    "label": "Booked Fixed Asset", | ||||
|    "no_copy": 1, | ||||
|    "read_only": 1 | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "column_break_51", | ||||
|    "fieldtype": "Column Break" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "purchase_receipt", | ||||
|    "fieldtype": "Link", | ||||
|    "label": "Purchase Receipt", | ||||
|    "no_copy": 1, | ||||
|    "options": "Purchase Receipt", | ||||
|    "print_hide": 1, | ||||
|    "read_only": 1 | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "purchase_receipt_amount", | ||||
|    "fieldtype": "Currency", | ||||
|    "hidden": 1, | ||||
|    "label": "Purchase Receipt Amount", | ||||
|    "no_copy": 1, | ||||
|    "print_hide": 1, | ||||
|    "read_only": 1 | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "purchase_invoice", | ||||
|    "fieldtype": "Link", | ||||
|    "label": "Purchase Invoice", | ||||
|    "no_copy": 1, | ||||
|    "options": "Purchase Invoice", | ||||
|    "read_only": 1 | ||||
|   }, | ||||
|   { | ||||
|    "fetch_from": "company.default_finance_book", | ||||
|    "fieldname": "default_finance_book", | ||||
|    "fieldtype": "Link", | ||||
|    "hidden": 1, | ||||
|    "label": "Default Finance Book", | ||||
|    "options": "Finance Book", | ||||
|    "read_only": 1 | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "amended_from", | ||||
|    "fieldtype": "Link", | ||||
|    "label": "Amended From", | ||||
|    "no_copy": 1, | ||||
|    "options": "Asset", | ||||
|    "print_hide": 1, | ||||
|    "read_only": 1 | ||||
|   }, | ||||
|   { | ||||
|    "collapsible": 1, | ||||
|    "fieldname": "accounting_dimensions_section", | ||||
|    "fieldtype": "Section Break", | ||||
|    "label": "Accounting Dimensions" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "dimension_col_break", | ||||
|    "fieldtype": "Column Break" | ||||
|    "allow_import": 1, | ||||
|    "allow_rename": 1, | ||||
|    "autoname": "naming_series:", | ||||
|    "creation": "2016-03-01 17:01:27.920130", | ||||
|    "doctype": "DocType", | ||||
|    "document_type": "Document", | ||||
|    "field_order": [ | ||||
|     "naming_series", | ||||
|     "asset_name", | ||||
|     "item_code", | ||||
|     "item_name", | ||||
|     "asset_category", | ||||
|     "asset_owner", | ||||
|     "asset_owner_company", | ||||
|     "supplier", | ||||
|     "customer", | ||||
|     "image", | ||||
|     "column_break_3", | ||||
|     "company", | ||||
|     "location", | ||||
|     "custodian", | ||||
|     "department", | ||||
|     "purchase_date", | ||||
|     "disposal_date", | ||||
|     "journal_entry_for_scrap", | ||||
|     "accounting_dimensions_section", | ||||
|     "cost_center", | ||||
|     "dimension_col_break", | ||||
|     "section_break_5", | ||||
|     "gross_purchase_amount", | ||||
|     "available_for_use_date", | ||||
|     "column_break_18", | ||||
|     "calculate_depreciation", | ||||
|     "is_existing_asset", | ||||
|     "opening_accumulated_depreciation", | ||||
|     "number_of_depreciations_booked", | ||||
|     "section_break_23", | ||||
|     "finance_books", | ||||
|     "section_break_33", | ||||
|     "depreciation_method", | ||||
|     "value_after_depreciation", | ||||
|     "total_number_of_depreciations", | ||||
|     "column_break_24", | ||||
|     "frequency_of_depreciation", | ||||
|     "next_depreciation_date", | ||||
|     "section_break_14", | ||||
|     "schedules", | ||||
|     "insurance_details", | ||||
|     "policy_number", | ||||
|     "insurer", | ||||
|     "insured_value", | ||||
|     "column_break_48", | ||||
|     "insurance_start_date", | ||||
|     "insurance_end_date", | ||||
|     "comprehensive_insurance", | ||||
|     "section_break_31", | ||||
|     "maintenance_required", | ||||
|     "other_details", | ||||
|     "status", | ||||
|     "booked_fixed_asset", | ||||
|     "column_break_51", | ||||
|     "purchase_receipt", | ||||
|     "purchase_receipt_amount", | ||||
|     "purchase_invoice", | ||||
|     "default_finance_book", | ||||
|     "amended_from" | ||||
|    ], | ||||
|    "fields": [ | ||||
|     { | ||||
|      "fieldname": "naming_series", | ||||
|      "fieldtype": "Select", | ||||
|      "label": "Naming Series", | ||||
|      "options": "ACC-ASS-.YYYY.-" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "asset_name", | ||||
|      "fieldtype": "Data", | ||||
|      "in_list_view": 1, | ||||
|      "label": "Asset Name", | ||||
|      "reqd": 1 | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "item_code", | ||||
|      "fieldtype": "Link", | ||||
|      "in_standard_filter": 1, | ||||
|      "label": "Item Code", | ||||
|      "options": "Item", | ||||
|      "reqd": 1 | ||||
|     }, | ||||
|     { | ||||
|      "fetch_from": "item_code.item_name", | ||||
|      "fieldname": "item_name", | ||||
|      "fieldtype": "Read Only", | ||||
|      "label": "Item Name" | ||||
|     }, | ||||
|     { | ||||
|      "fetch_from": "item_code.asset_category", | ||||
|      "fieldname": "asset_category", | ||||
|      "fieldtype": "Link", | ||||
|      "in_global_search": 1, | ||||
|      "in_list_view": 1, | ||||
|      "in_standard_filter": 1, | ||||
|      "label": "Asset Category", | ||||
|      "options": "Asset Category", | ||||
|      "read_only": 1 | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "asset_owner", | ||||
|      "fieldtype": "Select", | ||||
|      "label": "Asset Owner", | ||||
|      "options": "\nCompany\nSupplier\nCustomer" | ||||
|     }, | ||||
|     { | ||||
|      "depends_on": "eval:doc.asset_owner == \"Company\"", | ||||
|      "fieldname": "asset_owner_company", | ||||
|      "fieldtype": "Link", | ||||
|      "label": "Asset Owner Company", | ||||
|      "options": "Company" | ||||
|     }, | ||||
|     { | ||||
|      "depends_on": "eval:doc.asset_owner == \"Supplier\"", | ||||
|      "fieldname": "supplier", | ||||
|      "fieldtype": "Link", | ||||
|      "label": "Supplier", | ||||
|      "options": "Supplier" | ||||
|     }, | ||||
|     { | ||||
|      "depends_on": "eval:doc.asset_owner == \"Customer\"", | ||||
|      "fieldname": "customer", | ||||
|      "fieldtype": "Link", | ||||
|      "label": "Customer", | ||||
|      "options": "Customer" | ||||
|     }, | ||||
|     { | ||||
|      "allow_on_submit": 1, | ||||
|      "fieldname": "image", | ||||
|      "fieldtype": "Attach Image", | ||||
|      "hidden": 1, | ||||
|      "label": "Image", | ||||
|      "no_copy": 1, | ||||
|      "print_hide": 1 | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "column_break_3", | ||||
|      "fieldtype": "Column Break" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "company", | ||||
|      "fieldtype": "Link", | ||||
|      "label": "Company", | ||||
|      "options": "Company", | ||||
|      "remember_last_selected_value": 1, | ||||
|      "reqd": 1 | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "location", | ||||
|      "fieldtype": "Link", | ||||
|      "in_list_view": 1, | ||||
|      "label": "Location", | ||||
|      "options": "Location", | ||||
|      "reqd": 1 | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "custodian", | ||||
|      "fieldtype": "Link", | ||||
|      "ignore_user_permissions": 1, | ||||
|      "label": "Custodian", | ||||
|      "options": "Employee" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "cost_center", | ||||
|      "fieldtype": "Link", | ||||
|      "label": "Cost Center", | ||||
|      "options": "Cost Center" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "department", | ||||
|      "fieldtype": "Link", | ||||
|      "label": "Department", | ||||
|      "options": "Department" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "purchase_date", | ||||
|      "fieldtype": "Date", | ||||
|      "label": "Purchase Date", | ||||
|      "reqd": 1 | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "disposal_date", | ||||
|      "fieldtype": "Date", | ||||
|      "label": "Disposal Date", | ||||
|      "read_only": 1 | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "journal_entry_for_scrap", | ||||
|      "fieldtype": "Link", | ||||
|      "label": "Journal Entry for Scrap", | ||||
|      "no_copy": 1, | ||||
|      "options": "Journal Entry", | ||||
|      "print_hide": 1, | ||||
|      "read_only": 1 | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "section_break_5", | ||||
|      "fieldtype": "Section Break" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "gross_purchase_amount", | ||||
|      "fieldtype": "Currency", | ||||
|      "label": "Gross Purchase Amount", | ||||
|      "options": "Company:company:default_currency", | ||||
|      "reqd": 1 | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "available_for_use_date", | ||||
|      "fieldtype": "Date", | ||||
|      "label": "Available-for-use Date" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "column_break_18", | ||||
|      "fieldtype": "Column Break" | ||||
|     }, | ||||
|     { | ||||
|      "default": "0", | ||||
|      "fieldname": "calculate_depreciation", | ||||
|      "fieldtype": "Check", | ||||
|      "label": "Calculate Depreciation" | ||||
|     }, | ||||
|     { | ||||
|      "default": "0", | ||||
|      "fieldname": "is_existing_asset", | ||||
|      "fieldtype": "Check", | ||||
|      "label": "Is Existing Asset" | ||||
|     }, | ||||
|     { | ||||
|      "depends_on": "is_existing_asset", | ||||
|      "fieldname": "opening_accumulated_depreciation", | ||||
|      "fieldtype": "Currency", | ||||
|      "label": "Opening Accumulated Depreciation", | ||||
|      "no_copy": 1, | ||||
|      "options": "Company:company:default_currency" | ||||
|     }, | ||||
|     { | ||||
|      "depends_on": "eval:(doc.is_existing_asset && doc.opening_accumulated_depreciation)", | ||||
|      "fieldname": "number_of_depreciations_booked", | ||||
|      "fieldtype": "Int", | ||||
|      "label": "Number of Depreciations Booked", | ||||
|      "no_copy": 1 | ||||
|     }, | ||||
|     { | ||||
|      "depends_on": "calculate_depreciation", | ||||
|      "fieldname": "section_break_23", | ||||
|      "fieldtype": "Section Break", | ||||
|      "label": "Depreciation" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "finance_books", | ||||
|      "fieldtype": "Table", | ||||
|      "label": "Finance Books", | ||||
|      "options": "Asset Finance Book" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "section_break_33", | ||||
|      "fieldtype": "Section Break", | ||||
|      "hidden": 1 | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "depreciation_method", | ||||
|      "fieldtype": "Select", | ||||
|      "label": "Depreciation Method", | ||||
|      "options": "\nStraight Line\nDouble Declining Balance\nManual" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "value_after_depreciation", | ||||
|      "fieldtype": "Currency", | ||||
|      "hidden": 1, | ||||
|      "label": "Value After Depreciation", | ||||
|      "options": "Company:company:default_currency", | ||||
|      "read_only": 1 | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "total_number_of_depreciations", | ||||
|      "fieldtype": "Int", | ||||
|      "label": "Total Number of Depreciations" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "column_break_24", | ||||
|      "fieldtype": "Column Break" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "frequency_of_depreciation", | ||||
|      "fieldtype": "Int", | ||||
|      "label": "Frequency of Depreciation (Months)" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "next_depreciation_date", | ||||
|      "fieldtype": "Date", | ||||
|      "label": "Next Depreciation Date", | ||||
|      "no_copy": 1 | ||||
|     }, | ||||
|     { | ||||
|      "depends_on": "calculate_depreciation", | ||||
|      "fieldname": "section_break_14", | ||||
|      "fieldtype": "Section Break", | ||||
|      "label": "Depreciation Schedule" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "schedules", | ||||
|      "fieldtype": "Table", | ||||
|      "label": "Depreciation Schedules", | ||||
|      "no_copy": 1, | ||||
|      "options": "Depreciation Schedule" | ||||
|     }, | ||||
|     { | ||||
|      "collapsible": 1, | ||||
|      "fieldname": "insurance_details", | ||||
|      "fieldtype": "Section Break", | ||||
|      "label": "Insurance details" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "policy_number", | ||||
|      "fieldtype": "Data", | ||||
|      "label": "Policy number" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "insurer", | ||||
|      "fieldtype": "Data", | ||||
|      "label": "Insurer" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "insured_value", | ||||
|      "fieldtype": "Data", | ||||
|      "label": "Insured value" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "column_break_48", | ||||
|      "fieldtype": "Column Break" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "insurance_start_date", | ||||
|      "fieldtype": "Date", | ||||
|      "label": "Insurance Start Date" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "insurance_end_date", | ||||
|      "fieldtype": "Date", | ||||
|      "label": "Insurance End Date" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "comprehensive_insurance", | ||||
|      "fieldtype": "Data", | ||||
|      "label": "Comprehensive Insurance" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "section_break_31", | ||||
|      "fieldtype": "Section Break", | ||||
|      "label": "Maintenance" | ||||
|     }, | ||||
|     { | ||||
|      "allow_on_submit": 1, | ||||
|      "default": "0", | ||||
|      "description": "Check if Asset requires Preventive Maintenance or Calibration", | ||||
|      "fieldname": "maintenance_required", | ||||
|      "fieldtype": "Check", | ||||
|      "label": "Maintenance Required" | ||||
|     }, | ||||
|     { | ||||
|      "collapsible": 1, | ||||
|      "fieldname": "other_details", | ||||
|      "fieldtype": "Section Break", | ||||
|      "label": "Other Details" | ||||
|     }, | ||||
|     { | ||||
|      "allow_on_submit": 1, | ||||
|      "default": "Draft", | ||||
|      "fieldname": "status", | ||||
|      "fieldtype": "Select", | ||||
|      "in_list_view": 1, | ||||
|      "in_standard_filter": 1, | ||||
|      "label": "Status", | ||||
|      "no_copy": 1, | ||||
|      "options": "Draft\nSubmitted\nPartially Depreciated\nFully Depreciated\nSold\nScrapped\nIn Maintenance\nOut of Order\nIssue\nReceipt", | ||||
|      "read_only": 1 | ||||
|     }, | ||||
|     { | ||||
|      "default": "0", | ||||
|      "fieldname": "booked_fixed_asset", | ||||
|      "fieldtype": "Check", | ||||
|      "label": "Booked Fixed Asset", | ||||
|      "no_copy": 1, | ||||
|      "read_only": 1 | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "column_break_51", | ||||
|      "fieldtype": "Column Break" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "purchase_receipt", | ||||
|      "fieldtype": "Link", | ||||
|      "label": "Purchase Receipt", | ||||
|      "no_copy": 1, | ||||
|      "options": "Purchase Receipt", | ||||
|      "print_hide": 1, | ||||
|      "read_only": 1 | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "purchase_receipt_amount", | ||||
|      "fieldtype": "Currency", | ||||
|      "hidden": 1, | ||||
|      "label": "Purchase Receipt Amount", | ||||
|      "no_copy": 1, | ||||
|      "print_hide": 1, | ||||
|      "read_only": 1 | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "purchase_invoice", | ||||
|      "fieldtype": "Link", | ||||
|      "label": "Purchase Invoice", | ||||
|      "no_copy": 1, | ||||
|      "options": "Purchase Invoice", | ||||
|      "read_only": 1 | ||||
|     }, | ||||
|     { | ||||
|      "fetch_from": "company.default_finance_book", | ||||
|      "fieldname": "default_finance_book", | ||||
|      "fieldtype": "Link", | ||||
|      "hidden": 1, | ||||
|      "label": "Default Finance Book", | ||||
|      "options": "Finance Book", | ||||
|      "read_only": 1 | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "amended_from", | ||||
|      "fieldtype": "Link", | ||||
|      "label": "Amended From", | ||||
|      "no_copy": 1, | ||||
|      "options": "Asset", | ||||
|      "print_hide": 1, | ||||
|      "read_only": 1 | ||||
|     }, | ||||
|     { | ||||
|      "collapsible": 1, | ||||
|      "fieldname": "accounting_dimensions_section", | ||||
|      "fieldtype": "Section Break", | ||||
|      "label": "Accounting Dimensions" | ||||
|     }, | ||||
|     { | ||||
|      "fieldname": "dimension_col_break", | ||||
|      "fieldtype": "Column Break" | ||||
|     } | ||||
|    ], | ||||
|    "idx": 72, | ||||
|    "image_field": "image", | ||||
|    "is_submittable": 1, | ||||
|    "modified": "2019-05-25 22:26:19.786201", | ||||
|    "modified_by": "Administrator", | ||||
|    "module": "Assets", | ||||
|    "name": "Asset", | ||||
|    "owner": "Administrator", | ||||
|    "permissions": [ | ||||
|     { | ||||
|      "amend": 1, | ||||
|      "cancel": 1, | ||||
|      "create": 1, | ||||
|      "delete": 1, | ||||
|      "email": 1, | ||||
|      "export": 1, | ||||
|      "import": 1, | ||||
|      "print": 1, | ||||
|      "read": 1, | ||||
|      "report": 1, | ||||
|      "role": "Accounts User", | ||||
|      "share": 1, | ||||
|      "submit": 1, | ||||
|      "write": 1 | ||||
|     }, | ||||
|     { | ||||
|      "cancel": 1, | ||||
|      "create": 1, | ||||
|      "delete": 1, | ||||
|      "email": 1, | ||||
|      "export": 1, | ||||
|      "print": 1, | ||||
|      "read": 1, | ||||
|      "report": 1, | ||||
|      "role": "Quality Manager", | ||||
|      "share": 1, | ||||
|      "submit": 1, | ||||
|      "write": 1 | ||||
|     } | ||||
|    ], | ||||
|    "show_name_in_global_search": 1, | ||||
|    "sort_field": "modified", | ||||
|    "sort_order": "DESC", | ||||
|    "title_field": "asset_name" | ||||
|   } | ||||
|  ], | ||||
|  "idx": 72, | ||||
|  "image_field": "image", | ||||
|  "is_submittable": 1, | ||||
|  "modified": "2019-05-25 22:26:19.786201", | ||||
|  "modified_by": "Administrator", | ||||
|  "module": "Assets", | ||||
|  "name": "Asset", | ||||
|  "owner": "Administrator", | ||||
|  "permissions": [ | ||||
|   { | ||||
|    "amend": 1, | ||||
|    "cancel": 1, | ||||
|    "create": 1, | ||||
|    "delete": 1, | ||||
|    "email": 1, | ||||
|    "export": 1, | ||||
|    "import": 1, | ||||
|    "print": 1, | ||||
|    "read": 1, | ||||
|    "report": 1, | ||||
|    "role": "Accounts User", | ||||
|    "share": 1, | ||||
|    "submit": 1, | ||||
|    "write": 1 | ||||
|   }, | ||||
|   { | ||||
|    "cancel": 1, | ||||
|    "create": 1, | ||||
|    "delete": 1, | ||||
|    "email": 1, | ||||
|    "export": 1, | ||||
|    "print": 1, | ||||
|    "read": 1, | ||||
|    "report": 1, | ||||
|    "role": "Quality Manager", | ||||
|    "share": 1, | ||||
|    "submit": 1, | ||||
|    "write": 1 | ||||
|   } | ||||
|  ], | ||||
|  "show_name_in_global_search": 1, | ||||
|  "sort_field": "modified", | ||||
|  "sort_order": "DESC", | ||||
|  "title_field": "asset_name" | ||||
| } | ||||
| @ -510,4 +510,3 @@ def update_status(status, name): | ||||
| def make_inter_company_sales_order(source_name, target_doc=None): | ||||
| 	from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_inter_company_transaction | ||||
| 	return make_inter_company_transaction("Purchase Order", source_name, target_doc) | ||||
| 
 | ||||
|  | ||||
| @ -1,31 +1,31 @@ | ||||
| { | ||||
|  "add_total_row": 1, | ||||
|  "creation": "2013-05-13 16:10:02", | ||||
|  "disable_prepared_report": 0, | ||||
|  "disabled": 0, | ||||
|  "docstatus": 0, | ||||
|  "doctype": "Report", | ||||
|  "idx": 3, | ||||
|  "is_standard": "Yes", | ||||
|  "modified": "2019-04-18 19:02:03.099422", | ||||
|  "modified_by": "Administrator", | ||||
|  "module": "Buying", | ||||
|  "name": "Requested Items To Be Ordered", | ||||
|  "owner": "Administrator", | ||||
|  "prepared_report": 0, | ||||
|  "query": "select \n    mr.name as \"Material Request:Link/Material Request:120\",\n\tmr.transaction_date as \"Date:Date:100\",\n\tmr_item.item_code as \"Item Code:Link/Item:120\",\n\tsum(ifnull(mr_item.stock_qty, 0)) as \"Qty:Float:100\",\n\tifnull(mr_item.stock_uom, '') as \"UOM:Link/UOM:100\",\n\tsum(ifnull(mr_item.ordered_qty, 0)) as \"Ordered Qty:Float:100\", \n\t(sum(mr_item.stock_qty) - sum(ifnull(mr_item.ordered_qty, 0))) as \"Qty to Order:Float:100\",\n\tmr_item.item_name as \"Item Name::150\",\n\tmr_item.description as \"Description::200\",\n\tmr.company as \"Company:Link/Company:\"\nfrom\n\t`tabMaterial Request` mr, `tabMaterial Request Item` mr_item\nwhere\n\tmr_item.parent = mr.name\n\tand mr.material_request_type = \"Purchase\"\n\tand mr.docstatus = 1\n\tand mr.status != \"Stopped\"\ngroup by mr.name, mr_item.item_code\nhaving\n\tsum(ifnull(mr_item.ordered_qty, 0)) < sum(ifnull(mr_item.stock_qty, 0))\norder by mr.transaction_date asc", | ||||
|  "ref_doctype": "Purchase Order", | ||||
|  "report_name": "Requested Items To Be Ordered", | ||||
|  "report_type": "Query Report", | ||||
|  "roles": [ | ||||
|   { | ||||
|    "role": "Stock User" | ||||
|   }, | ||||
|   { | ||||
|    "role": "Purchase Manager" | ||||
|   }, | ||||
|   { | ||||
|    "role": "Purchase User" | ||||
|   } | ||||
|  ] | ||||
| } | ||||
|     "add_total_row": 1, | ||||
|     "creation": "2013-05-13 16:10:02", | ||||
|     "disable_prepared_report": 0, | ||||
|     "disabled": 0, | ||||
|     "docstatus": 0, | ||||
|     "doctype": "Report", | ||||
|     "idx": 3, | ||||
|     "is_standard": "Yes", | ||||
|     "modified": "2019-04-18 19:02:03.099422", | ||||
|     "modified_by": "Administrator", | ||||
|     "module": "Buying", | ||||
|     "name": "Requested Items To Be Ordered", | ||||
|     "owner": "Administrator", | ||||
|     "prepared_report": 0, | ||||
|     "query": "select \n    mr.name as \"Material Request:Link/Material Request:120\",\n\tmr.transaction_date as \"Date:Date:100\",\n\tmr_item.item_code as \"Item Code:Link/Item:120\",\n\tsum(ifnull(mr_item.stock_qty, 0)) as \"Qty:Float:100\",\n\tifnull(mr_item.stock_uom, '') as \"UOM:Link/UOM:100\",\n\tsum(ifnull(mr_item.ordered_qty, 0)) as \"Ordered Qty:Float:100\", \n\t(sum(mr_item.stock_qty) - sum(ifnull(mr_item.ordered_qty, 0))) as \"Qty to Order:Float:100\",\n\tmr_item.item_name as \"Item Name::150\",\n\tmr_item.description as \"Description::200\",\n\tmr.company as \"Company:Link/Company:\"\nfrom\n\t`tabMaterial Request` mr, `tabMaterial Request Item` mr_item\nwhere\n\tmr_item.parent = mr.name\n\tand mr.material_request_type = \"Purchase\"\n\tand mr.docstatus = 1\n\tand mr.status != \"Stopped\"\ngroup by mr.name, mr_item.item_code\nhaving\n\tsum(ifnull(mr_item.ordered_qty, 0)) < sum(ifnull(mr_item.stock_qty, 0))\norder by mr.transaction_date asc", | ||||
|     "ref_doctype": "Purchase Order", | ||||
|     "report_name": "Requested Items To Be Ordered", | ||||
|     "report_type": "Query Report", | ||||
|     "roles": [ | ||||
|      { | ||||
|       "role": "Stock User" | ||||
|      }, | ||||
|      { | ||||
|       "role": "Purchase Manager" | ||||
|      }, | ||||
|      { | ||||
|       "role": "Purchase User" | ||||
|      } | ||||
|     ] | ||||
|    } | ||||
| @ -167,7 +167,7 @@ def get_data(): | ||||
| 					"type": "doctype", | ||||
| 					"name": "Opening Invoice Creation Tool", | ||||
| 					"description": _("Create Opening Sales and Purchase Invoices") | ||||
| 				}, | ||||
| 				} | ||||
| 			] | ||||
| 		}, | ||||
| 		{ | ||||
| @ -182,7 +182,7 @@ def get_data(): | ||||
| 					"type": "doctype", | ||||
| 					"name": "Journal Entry", | ||||
| 					"description": _("Accounting journal entries.") | ||||
| 				}, | ||||
| 				} | ||||
| 			] | ||||
| 		}, | ||||
| 		{ | ||||
| @ -246,6 +246,12 @@ def get_data(): | ||||
| 					"label": _("Bank"), | ||||
| 					"name": "Bank", | ||||
| 				}, | ||||
| 				{ | ||||
| 					"type": "page", | ||||
| 					"label": _("Reconcile payments and bank transactions"), | ||||
| 					"name": "bank-reconciliation", | ||||
| 					"description": _("Link bank transactions with payments.") | ||||
| 				}, | ||||
| 				{ | ||||
| 					"type": "doctype", | ||||
| 					"label": _("Bank Account"), | ||||
|  | ||||
| @ -35,6 +35,11 @@ def get_data(): | ||||
| 					"type": "doctype", | ||||
| 					"name": "Amazon MWS Settings", | ||||
| 					"description": _("Connect Amazon with ERPNext"), | ||||
| 				}, | ||||
| 				{ | ||||
| 					"type": "doctype", | ||||
| 					"name": "Plaid Settings", | ||||
| 					"description": _("Connect your bank accounts to ERPNext"), | ||||
| 				} | ||||
| 			] | ||||
| 		} | ||||
|  | ||||
| @ -304,6 +304,12 @@ def get_data(): | ||||
| 					"name": "Customers Without Any Sales Transactions", | ||||
| 					"doctype": "Customer" | ||||
| 				}, | ||||
| 				{ | ||||
| 					"type": "report", | ||||
| 					"is_query_report": True, | ||||
| 					"name": "Sales Partners Commission", | ||||
| 					"doctype": "Customer" | ||||
| 				}, | ||||
| 				{ | ||||
| 					"type": "report", | ||||
| 					"is_query_report": True, | ||||
| @ -312,6 +318,23 @@ def get_data(): | ||||
| 				} | ||||
| 			] | ||||
| 		}, | ||||
| 		{ | ||||
| 			"label": _("SMS"), | ||||
| 			"icon": "fa fa-wrench", | ||||
| 			"items": [ | ||||
| 				{ | ||||
| 					"type": "doctype", | ||||
| 					"name": "SMS Center", | ||||
| 					"description":_("Send mass SMS to your contacts"), | ||||
| 				}, | ||||
| 				{ | ||||
| 					"type": "doctype", | ||||
| 					"name": "SMS Log", | ||||
| 					"description":_("Logs for maintaining sms delivery status"), | ||||
| 				}, | ||||
| 
 | ||||
| 			] | ||||
| 		}, | ||||
| 		{ | ||||
| 			"label": _("Help"), | ||||
| 			"items": [ | ||||
|  | ||||
| @ -32,8 +32,8 @@ class AccountsController(TransactionBase): | ||||
| 		return self.__company_currency | ||||
| 
 | ||||
| 	def onload(self): | ||||
| 		self.get("__onload").make_payment_via_journal_entry \ | ||||
| 			= frappe.db.get_single_value('Accounts Settings', 'make_payment_via_journal_entry') | ||||
| 		self.set_onload("make_payment_via_journal_entry", | ||||
| 			frappe.db.get_single_value('Accounts Settings', 'make_payment_via_journal_entry')) | ||||
| 
 | ||||
| 		if self.is_new(): | ||||
| 			relevant_docs = ("Quotation", "Purchase Order", "Sales Order", | ||||
| @ -242,6 +242,10 @@ class AccountsController(TransactionBase): | ||||
| 				parent_dict.update({"document_type": document_type}) | ||||
| 
 | ||||
| 			self.set('pricing_rules', []) | ||||
| 			# party_name field used for customer in quotation | ||||
| 			if self.doctype == "Quotation" and self.quotation_to == "Customer" and parent_dict.get("party_name"): | ||||
| 				parent_dict.update({"customer": parent_dict.get("party_name")}) | ||||
| 
 | ||||
| 			for item in self.get("items"): | ||||
| 				if item.get("item_code"): | ||||
| 					args = parent_dict.copy() | ||||
| @ -1006,11 +1010,11 @@ def get_advance_journal_entries(party_type, party, party_account, amount_field, | ||||
| 
 | ||||
| 
 | ||||
| def get_advance_payment_entries(party_type, party, party_account, order_doctype, | ||||
| 		order_list=None, include_unallocated=True, against_all_orders=False, limit=1000): | ||||
| 		order_list=None, include_unallocated=True, against_all_orders=False, limit=None): | ||||
| 	party_account_field = "paid_from" if party_type == "Customer" else "paid_to" | ||||
| 	payment_type = "Receive" if party_type == "Customer" else "Pay" | ||||
| 	payment_entries_against_order, unallocated_payment_entries = [], [] | ||||
| 	limit_cond = "limit %s" % (limit or 1000) | ||||
| 	limit_cond = "limit %s" % limit if limit else "" | ||||
| 
 | ||||
| 	if order_list or against_all_orders: | ||||
| 		if order_list: | ||||
|  | ||||
| @ -176,7 +176,7 @@ def enqueue_multiple_variant_creation(item, args): | ||||
| 	for key in variants: | ||||
| 		total_variants *= len(variants[key]) | ||||
| 	if total_variants >= 600: | ||||
| 		frappe.msgprint("Please do not create more than 500 items at a time", raise_exception=1) | ||||
| 		frappe.throw(_("Please do not create more than 500 items at a time")) | ||||
| 		return | ||||
| 	if total_variants < 10: | ||||
| 		return create_multiple_variants(item, args) | ||||
| @ -282,7 +282,7 @@ def copy_attributes_to_variant(item, variant): | ||||
| 
 | ||||
| 	if 'description' not in allow_fields: | ||||
| 		if not variant.description: | ||||
| 			variant.description = "" | ||||
| 				variant.description = "" | ||||
| 
 | ||||
| 		if item.variant_based_on=='Item Attribute': | ||||
| 			if variant.attributes: | ||||
|  | ||||
| @ -205,11 +205,14 @@ def get_already_returned_items(doc): | ||||
| 
 | ||||
| def make_return_doc(doctype, source_name, target_doc=None): | ||||
| 	from frappe.model.mapper import get_mapped_doc | ||||
| 	company = frappe.db.get_value("Delivery Note", source_name, "company") | ||||
| 	default_warehouse_for_sales_return = frappe.db.get_value("Company", company, "default_warehouse_for_sales_return") | ||||
| 	def set_missing_values(source, target): | ||||
| 		doc = frappe.get_doc(target) | ||||
| 		doc.is_return = 1 | ||||
| 		doc.return_against = source.name | ||||
| 		doc.ignore_pricing_rule = 1 | ||||
| 		doc.set_warehouse = "" | ||||
| 		if doctype == "Sales Invoice": | ||||
| 			doc.is_pos = source.is_pos | ||||
| 
 | ||||
| @ -253,7 +256,6 @@ def make_return_doc(doctype, source_name, target_doc=None): | ||||
| 
 | ||||
| 	def update_item(source_doc, target_doc, source_parent): | ||||
| 		target_doc.qty = -1* source_doc.qty | ||||
| 		default_return_warehouse = frappe.db.get_single_value("Stock Settings", "default_return_warehouse") | ||||
| 		if doctype == "Purchase Receipt": | ||||
| 			target_doc.received_qty = -1* source_doc.received_qty | ||||
| 			target_doc.rejected_qty = -1* source_doc.rejected_qty | ||||
| @ -278,13 +280,16 @@ def make_return_doc(doctype, source_name, target_doc=None): | ||||
| 			target_doc.so_detail = source_doc.so_detail | ||||
| 			target_doc.si_detail = source_doc.si_detail | ||||
| 			target_doc.expense_account = source_doc.expense_account | ||||
| 			target_doc.warehouse = default_return_warehouse if default_return_warehouse else source_doc.warehouse | ||||
| 			if default_warehouse_for_sales_return: | ||||
| 				target_doc.warehouse = default_warehouse_for_sales_return | ||||
| 		elif doctype == "Sales Invoice": | ||||
| 			target_doc.sales_order = source_doc.sales_order | ||||
| 			target_doc.delivery_note = source_doc.delivery_note | ||||
| 			target_doc.so_detail = source_doc.so_detail | ||||
| 			target_doc.dn_detail = source_doc.dn_detail | ||||
| 			target_doc.expense_account = source_doc.expense_account | ||||
| 			if default_warehouse_for_sales_return: | ||||
| 				target_doc.warehouse = default_warehouse_for_sales_return | ||||
| 
 | ||||
| 	def update_terms(source_doc, target_doc, source_parent): | ||||
| 		target_doc.payment_amount = -source_doc.payment_amount | ||||
|  | ||||
| @ -55,14 +55,28 @@ class SellingController(StockController): | ||||
| 		self.set_price_list_and_item_details(for_validate=for_validate) | ||||
| 
 | ||||
| 	def set_missing_lead_customer_details(self): | ||||
| 		customer, lead = None, None | ||||
| 		if getattr(self, "customer", None): | ||||
| 			customer = self.customer | ||||
| 		elif self.doctype == "Opportunity" and self.party_name: | ||||
| 			if self.opportunity_from == "Customer": | ||||
| 				customer = self.party_name | ||||
| 			else: | ||||
| 				lead = self.party_name | ||||
| 		elif self.doctype == "Quotation" and self.party_name: | ||||
| 			if self.quotation_to == "Customer": | ||||
| 				customer = self.party_name | ||||
| 			else: | ||||
| 				lead = self.party_name | ||||
| 
 | ||||
| 		if customer: | ||||
| 			from erpnext.accounts.party import _get_party_details | ||||
| 			fetch_payment_terms_template = False | ||||
| 			if (self.get("__islocal") or | ||||
| 				self.company != frappe.db.get_value(self.doctype, self.name, 'company')): | ||||
| 				fetch_payment_terms_template = True | ||||
| 
 | ||||
| 			party_details = _get_party_details(self.customer, | ||||
| 			party_details = _get_party_details(customer, | ||||
| 				ignore_permissions=self.flags.ignore_permissions, | ||||
| 				doctype=self.doctype, company=self.company, | ||||
| 				fetch_payment_terms_template=fetch_payment_terms_template, | ||||
| @ -71,10 +85,9 @@ class SellingController(StockController): | ||||
| 				party_details.pop("sales_team") | ||||
| 			self.update_if_missing(party_details) | ||||
| 
 | ||||
| 		elif getattr(self, "lead", None): | ||||
| 		elif lead: | ||||
| 			from erpnext.crm.doctype.lead.lead import get_lead_details | ||||
| 			self.update_if_missing(get_lead_details( | ||||
| 				self.lead, | ||||
| 			self.update_if_missing(get_lead_details(lead, | ||||
| 				posting_date=self.get('transaction_date') or self.get('posting_date'), | ||||
| 				company=self.company)) | ||||
| 
 | ||||
|  | ||||
| @ -46,9 +46,9 @@ status_map = { | ||||
| 	"Sales Invoice": [ | ||||
| 		["Draft", None], | ||||
| 		["Submitted", "eval:self.docstatus==1"], | ||||
| 		["Paid", "eval:self.outstanding_amount==0 and self.docstatus==1"], | ||||
| 		["Return", "eval:self.is_return==1 and self.docstatus==1"], | ||||
| 		["Paid", "eval:self.outstanding_amount<=0 and self.docstatus==1 and self.is_return==0"], | ||||
| 		["Credit Note Issued", "eval:self.outstanding_amount < 0 and self.docstatus==1 and self.is_return==0 and get_value('Sales Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1})"], | ||||
| 		["Credit Note Issued", "eval:self.outstanding_amount < 0 and self.docstatus==1"], | ||||
| 		["Unpaid", "eval:self.outstanding_amount > 0 and getdate(self.due_date) >= getdate(nowdate()) and self.docstatus==1"], | ||||
| 		["Overdue", "eval:self.outstanding_amount > 0 and getdate(self.due_date) < getdate(nowdate()) and self.docstatus==1"], | ||||
| 		["Cancelled", "eval:self.docstatus==2"], | ||||
| @ -56,9 +56,9 @@ status_map = { | ||||
| 	"Purchase Invoice": [ | ||||
| 		["Draft", None], | ||||
| 		["Submitted", "eval:self.docstatus==1"], | ||||
| 		["Paid", "eval:self.outstanding_amount==0 and self.docstatus==1"], | ||||
| 		["Return", "eval:self.is_return==1 and self.docstatus==1"], | ||||
| 		["Paid", "eval:self.outstanding_amount<=0 and self.docstatus==1 and self.is_return==0"], | ||||
| 		["Debit Note Issued", "eval:self.outstanding_amount < 0 and self.docstatus==1 and self.is_return==0 and get_value('Purchase Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1})"], | ||||
| 		["Debit Note Issued", "eval:self.outstanding_amount < 0 and self.docstatus==1"], | ||||
| 		["Unpaid", "eval:self.outstanding_amount > 0 and getdate(self.due_date) >= getdate(nowdate()) and self.docstatus==1"], | ||||
| 		["Overdue", "eval:self.outstanding_amount > 0 and getdate(self.due_date) < getdate(nowdate()) and self.docstatus==1"], | ||||
| 		["Cancelled", "eval:self.docstatus==2"], | ||||
| @ -99,6 +99,10 @@ status_map = { | ||||
| 		["Issued", "eval:self.status != 'Stopped' and self.per_ordered == 100 and self.docstatus == 1 and self.material_request_type == 'Material Issue'"], | ||||
| 		["Received", "eval:self.status != 'Stopped' and self.per_received == 100 and self.docstatus == 1 and self.material_request_type == 'Purchase'"], | ||||
| 		["Partially Received", "eval:self.status != 'Stopped' and self.per_received > 0 and self.per_received < 100 and self.docstatus == 1 and self.material_request_type == 'Purchase'"] | ||||
| 	], | ||||
| 	"Bank Transaction": [ | ||||
| 		["Unreconciled", "eval:self.docstatus == 1 and self.unallocated_amount>0"], | ||||
| 		["Reconciled", "eval:self.docstatus == 1 and self.unallocated_amount<=0"] | ||||
| 	] | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -128,7 +128,7 @@ class StockController(AccountsController): | ||||
| 			reconciliation_purpose = frappe.db.get_value(self.doctype, self.name, "purpose") | ||||
| 			is_opening = "Yes" if reconciliation_purpose == "Opening Stock" else "No" | ||||
| 			details = [] | ||||
| 			for voucher_detail_no, sle in sle_map.items(): | ||||
| 			for voucher_detail_no in sle_map: | ||||
| 				details.append(frappe._dict({ | ||||
| 					"name": voucher_detail_no, | ||||
| 					"expense_account": default_expense_account, | ||||
| @ -362,10 +362,12 @@ class StockController(AccountsController): | ||||
| 					frappe.throw(_("Row {0}: Quality Inspection rejected for item {1}") | ||||
| 						.format(d.idx, d.item_code), QualityInspectionRejectedError) | ||||
| 			elif qa_required : | ||||
| 				frappe.msgprint(_("Quality Inspection required for Item {0}").format(d.item_code)) | ||||
| 				if self.docstatus==1: | ||||
| 					raise QualityInspectionRequiredError | ||||
| 
 | ||||
| 				action = frappe.get_doc('Stock Settings').action_if_quality_inspection_is_not_submitted | ||||
| 				if self.docstatus==1 and action == 'Stop': | ||||
| 					frappe.throw(_("Quality Inspection required for Item {0} to submit").format(frappe.bold(d.item_code)), | ||||
| 						exc=QualityInspectionRequiredError) | ||||
| 				else: | ||||
| 					frappe.msgprint(_("Create Quality Inspection for Item {0}").format(frappe.bold(d.item_code))) | ||||
| 
 | ||||
| 	def update_blanket_order(self): | ||||
| 		blanket_orders = list(set([d.blanket_order for d in self.items if d.blanket_order])) | ||||
|  | ||||
| @ -616,7 +616,7 @@ def get_itemised_tax_breakup_data(doc): | ||||
| 
 | ||||
| 	return itemised_tax, itemised_taxable_amount | ||||
| 
 | ||||
| def get_itemised_tax(taxes): | ||||
| def get_itemised_tax(taxes, with_tax_account=False): | ||||
| 	itemised_tax = {} | ||||
| 	for tax in taxes: | ||||
| 		if getattr(tax, "category", None) and tax.category=="Valuation": | ||||
| @ -641,6 +641,9 @@ def get_itemised_tax(taxes): | ||||
| 					tax_amount = tax_amount | ||||
| 				)) | ||||
| 
 | ||||
| 				if with_tax_account: | ||||
| 					itemised_tax[item_code][tax.description].tax_account = tax.account_head | ||||
| 
 | ||||
| 	return itemised_tax | ||||
| 
 | ||||
| def get_itemised_taxable_amount(items): | ||||
|  | ||||
| @ -43,7 +43,7 @@ class TestMapper(unittest.TestCase): | ||||
| 		qtn = frappe.get_doc({ | ||||
| 			"doctype": "Quotation", | ||||
| 			"quotation_to": "Customer", | ||||
| 			"customer": customer, | ||||
| 			"party_name": customer, | ||||
| 			"order_type": "Sales", | ||||
| 			"transaction_date" : nowdate(), | ||||
| 			"valid_till" : add_months(nowdate(), 1) | ||||
|  | ||||
| @ -6,6 +6,17 @@ cur_frm.email_field = "email_id"; | ||||
| 
 | ||||
| erpnext.LeadController = frappe.ui.form.Controller.extend({ | ||||
| 	setup: function () { | ||||
| 		this.frm.make_methods = { | ||||
| 			'Quotation': () => erpnext.utils.create_new_doc('Quotation', { | ||||
| 				'quotation_to': this.frm.doc.doctype, | ||||
| 				'party_name': this.frm.doc.name | ||||
| 			}), | ||||
| 			'Opportunity': () => erpnext.utils.create_new_doc('Opportunity', { | ||||
| 				'opportunity_from': this.frm.doc.doctype, | ||||
| 				'party_name': this.frm.doc.name | ||||
| 			}) | ||||
| 		} | ||||
| 
 | ||||
| 		this.frm.fields_dict.customer.get_query = function (doc, cdt, cdn) { | ||||
| 			return { query: "erpnext.controllers.queries.customer_query" } | ||||
| 		} | ||||
|  | ||||
| @ -1430,7 +1430,7 @@ | ||||
|  "issingle": 0, | ||||
|  "istable": 0, | ||||
|  "max_attachments": 0, | ||||
|  "modified": "2019-05-10 03:22:57.283628", | ||||
|  "modified": "2019-06-18 03:22:57.283628", | ||||
|  "modified_by": "Administrator", | ||||
|  "module": "CRM", | ||||
|  "name": "Lead", | ||||
|  | ||||
| @ -90,11 +90,11 @@ class Lead(SellingController): | ||||
| 		return frappe.db.get_value("Customer", {"lead_name": self.name}) | ||||
| 
 | ||||
| 	def has_opportunity(self): | ||||
| 		return frappe.db.get_value("Opportunity", {"lead": self.name, "status": ["!=", "Lost"]}) | ||||
| 		return frappe.db.get_value("Opportunity", {"party_name": self.name, "status": ["!=", "Lost"]}) | ||||
| 
 | ||||
| 	def has_quotation(self): | ||||
| 		return frappe.db.get_value("Quotation", { | ||||
| 			"lead": self.name, | ||||
| 			"party_name": self.name, | ||||
| 			"docstatus": 1, | ||||
| 			"status": ["!=", "Lost"] | ||||
| 
 | ||||
| @ -102,7 +102,7 @@ class Lead(SellingController): | ||||
| 
 | ||||
| 	def has_lost_quotation(self): | ||||
| 		return frappe.db.get_value("Quotation", { | ||||
| 			"lead": self.name, | ||||
| 			"party_name": self.name, | ||||
| 			"docstatus": 1, | ||||
| 			"status": "Lost" | ||||
| 		}) | ||||
| @ -150,8 +150,8 @@ def make_opportunity(source_name, target_doc=None): | ||||
| 			"doctype": "Opportunity", | ||||
| 			"field_map": { | ||||
| 				"campaign_name": "campaign", | ||||
| 				"doctype": "enquiry_from", | ||||
| 				"name": "lead", | ||||
| 				"doctype": "opportunity_from", | ||||
| 				"name": "party_name", | ||||
| 				"lead_name": "contact_display", | ||||
| 				"company_name": "customer_name", | ||||
| 				"email_id": "contact_email", | ||||
| @ -167,7 +167,7 @@ def make_quotation(source_name, target_doc=None): | ||||
| 		{"Lead": { | ||||
| 			"doctype": "Quotation", | ||||
| 			"field_map": { | ||||
| 				"name": "lead" | ||||
| 				"name": "party_name" | ||||
| 			} | ||||
| 		}}, target_doc) | ||||
| 	target_doc.quotation_to = "Lead" | ||||
| @ -190,7 +190,7 @@ def get_lead_details(lead, posting_date=None, company=None): | ||||
| 	out.update({ | ||||
| 		"territory": lead.territory, | ||||
| 		"customer_name": lead.company_name or lead.lead_name, | ||||
| 		"contact_display": lead.lead_name, | ||||
| 		"contact_display": " ".join(filter(None, [lead.salutation, lead.lead_name])), | ||||
| 		"contact_email": lead.email_id, | ||||
| 		"contact_mobile": lead.mobile_no, | ||||
| 		"contact_phone": lead.phone, | ||||
|  | ||||
| @ -4,6 +4,13 @@ from frappe import _ | ||||
| def get_data(): | ||||
| 	return { | ||||
| 		'fieldname': 'lead', | ||||
| 		'non_standard_fieldnames': { | ||||
| 			'Quotation': 'party_name', | ||||
| 			'Opportunity': 'party_name' | ||||
| 		}, | ||||
| 		'dynamic_links': { | ||||
| 			'party_name': ['Lead', 'quotation_to'] | ||||
| 		}, | ||||
| 		'transactions': [ | ||||
| 			{ | ||||
| 				'items': ['Opportunity', 'Quotation'] | ||||
|  | ||||
| @ -10,15 +10,34 @@ frappe.ui.form.on("Opportunity", { | ||||
| 		frm.custom_make_buttons = { | ||||
| 			'Quotation': 'Quotation', | ||||
| 			'Supplier Quotation': 'Supplier Quotation' | ||||
| 		} | ||||
| 	}, | ||||
| 	customer: function(frm) { | ||||
| 		frm.trigger('set_contact_link'); | ||||
| 		erpnext.utils.get_party_details(frm); | ||||
| 		}, | ||||
| 
 | ||||
| 		frm.set_query("opportunity_from", function() { | ||||
| 			return{ | ||||
| 				"filters": { | ||||
| 					"name": ["in", ["Customer", "Lead"]], | ||||
| 				} | ||||
| 			} | ||||
| 		}); | ||||
| 	}, | ||||
| 
 | ||||
| 	lead: function(frm) { | ||||
| 		frm.trigger('set_contact_link'); | ||||
| 	onload_post_render: function(frm) { | ||||
| 		frm.get_field("items").grid.set_multiple_add("item_code", "qty"); | ||||
| 	}, | ||||
| 
 | ||||
| 	party_name: function(frm) { | ||||
| 		frm.toggle_display("contact_info", frm.doc.party_name); | ||||
| 
 | ||||
| 		if (frm.doc.opportunity_from == "Customer") { | ||||
| 			frm.trigger('set_contact_link'); | ||||
| 			erpnext.utils.get_party_details(frm); | ||||
| 		} else if (frm.doc.opportunity_from == "Lead") { | ||||
| 			erpnext.utils.map_current_doc({ | ||||
| 				method: "erpnext.crm.doctype.lead.lead.make_opportunity", | ||||
| 				source_name: frm.doc.party_name, | ||||
| 				frm: frm | ||||
| 			}); | ||||
| 		} | ||||
| 	}, | ||||
| 
 | ||||
| 	onload_post_render: function(frm) { | ||||
| @ -42,15 +61,14 @@ frappe.ui.form.on("Opportunity", { | ||||
| 
 | ||||
| 	contact_person: erpnext.utils.get_contact_details, | ||||
| 
 | ||||
| 	enquiry_from: function(frm) { | ||||
| 		frm.toggle_reqd("lead", frm.doc.enquiry_from==="Lead"); | ||||
| 		frm.toggle_reqd("customer", frm.doc.enquiry_from==="Customer"); | ||||
| 	opportunity_from: function(frm) { | ||||
| 		frm.toggle_reqd("party_name", frm.doc.opportunity_from); | ||||
| 		frm.trigger("set_dynamic_field_label"); | ||||
| 	}, | ||||
| 
 | ||||
| 	refresh: function(frm) { | ||||
| 		var doc = frm.doc; | ||||
| 		frm.events.enquiry_from(frm); | ||||
| 		frm.trigger('set_contact_link'); | ||||
| 		frm.events.opportunity_from(frm); | ||||
| 		frm.trigger('toggle_mandatory'); | ||||
| 		erpnext.toggle_naming_series(); | ||||
| 
 | ||||
| @ -88,10 +106,17 @@ frappe.ui.form.on("Opportunity", { | ||||
| 	}, | ||||
| 
 | ||||
| 	set_contact_link: function(frm) { | ||||
| 		if(frm.doc.customer) { | ||||
| 			frappe.dynamic_link = {doc: frm.doc, fieldname: 'customer', doctype: 'Customer'} | ||||
| 		} else if(frm.doc.lead) { | ||||
| 			frappe.dynamic_link = {doc: frm.doc, fieldname: 'lead', doctype: 'Lead'} | ||||
| 		if(frm.doc.opportunity_from == "Customer" && frm.doc.party_name) { | ||||
| 			frappe.dynamic_link = {doc: frm.doc, fieldname: 'party_name', doctype: 'Customer'} | ||||
| 		} else if(frm.doc.opportunity_from == "Lead" && frm.doc.party_name) { | ||||
| 			frappe.dynamic_link = {doc: frm.doc, fieldname: 'party_name', doctype: 'Lead'} | ||||
| 		} | ||||
| 	}, | ||||
| 
 | ||||
| 	set_dynamic_field_label: function(frm){ | ||||
| 
 | ||||
| 		if (frm.doc.opportunity_from) { | ||||
| 			frm.set_df_property("party_name", "label", frm.doc.opportunity_from); | ||||
| 		} | ||||
| 	}, | ||||
| 
 | ||||
| @ -110,10 +135,6 @@ frappe.ui.form.on("Opportunity", { | ||||
| // TODO commonify this code
 | ||||
| erpnext.crm.Opportunity = frappe.ui.form.Controller.extend({ | ||||
| 	onload: function() { | ||||
| 		if(!this.frm.doc.enquiry_from && this.frm.doc.customer) | ||||
| 			this.frm.doc.enquiry_from = "Customer"; | ||||
| 		if(!this.frm.doc.enquiry_from && this.frm.doc.lead) | ||||
| 			this.frm.doc.enquiry_from = "Lead"; | ||||
| 
 | ||||
| 		if(!this.frm.doc.status) { | ||||
| 			frm.set_value('status', 'Open'); | ||||
| @ -144,12 +165,14 @@ erpnext.crm.Opportunity = frappe.ui.form.Controller.extend({ | ||||
| 			}; | ||||
| 		}); | ||||
| 
 | ||||
| 		$.each([["lead", "lead"], | ||||
| 			["customer", "customer"], | ||||
| 			["contact_person", "contact_query"]], | ||||
| 			function(i, opts) { | ||||
| 				me.frm.set_query(opts[0], erpnext.queries[opts[1]]); | ||||
| 			}); | ||||
| 		me.frm.set_query('contact_person', erpnext.queries['contact_query']) | ||||
| 
 | ||||
| 		if (me.frm.doc.opportunity_from == "Lead") { | ||||
| 			me.frm.set_query('party_name', erpnext.queries['lead']); | ||||
| 		} | ||||
| 		else if (me.frm.doc.opportunity_from == "Cuatomer") { | ||||
| 			me.frm.set_query('party_name', erpnext.queries['customer']); | ||||
| 		} | ||||
| 	}, | ||||
| 
 | ||||
| 	create_quotation: function() { | ||||
| @ -162,11 +185,6 @@ erpnext.crm.Opportunity = frappe.ui.form.Controller.extend({ | ||||
| 
 | ||||
| $.extend(cur_frm.cscript, new erpnext.crm.Opportunity({frm: cur_frm})); | ||||
| 
 | ||||
| cur_frm.cscript.onload_post_render = function(doc, cdt, cdn) { | ||||
| 	if(doc.enquiry_from == 'Lead' && doc.lead) | ||||
| 		cur_frm.cscript.lead(doc, cdt, cdn); | ||||
| } | ||||
| 
 | ||||
| cur_frm.cscript.item_code = function(doc, cdt, cdn) { | ||||
| 	var d = locals[cdt][cdn]; | ||||
| 	if (d.item_code) { | ||||
| @ -184,12 +202,3 @@ cur_frm.cscript.item_code = function(doc, cdt, cdn) { | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| cur_frm.cscript.lead = function(doc, cdt, cdn) { | ||||
| 	cur_frm.toggle_display("contact_info", doc.customer || doc.lead); | ||||
| 	erpnext.utils.map_current_doc({ | ||||
| 		method: "erpnext.crm.doctype.lead.lead.make_opportunity", | ||||
| 		source_name: cur_frm.doc.lead, | ||||
| 		frm: cur_frm | ||||
| 	}); | ||||
| } | ||||
|  | ||||
| @ -21,6 +21,7 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "from_section", | ||||
|    "fieldtype": "Section Break", | ||||
|    "hidden": 0, | ||||
| @ -54,6 +55,7 @@ | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "default": "", | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "naming_series", | ||||
|    "fieldtype": "Select", | ||||
|    "hidden": 0, | ||||
| @ -88,21 +90,22 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fieldname": "enquiry_from",  | ||||
|    "fieldtype": "Select",  | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "opportunity_from", | ||||
|    "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,  | ||||
|    "in_standard_filter": 1, | ||||
|    "label": "Opportunity From", | ||||
|    "length": 0, | ||||
|    "no_copy": 0, | ||||
|    "oldfieldname": "enquiry_from", | ||||
|    "oldfieldtype": "Select", | ||||
|    "options": "\nLead\nCustomer",  | ||||
|    "options": "DocType", | ||||
|    "permlevel": 0, | ||||
|    "print_hide": 1, | ||||
|    "print_hide_if_no_value": 0, | ||||
| @ -122,9 +125,10 @@ | ||||
|    "bold": 1, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "depends_on": "eval:doc.enquiry_from===\"Customer\"",  | ||||
|    "fieldname": "customer",  | ||||
|    "fieldtype": "Link",  | ||||
|    "depends_on": "", | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "party_name", | ||||
|    "fieldtype": "Dynamic Link", | ||||
|    "hidden": 0, | ||||
|    "ignore_user_permissions": 0, | ||||
|    "ignore_xss_filter": 0, | ||||
| @ -132,54 +136,19 @@ | ||||
|    "in_global_search": 0, | ||||
|    "in_list_view": 0, | ||||
|    "in_standard_filter": 1, | ||||
|    "label": "Customer",  | ||||
|    "label": "Party", | ||||
|    "length": 0, | ||||
|    "no_copy": 0, | ||||
|    "oldfieldname": "customer", | ||||
|    "oldfieldtype": "Link", | ||||
|    "options": "Customer",  | ||||
|    "options": "opportunity_from", | ||||
|    "permlevel": 0, | ||||
|    "print_hide": 1, | ||||
|    "print_hide_if_no_value": 0, | ||||
|    "read_only": 0, | ||||
|    "remember_last_selected_value": 0, | ||||
|    "report_hide": 0, | ||||
|    "reqd": 0,  | ||||
|    "search_index": 0,  | ||||
|    "set_only_once": 0,  | ||||
|    "translatable": 0,  | ||||
|    "unique": 0 | ||||
|   },  | ||||
|   { | ||||
|    "allow_bulk_edit": 0,  | ||||
|    "allow_in_quick_entry": 0,  | ||||
|    "allow_on_submit": 0,  | ||||
|    "bold": 1,  | ||||
|    "collapsible": 0,  | ||||
|    "columns": 0,  | ||||
|    "depends_on": "eval:doc.enquiry_from===\"Lead\"",  | ||||
|    "fieldname": "lead",  | ||||
|    "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": 1,  | ||||
|    "label": "Lead",  | ||||
|    "length": 0,  | ||||
|    "no_copy": 0,  | ||||
|    "oldfieldname": "lead",  | ||||
|    "oldfieldtype": "Link",  | ||||
|    "options": "Lead",  | ||||
|    "permlevel": 0,  | ||||
|    "print_hide": 1,  | ||||
|    "print_hide_if_no_value": 0,  | ||||
|    "read_only": 0,  | ||||
|    "remember_last_selected_value": 0,  | ||||
|    "report_hide": 0,  | ||||
|    "reqd": 0,  | ||||
|    "reqd": 1, | ||||
|    "search_index": 0, | ||||
|    "set_only_once": 0, | ||||
|    "translatable": 0, | ||||
| @ -193,6 +162,8 @@ | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "depends_on": "", | ||||
|    "fetch_from": "", | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "customer_name", | ||||
|    "fieldtype": "Data", | ||||
|    "hidden": 0, | ||||
| @ -224,6 +195,7 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "column_break0", | ||||
|    "fieldtype": "Column Break", | ||||
|    "hidden": 0, | ||||
| @ -256,6 +228,7 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "title", | ||||
|    "fieldtype": "Data", | ||||
|    "hidden": 1, | ||||
| @ -289,6 +262,7 @@ | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "default": "Sales", | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "opportunity_type", | ||||
|    "fieldtype": "Link", | ||||
|    "hidden": 0, | ||||
| @ -324,6 +298,7 @@ | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "default": "Open", | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "status", | ||||
|    "fieldtype": "Select", | ||||
|    "hidden": 0, | ||||
| @ -351,6 +326,39 @@ | ||||
|    "translatable": 0, | ||||
|    "unique": 0 | ||||
|   }, | ||||
|   { | ||||
|    "allow_bulk_edit": 0, | ||||
|    "allow_in_quick_entry": 0, | ||||
|    "allow_on_submit": 0, | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "depends_on": "eval:doc.status===\"Lost\"", | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "order_lost_reason", | ||||
|    "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": "Lost Reason", | ||||
|    "length": 0, | ||||
|    "no_copy": 1, | ||||
|    "permlevel": 0, | ||||
|    "print_hide": 0, | ||||
|    "print_hide_if_no_value": 0, | ||||
|    "read_only": 1, | ||||
|    "remember_last_selected_value": 0, | ||||
|    "report_hide": 0, | ||||
|    "reqd": 0, | ||||
|    "search_index": 0, | ||||
|    "set_only_once": 0, | ||||
|    "translatable": 0, | ||||
|    "unique": 0 | ||||
|   }, | ||||
|   { | ||||
|    "allow_bulk_edit": 0, | ||||
|    "allow_in_quick_entry": 0, | ||||
| @ -358,6 +366,7 @@ | ||||
|    "bold": 1, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "mins_to_first_response", | ||||
|    "fieldtype": "Float", | ||||
|    "hidden": 0, | ||||
| @ -391,6 +400,7 @@ | ||||
|    "collapsible": 1, | ||||
|    "collapsible_depends_on": "contact_by", | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "next_contact", | ||||
|    "fieldtype": "Section Break", | ||||
|    "hidden": 0, | ||||
| @ -424,6 +434,7 @@ | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "description": "", | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "contact_by", | ||||
|    "fieldtype": "Link", | ||||
|    "hidden": 0, | ||||
| @ -460,6 +471,7 @@ | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "description": "", | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "contact_date", | ||||
|    "fieldtype": "Datetime", | ||||
|    "hidden": 0, | ||||
| @ -493,6 +505,7 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "column_break2", | ||||
|    "fieldtype": "Column Break", | ||||
|    "hidden": 0, | ||||
| @ -525,6 +538,7 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "to_discuss", | ||||
|    "fieldtype": "Small Text", | ||||
|    "hidden": 0, | ||||
| @ -558,6 +572,7 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "section_break_14", | ||||
|    "fieldtype": "Section Break", | ||||
|    "hidden": 0, | ||||
| @ -590,6 +605,7 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "currency", | ||||
|    "fieldtype": "Link", | ||||
|    "hidden": 0, | ||||
| @ -623,6 +639,7 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "opportunity_amount", | ||||
|    "fieldtype": "Currency", | ||||
|    "hidden": 0, | ||||
| @ -655,6 +672,7 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "with_items", | ||||
|    "fieldtype": "Check", | ||||
|    "hidden": 0, | ||||
| @ -687,6 +705,7 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "column_break_17", | ||||
|    "fieldtype": "Column Break", | ||||
|    "hidden": 0, | ||||
| @ -719,6 +738,7 @@ | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "default": "Prospecting", | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "sales_stage", | ||||
|    "fieldtype": "Link", | ||||
|    "hidden": 0, | ||||
| @ -753,6 +773,7 @@ | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "default": "100", | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "probability", | ||||
|    "fieldtype": "Percent", | ||||
|    "hidden": 0, | ||||
| @ -786,6 +807,7 @@ | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "depends_on": "with_items", | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "items_section", | ||||
|    "fieldtype": "Section Break", | ||||
|    "hidden": 0, | ||||
| @ -820,6 +842,7 @@ | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "description": "", | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "items", | ||||
|    "fieldtype": "Table", | ||||
|    "hidden": 0, | ||||
| @ -855,7 +878,8 @@ | ||||
|    "collapsible": 1, | ||||
|    "collapsible_depends_on": "next_contact_by", | ||||
|    "columns": 0, | ||||
|    "depends_on": "eval:doc.lead || doc.customer",  | ||||
|    "depends_on": "eval:doc.party_name", | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "contact_info", | ||||
|    "fieldtype": "Section Break", | ||||
|    "hidden": 0, | ||||
| @ -888,7 +912,8 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "depends_on": "eval:doc.customer || doc.lead",  | ||||
|    "depends_on": "eval:doc.party_name", | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "customer_address", | ||||
|    "fieldtype": "Link", | ||||
|    "hidden": 0, | ||||
| @ -921,6 +946,7 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "address_display", | ||||
|    "fieldtype": "Small Text", | ||||
|    "hidden": 1, | ||||
| @ -954,8 +980,9 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "depends_on": "customer",  | ||||
|    "depends_on": "eval:", | ||||
|    "description": "", | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "territory", | ||||
|    "fieldtype": "Link", | ||||
|    "hidden": 0, | ||||
| @ -988,8 +1015,9 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "depends_on": "customer",  | ||||
|    "depends_on": "eval:doc.opportunity_from=='Customer' && doc.party_name", | ||||
|    "description": "", | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "customer_group", | ||||
|    "fieldtype": "Link", | ||||
|    "hidden": 0, | ||||
| @ -1024,6 +1052,7 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "column_break3", | ||||
|    "fieldtype": "Column Break", | ||||
|    "hidden": 0, | ||||
| @ -1054,7 +1083,8 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "depends_on": "eval:doc.lead || doc.customer",  | ||||
|    "depends_on": "eval:doc.party_name", | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "contact_person", | ||||
|    "fieldtype": "Link", | ||||
|    "hidden": 0, | ||||
| @ -1087,7 +1117,8 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "depends_on": "customer",  | ||||
|    "depends_on": "eval:doc.opportunity_from=='Customer' && doc.party_name", | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "contact_display", | ||||
|    "fieldtype": "Small Text", | ||||
|    "hidden": 0, | ||||
| @ -1119,7 +1150,8 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "depends_on": "eval:doc.lead || doc.customer",  | ||||
|    "depends_on": "eval:doc.party_name", | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "contact_email", | ||||
|    "fieldtype": "Data", | ||||
|    "hidden": 0, | ||||
| @ -1151,7 +1183,8 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "depends_on": "eval:doc.lead || doc.customer",  | ||||
|    "depends_on": "eval:doc.party_name", | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "contact_mobile", | ||||
|    "fieldtype": "Small Text", | ||||
|    "hidden": 0, | ||||
| @ -1184,6 +1217,7 @@ | ||||
|    "collapsible": 1, | ||||
|    "collapsible_depends_on": "", | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "more_info", | ||||
|    "fieldtype": "Section Break", | ||||
|    "hidden": 0, | ||||
| @ -1217,6 +1251,7 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "source", | ||||
|    "fieldtype": "Link", | ||||
|    "hidden": 0, | ||||
| @ -1253,6 +1288,7 @@ | ||||
|    "columns": 0, | ||||
|    "depends_on": "eval: doc.source==\"Campaign\"", | ||||
|    "description": "Enter name of campaign if source of enquiry is campaign", | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "campaign", | ||||
|    "fieldtype": "Link", | ||||
|    "hidden": 0, | ||||
| @ -1287,38 +1323,7 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "depends_on": "eval:doc.status===\"Lost\"",  | ||||
|    "fieldname": "order_lost_reason",  | ||||
|    "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": "Detailed Reason",  | ||||
|    "length": 0,  | ||||
|    "no_copy": 1,  | ||||
|    "permlevel": 0,  | ||||
|    "print_hide": 0,  | ||||
|    "print_hide_if_no_value": 0,  | ||||
|    "read_only": 1,  | ||||
|    "remember_last_selected_value": 0,  | ||||
|    "report_hide": 0,  | ||||
|    "reqd": 0,  | ||||
|    "search_index": 0,  | ||||
|    "set_only_once": 0,  | ||||
|    "translatable": 0,  | ||||
|    "unique": 0 | ||||
|   },  | ||||
|   { | ||||
|    "allow_bulk_edit": 0,  | ||||
|    "allow_in_quick_entry": 0,  | ||||
|    "allow_on_submit": 0,  | ||||
|    "bold": 0,  | ||||
|    "collapsible": 0,  | ||||
|    "columns": 0,  | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "column_break1", | ||||
|    "fieldtype": "Column Break", | ||||
|    "hidden": 0, | ||||
| @ -1351,6 +1356,7 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "company", | ||||
|    "fieldtype": "Link", | ||||
|    "hidden": 0, | ||||
| @ -1386,6 +1392,7 @@ | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "default": "Today", | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "transaction_date", | ||||
|    "fieldtype": "Date", | ||||
|    "hidden": 0, | ||||
| @ -1420,6 +1427,7 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "amended_from", | ||||
|    "fieldtype": "Link", | ||||
|    "hidden": 0, | ||||
| @ -1493,7 +1501,7 @@ | ||||
|  "issingle": 0, | ||||
|  "istable": 0, | ||||
|  "max_attachments": 0, | ||||
|  "modified": "2018-12-29 18:38:37.270217",  | ||||
|  "modified": "2019-06-19 19:03:32.740910", | ||||
|  "modified_by": "Administrator", | ||||
|  "module": "CRM", | ||||
|  "name": "Opportunity", | ||||
| @ -1541,11 +1549,11 @@ | ||||
|  "quick_entry": 0, | ||||
|  "read_only": 0, | ||||
|  "read_only_onload": 0, | ||||
|  "search_fields": "status,transaction_date,customer,lead,opportunity_type,territory,company",  | ||||
|  "search_fields": "status,transaction_date,party_name,opportunity_type,territory,company", | ||||
|  "show_name_in_global_search": 1, | ||||
|  "sort_field": "modified", | ||||
|  "sort_order": "DESC", | ||||
|  "timeline_field": "customer",  | ||||
|  "timeline_field": "party_name", | ||||
|  "title_field": "title", | ||||
|  "track_changes": 0, | ||||
|  "track_seen": 1, | ||||
|  | ||||
| @ -16,8 +16,8 @@ sender_field = "contact_email" | ||||
| 
 | ||||
| class Opportunity(TransactionBase): | ||||
| 	def after_insert(self): | ||||
| 		if self.lead: | ||||
| 			frappe.get_doc("Lead", self.lead).set_status(update=True) | ||||
| 		if self.opportunity_from == "Lead": | ||||
| 			frappe.get_doc("Lead", self.party_name).set_status(update=True) | ||||
| 
 | ||||
| 	def validate(self): | ||||
| 		self._prev = frappe._dict({ | ||||
| @ -29,12 +29,8 @@ class Opportunity(TransactionBase): | ||||
| 
 | ||||
| 		self.make_new_lead_if_required() | ||||
| 
 | ||||
| 		if not self.enquiry_from: | ||||
| 			frappe.throw(_("Opportunity From field is mandatory")) | ||||
| 
 | ||||
| 		self.validate_item_details() | ||||
| 		self.validate_uom_is_integer("uom", "qty") | ||||
| 		self.validate_lead_cust() | ||||
| 		self.validate_cust_name() | ||||
| 
 | ||||
| 		if not self.title: | ||||
| @ -45,7 +41,7 @@ class Opportunity(TransactionBase): | ||||
| 
 | ||||
| 	def make_new_lead_if_required(self): | ||||
| 		"""Set lead against new opportunity""" | ||||
| 		if not (self.lead or self.customer) and self.contact_email: | ||||
| 		if (not self.get("party_name")) and self.contact_email: | ||||
| 			# check if customer is already created agains the self.contact_email | ||||
| 			customer = frappe.db.sql("""select | ||||
| 				distinct `tabDynamic Link`.link_name as customer | ||||
| @ -61,8 +57,8 @@ class Opportunity(TransactionBase): | ||||
| 					`tabDynamic Link`.link_doctype='Customer' | ||||
| 			""".format(self.contact_email), as_dict=True) | ||||
| 			if customer and customer[0].customer: | ||||
| 				self.customer = customer[0].customer | ||||
| 				self.enquiry_from = "Customer" | ||||
| 				self.party_name = customer[0].customer | ||||
| 				self.opportunity_from = "Customer" | ||||
| 				return | ||||
| 
 | ||||
| 			lead_name = frappe.db.get_value("Lead", {"email_id": self.contact_email}) | ||||
| @ -89,8 +85,8 @@ class Opportunity(TransactionBase): | ||||
| 				lead.insert(ignore_permissions=True) | ||||
| 				lead_name = lead.name | ||||
| 
 | ||||
| 			self.enquiry_from = "Lead" | ||||
| 			self.lead = lead_name | ||||
| 			self.opportunity_from = "Lead" | ||||
| 			self.party_name = lead_name | ||||
| 
 | ||||
| 	def declare_enquiry_lost(self, lost_reasons_list, detailed_reason=None): | ||||
| 		if not self.has_active_quotation(): | ||||
| @ -145,10 +141,10 @@ class Opportunity(TransactionBase): | ||||
| 			return True | ||||
| 
 | ||||
| 	def validate_cust_name(self): | ||||
| 		if self.customer: | ||||
| 			self.customer_name = frappe.db.get_value("Customer", self.customer, "customer_name") | ||||
| 		elif self.lead: | ||||
| 			lead_name, company_name = frappe.db.get_value("Lead", self.lead, ["lead_name", "company_name"]) | ||||
| 		if self.party_name and self.opportunity_from == 'Customer': | ||||
| 			self.customer_name = frappe.db.get_value("Customer", self.party_name, "customer_name") | ||||
| 		elif self.party_name and self.opportunity_from == 'Lead': | ||||
| 			lead_name, company_name = frappe.db.get_value("Lead", self.party_name, ["lead_name", "company_name"]) | ||||
| 			self.customer_name = company_name or lead_name | ||||
| 
 | ||||
| 	def on_update(self): | ||||
| @ -161,16 +157,16 @@ class Opportunity(TransactionBase): | ||||
| 		opts.description = "" | ||||
| 		opts.contact_date = self.contact_date | ||||
| 
 | ||||
| 		if self.customer: | ||||
| 		if self.party_name and self.opportunity_from == 'Customer': | ||||
| 			if self.contact_person: | ||||
| 				opts.description = 'Contact '+cstr(self.contact_person) | ||||
| 			else: | ||||
| 				opts.description = 'Contact customer '+cstr(self.customer) | ||||
| 		elif self.lead: | ||||
| 				opts.description = 'Contact customer '+cstr(self.party_name) | ||||
| 		elif self.party_name and self.opportunity_from == 'Lead': | ||||
| 			if self.contact_display: | ||||
| 				opts.description = 'Contact '+cstr(self.contact_display) | ||||
| 			else: | ||||
| 				opts.description = 'Contact lead '+cstr(self.lead) | ||||
| 				opts.description = 'Contact lead '+cstr(self.party_name) | ||||
| 
 | ||||
| 		opts.subject = opts.description | ||||
| 		opts.description += '. By : ' + cstr(self.contact_by) | ||||
| @ -195,17 +191,6 @@ class Opportunity(TransactionBase): | ||||
| 			for key in item_fields: | ||||
| 				if not d.get(key): d.set(key, item.get(key)) | ||||
| 
 | ||||
| 	def validate_lead_cust(self): | ||||
| 		if self.enquiry_from == 'Lead': | ||||
| 			if not self.lead: | ||||
| 				frappe.throw(_("Lead must be set if Opportunity is made from Lead")) | ||||
| 			else: | ||||
| 				self.customer = None | ||||
| 		elif self.enquiry_from == 'Customer': | ||||
| 			if not self.customer: | ||||
| 				msgprint(_("Customer is mandatory if 'Opportunity From' is selected as Customer"), raise_exception=1) | ||||
| 			else: | ||||
| 				self.lead = None | ||||
| 
 | ||||
| @frappe.whitelist() | ||||
| def get_item_details(item_code): | ||||
| @ -227,8 +212,11 @@ def make_quotation(source_name, target_doc=None): | ||||
| 		quotation = frappe.get_doc(target) | ||||
| 
 | ||||
| 		company_currency = frappe.get_cached_value('Company',  quotation.company,  "default_currency") | ||||
| 		party_account_currency = get_party_account_currency("Customer", quotation.customer, | ||||
| 			quotation.company) if quotation.customer else company_currency | ||||
| 
 | ||||
| 		if quotation.quotation_to == 'Customer' and quotation.party_name: | ||||
| 			party_account_currency = get_party_account_currency("Customer", quotation.party_name, quotation.company) | ||||
| 		else: | ||||
| 			party_account_currency = company_currency | ||||
| 
 | ||||
| 		quotation.currency = party_account_currency or company_currency | ||||
| 
 | ||||
| @ -254,7 +242,7 @@ def make_quotation(source_name, target_doc=None): | ||||
| 		"Opportunity": { | ||||
| 			"doctype": "Quotation", | ||||
| 			"field_map": { | ||||
| 				"enquiry_from": "quotation_to", | ||||
| 				"opportunity_from": "quotation_to", | ||||
| 				"opportunity_type": "order_type", | ||||
| 				"name": "enq_no", | ||||
| 			} | ||||
| @ -340,11 +328,11 @@ def make_opportunity_from_communication(communication, ignore_communication_link | ||||
| 	if not lead: | ||||
| 		lead = make_lead_from_communication(communication, ignore_communication_links=True) | ||||
| 
 | ||||
| 	enquiry_from = "Lead" | ||||
| 	opportunity_from = "Lead" | ||||
| 
 | ||||
| 	opportunity = frappe.get_doc({ | ||||
| 		"doctype": "Opportunity", | ||||
| 		"enquiry_from": enquiry_from, | ||||
| 		"opportunity_from": opportunity_from, | ||||
| 		"lead": lead | ||||
| 	}).insert(ignore_permissions=True) | ||||
| 
 | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| frappe.listview_settings['Opportunity'] = { | ||||
| 	add_fields: ["customer_name", "opportunity_type", "enquiry_from", "status"], | ||||
| 	add_fields: ["customer_name", "opportunity_type", "opportunity_from", "status"], | ||||
| 	get_indicator: function(doc) { | ||||
| 		var indicator = [__(doc.status), frappe.utils.guess_colour(doc.status), "status,=," + doc.status]; | ||||
| 		if(doc.status=="Quotation") { | ||||
| @ -17,5 +17,13 @@ frappe.listview_settings['Opportunity'] = { | ||||
| 		listview.page.add_menu_item(__("Set as Closed"), function() { | ||||
| 			listview.call_for_selected_items(method, {"status": "Closed"}); | ||||
| 		}); | ||||
| 
 | ||||
| 		listview.page.fields_dict.opportunity_from.get_query = function() { | ||||
| 			return { | ||||
| 				"filters": { | ||||
| 					"name": ["in", ["Customer", "Lead"]], | ||||
| 				} | ||||
| 			}; | ||||
| 		}; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| @ -6,7 +6,7 @@ QUnit.test("test: opportunity", function (assert) { | ||||
| 		() => frappe.timeout(1), | ||||
| 		() => frappe.click_button('New'), | ||||
| 		() => frappe.timeout(1), | ||||
| 		() => cur_frm.set_value('enquiry_from', 'Customer'), | ||||
| 		() => cur_frm.set_value('opportunity_from', 'Customer'), | ||||
| 		() => cur_frm.set_value('customer', 'Test Customer 1'), | ||||
| 
 | ||||
| 		// check items
 | ||||
|  | ||||
| @ -38,13 +38,13 @@ class TestOpportunity(unittest.TestCase): | ||||
| 		# new lead should be created against the new.opportunity@example.com | ||||
| 		opp_doc = frappe.get_doc(args).insert(ignore_permissions=True) | ||||
| 
 | ||||
| 		self.assertTrue(opp_doc.lead) | ||||
| 		self.assertEqual(opp_doc.enquiry_from, "Lead") | ||||
| 		self.assertEqual(frappe.db.get_value("Lead", opp_doc.lead, "email_id"), | ||||
| 		self.assertTrue(opp_doc.party_name) | ||||
| 		self.assertEqual(opp_doc.opportunity_from, "Lead") | ||||
| 		self.assertEqual(frappe.db.get_value("Lead", opp_doc.party_name, "email_id"), | ||||
| 			new_lead_email_id) | ||||
| 
 | ||||
| 		# create new customer and create new contact against 'new.opportunity@example.com' | ||||
| 		customer = make_customer(opp_doc.lead).insert(ignore_permissions=True) | ||||
| 		customer = make_customer(opp_doc.party_name).insert(ignore_permissions=True) | ||||
| 		frappe.get_doc({ | ||||
| 			"doctype": "Contact", | ||||
| 			"email_id": new_lead_email_id, | ||||
| @ -56,10 +56,9 @@ class TestOpportunity(unittest.TestCase): | ||||
| 		}).insert(ignore_permissions=True) | ||||
| 
 | ||||
| 		opp_doc = frappe.get_doc(args).insert(ignore_permissions=True) | ||||
| 		self.assertTrue(opp_doc.customer) | ||||
| 		self.assertEqual(opp_doc.enquiry_from, "Customer") | ||||
| 		self.assertEqual(opp_doc.customer, customer.name) | ||||
| 
 | ||||
| 		self.assertTrue(opp_doc.party_name) | ||||
| 		self.assertEqual(opp_doc.opportunity_from, "Customer") | ||||
| 		self.assertEqual(opp_doc.party_name, customer.name) | ||||
| 
 | ||||
| def make_opportunity(**args): | ||||
| 	args = frappe._dict(args) | ||||
| @ -67,17 +66,17 @@ def make_opportunity(**args): | ||||
| 	opp_doc = frappe.get_doc({ | ||||
| 		"doctype": "Opportunity", | ||||
| 		"company": args.company or "_Test Company", | ||||
| 		"enquiry_from": args.enquiry_from or "Customer", | ||||
| 		"opportunity_from": args.opportunity_from or "Customer", | ||||
| 		"opportunity_type": "Sales", | ||||
| 		"with_items": args.with_items or 0, | ||||
| 		"transaction_date": today() | ||||
| 	}) | ||||
| 
 | ||||
| 	if opp_doc.enquiry_from == 'Customer': | ||||
| 		opp_doc.customer = args.customer or "_Test Customer" | ||||
| 	if opp_doc.opportunity_from == 'Customer': | ||||
| 		opp_doc.party_name= args.customer or "_Test Customer" | ||||
| 
 | ||||
| 	if opp_doc.enquiry_from == 'Lead': | ||||
| 		opp_doc.lead = args.lead or "_T-Lead-00001" | ||||
| 	if opp_doc.opportunity_from == 'Lead': | ||||
| 		opp_doc.party_name = args.lead or "_T-Lead-00001" | ||||
| 
 | ||||
| 	if args.with_items: | ||||
| 		opp_doc.append('items', { | ||||
|  | ||||
| @ -2,9 +2,9 @@ | ||||
| 	{ | ||||
| 		"doctype": "Opportunity", | ||||
| 		"name": "_Test Opportunity 1", | ||||
| 		"enquiry_from": "Lead", | ||||
| 		"opportunity_from": "Lead", | ||||
| 		"enquiry_type": "Sales", | ||||
| 		"lead": "_T-Lead-00001", | ||||
| 		"party_name": "_T-Lead-00001", | ||||
| 		"transaction_date": "2013-12-12", | ||||
| 		"items": [{ | ||||
| 			"item_name": "Test Item", | ||||
|  | ||||
| @ -87,7 +87,7 @@ def get_employee_emails_for_popup(communication_medium): | ||||
| 		'parent': communication_medium, | ||||
| 		'from_time': ['<=', now_time], | ||||
| 		'to_time': ['>=', now_time], | ||||
| 	}, fields=['employee_group'], debug=1) | ||||
| 	}, fields=['employee_group']) | ||||
| 
 | ||||
| 	available_employee_groups = tuple([emp.employee_group for emp in available_employee_groups]) | ||||
| 
 | ||||
|  | ||||
| @ -4,24 +4,70 @@ | ||||
| from __future__ import unicode_literals | ||||
| import frappe | ||||
| from frappe import _ | ||||
| from frappe.utils import flt | ||||
| 
 | ||||
| def execute(filters=None): | ||||
| 	columns, data = [], [] | ||||
| 	columns=get_columns() | ||||
| 	data=get_lead_data(filters, "Campaign Name") | ||||
| 	columns=get_columns("Campaign Name") | ||||
| 	data=get_lead_data(filters or {}, "Campaign Name") | ||||
| 	return columns, data | ||||
| 
 | ||||
| def get_columns(): | ||||
| def get_columns(based_on): | ||||
| 	return [ | ||||
| 		_("Campaign Name") + ":data:130",  | ||||
| 		_("Lead Count") + ":Int:80", | ||||
| 		_("Opp Count") + ":Int:80", | ||||
| 		_("Quot Count") + ":Int:80",  | ||||
| 		_("Order Count") + ":Int:100", | ||||
| 		_("Order Value") + ":Float:100", | ||||
| 		_("Opp/Lead %") + ":Float:100", | ||||
| 		_("Quot/Lead %") + ":Float:100", | ||||
| 		_("Order/Quot %") + ":Float:100" | ||||
| 		{ | ||||
| 			"fieldname": frappe.scrub(based_on), | ||||
| 			"label": _(based_on), | ||||
| 			"fieldtype": "Data", | ||||
| 			"width": 150 | ||||
| 		}, | ||||
| 		{ | ||||
| 			"fieldname": "lead_count", | ||||
| 			"label": _("Lead Count"), | ||||
| 			"fieldtype": "Int", | ||||
| 			"width": 80 | ||||
| 		}, | ||||
| 		{ | ||||
| 			"fieldname": "opp_count", | ||||
| 			"label": _("Opp Count"), | ||||
| 			"fieldtype": "Int", | ||||
| 			"width": 80 | ||||
| 		}, | ||||
| 		{ | ||||
| 			"fieldname": "quot_count", | ||||
| 			"label": _("Quot Count"), | ||||
| 			"fieldtype": "Int", | ||||
| 			"width": 80 | ||||
| 		}, | ||||
| 		{ | ||||
| 			"fieldname": "order_count", | ||||
| 			"label": _("Order Count"), | ||||
| 			"fieldtype": "Int", | ||||
| 			"width": 100 | ||||
| 		}, | ||||
| 		{ | ||||
| 			"fieldname": "order_value", | ||||
| 			"label": _("Order Value"), | ||||
| 			"fieldtype": "Float", | ||||
| 			"width": 100 | ||||
| 		}, | ||||
| 		{ | ||||
| 			"fieldname": "opp_lead", | ||||
| 			"label": _("Opp/Lead %"), | ||||
| 			"fieldtype": "Float", | ||||
| 			"width": 100 | ||||
| 		}, | ||||
| 		{ | ||||
| 			"fieldname": "quot_lead", | ||||
| 			"label": _("Quot/Lead %"), | ||||
| 			"fieldtype": "Float", | ||||
| 			"width": 100 | ||||
| 		}, | ||||
| 		{ | ||||
| 			"fieldname": "order_quot", | ||||
| 			"label": _("Order/Quot %"), | ||||
| 			"fieldtype": "Float", | ||||
| 			"width": 100 | ||||
| 		} | ||||
| 	] | ||||
| 
 | ||||
| def get_lead_data(filters, based_on): | ||||
| @ -41,18 +87,18 @@ def get_lead_data(filters, based_on): | ||||
| 	data = [] | ||||
| 	for based_on_value, leads in lead_map.items(): | ||||
| 		row = { | ||||
| 			based_on: based_on_value, | ||||
| 			"Lead Count": len(leads) | ||||
| 			based_on_field: based_on_value, | ||||
| 			"lead_count": len(leads) | ||||
| 		} | ||||
| 		row["Quot Count"]= get_lead_quotation_count(leads) | ||||
| 		row["Opp Count"] = get_lead_opp_count(leads) | ||||
| 		row["Order Count"] = get_quotation_ordered_count(leads) | ||||
| 		row["Order Value"] = get_order_amount(leads) | ||||
| 		row["quot_count"]= get_lead_quotation_count(leads) | ||||
| 		row["opp_count"] = get_lead_opp_count(leads) | ||||
| 		row["order_count"] = get_quotation_ordered_count(leads) | ||||
| 		row["order_value"] = get_order_amount(leads) or 0 | ||||
| 
 | ||||
| 		row["Opp/Lead %"] = row["Opp Count"] / row["Lead Count"] * 100 | ||||
| 		row["Quot/Lead %"] = row["Quot Count"] / row["Lead Count"] * 100 | ||||
| 		row["opp_lead"] = flt(row["opp_count"]) / flt(row["lead_count"] or 1.0) * 100.0 | ||||
| 		row["quot_lead"] = flt(row["quot_count"]) / flt(row["lead_count"] or 1.0) * 100.0 | ||||
| 
 | ||||
| 		row["Order/Quot %"] = row["Order Count"] / (row["Quot Count"] or 1) * 100 | ||||
| 		row["order_quot"] = flt(row["order_count"]) / flt(row["quot_count"] or 1.0) * 100.0 | ||||
| 
 | ||||
| 		data.append(row) | ||||
| 
 | ||||
| @ -69,21 +115,21 @@ def get_filter_conditions(filters): | ||||
| 
 | ||||
| def get_lead_quotation_count(leads): | ||||
| 	return frappe.db.sql("""select count(name) from `tabQuotation` | ||||
| 		where lead in (%s)""" % ', '.join(["%s"]*len(leads)), tuple(leads))[0][0] | ||||
| 		where quotation_to = 'Lead' and party_name in (%s)""" % ', '.join(["%s"]*len(leads)), tuple(leads))[0][0] #nosec | ||||
| 
 | ||||
| def get_lead_opp_count(leads): | ||||
| 	return frappe.db.sql("""select count(name) from `tabOpportunity` | ||||
| 	where lead in (%s)""" % ', '.join(["%s"]*len(leads)), tuple(leads))[0][0] | ||||
| 	where opportunity_from = 'Lead' and party_name in (%s)""" % ', '.join(["%s"]*len(leads)), tuple(leads))[0][0] | ||||
| 
 | ||||
| def get_quotation_ordered_count(leads): | ||||
| 	return frappe.db.sql("""select count(name) | ||||
| 		from `tabQuotation` where status = 'Ordered' | ||||
| 		and lead in (%s)""" % ', '.join(["%s"]*len(leads)), tuple(leads))[0][0] | ||||
| 		from `tabQuotation` where status = 'Ordered' and quotation_to = 'Lead' | ||||
| 		and party_name in (%s)""" % ', '.join(["%s"]*len(leads)), tuple(leads))[0][0] | ||||
| 
 | ||||
| def get_order_amount(leads): | ||||
| 	return frappe.db.sql("""select sum(base_net_amount) | ||||
| 		from `tabSales Order Item` | ||||
| 		where prevdoc_docname in ( | ||||
| 			select name from `tabQuotation` where status = 'Ordered' | ||||
| 			and lead in (%s) | ||||
| 			and quotation_to = 'Lead' and party_name in (%s) | ||||
| 		)""" % ', '.join(["%s"]*len(leads)), tuple(leads))[0][0] | ||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user