From ed965916187fb71adeb5787f2098bb516669275d Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 8 Mar 2019 15:09:13 +0530 Subject: [PATCH 01/12] feat(accounts): Invoice Discounting --- .../accounts/doctype/account/test_account.py | 24 +- .../doctype/discounted_invoice/__init__.py | 0 .../discounted_invoice.json | 177 ++ .../discounted_invoice/discounted_invoice.py | 10 + .../doctype/invoice_discounting/__init__.py | 0 .../invoice_discounting.js | 196 ++ .../invoice_discounting.json | 773 ++++++++ .../invoice_discounting.py | 194 ++ .../test_invoice_discounting.py | 61 + .../doctype/journal_entry/journal_entry.py | 31 +- .../journal_entry_account.json | 1740 ++++++++--------- .../sales_invoice/sales_invoice_dashboard.py | 2 +- 12 files changed, 2326 insertions(+), 882 deletions(-) create mode 100644 erpnext/accounts/doctype/discounted_invoice/__init__.py create mode 100644 erpnext/accounts/doctype/discounted_invoice/discounted_invoice.json create mode 100644 erpnext/accounts/doctype/discounted_invoice/discounted_invoice.py create mode 100644 erpnext/accounts/doctype/invoice_discounting/__init__.py create mode 100644 erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js create mode 100644 erpnext/accounts/doctype/invoice_discounting/invoice_discounting.json create mode 100644 erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py create mode 100644 erpnext/accounts/doctype/invoice_discounting/test_invoice_discounting.py diff --git a/erpnext/accounts/doctype/account/test_account.py b/erpnext/accounts/doctype/account/test_account.py index acaa0966a2..cf881ec5aa 100644 --- a/erpnext/accounts/doctype/account/test_account.py +++ b/erpnext/accounts/doctype/account/test_account.py @@ -131,7 +131,7 @@ def _make_test_records(verbose): # related to Account Inventory Integration ["_Test Account Stock In Hand", "Current Assets", 0, None, None], - + # fixed asset depreciation ["_Test Fixed Asset", "Current Assets", 0, "Fixed Asset", None], ["_Test Accumulated Depreciations", "Current Assets", 0, None, None], @@ -168,13 +168,17 @@ def get_inventory_account(company, warehouse=None): return account def create_account(**kwargs): - account = frappe.get_doc(dict( - doctype = "Account", - account_name = kwargs.get('account_name'), - account_type = kwargs.get('account_type'), - parent_account = kwargs.get('parent_account'), - company = kwargs.get('company') - )) - - account.save() + try: + account = frappe.get_doc(dict( + doctype = "Account", + account_name = kwargs.get('account_name'), + account_type = kwargs.get('account_type'), + parent_account = kwargs.get('parent_account'), + company = kwargs.get('company') or "_Test Company" + )) + + account.save() + except frappe.DuplicateEntryError: + pass + return account.name diff --git a/erpnext/accounts/doctype/discounted_invoice/__init__.py b/erpnext/accounts/doctype/discounted_invoice/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.json b/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.json new file mode 100644 index 0000000000..0d04b19fd1 --- /dev/null +++ b/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.json @@ -0,0 +1,177 @@ +{ + "allow_copy": 0, + "allow_events_in_timeline": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "beta": 0, + "creation": "2019-03-07 12:07:09.416101", + "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": "sales_invoice", + "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": "Invoice", + "length": 0, + "no_copy": 0, + "options": "Sales Invoice", + "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, + "fetch_from": "sales_invoice.customer", + "fieldname": "customer", + "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": "Customer", + "length": 0, + "no_copy": 0, + "options": "Customer", + "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_from": "sales_invoice.posting_date", + "fieldname": "posting_date", + "fieldtype": "Date", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Date", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_from": "sales_invoice.grand_total", + "fieldname": "outstanding_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": "Outstanding Amount", + "length": 0, + "no_copy": 0, + "options": "Company:company:default_currency", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + } + ], + "has_web_view": 0, + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_view": 0, + "in_create": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 1, + "max_attachments": 0, + "modified": "2019-03-07 16:38:03.622666", + "modified_by": "Administrator", + "module": "Accounts", + "name": "Discounted Invoice", + "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 +} \ No newline at end of file diff --git a/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.py b/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.py new file mode 100644 index 0000000000..93dfcc14bd --- /dev/null +++ b/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.py @@ -0,0 +1,10 @@ +# -*- 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 frappe.model.document import Document + +class DiscountedInvoice(Document): + pass diff --git a/erpnext/accounts/doctype/invoice_discounting/__init__.py b/erpnext/accounts/doctype/invoice_discounting/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js new file mode 100644 index 0000000000..872072c91d --- /dev/null +++ b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js @@ -0,0 +1,196 @@ +// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Invoice Discounting', { + setup: (frm) => { + frm.set_query("sales_invoice", "invoices", (doc, cdt, cdn) => { + return { + "filters": { + "docstatus": 1, + "company": doc.company, + "outstanding_amount": [">", 0] + } + } + }); + + frm.events.filter_accounts("bank_account", frm, {"account_type": "Bank"}); + frm.events.filter_accounts("bank_charges_account", frm, {"root_type": "Expense"}); + frm.events.filter_accounts("short_term_loan", frm, {"root_type": "Liability"}); + frm.events.filter_accounts("accounts_receivable_credit", frm, {"account_type": "Receivable"}); + frm.events.filter_accounts("accounts_receivable_discounted", frm, {"account_type": "Receivable"}); + frm.events.filter_accounts("accounts_receivable_unpaid", frm, {"account_type": "Receivable"}); + + }, + + filter_accounts: (fieldname, frm, addl_filters) => { + let filters = { + "company": frm.doc.company, + "is_group": 0 + }; + if(addl_filters) Object.assign(filters, addl_filters); + + frm.set_query(fieldname, () => { return { "filters": filters }; }); + }, + + refresh: (frm) => { + frm.events.show_general_ledger(frm); + + if(frm.doc.docstatus == 0) { + frm.add_custom_button(__('Get Invoices'), function() { + frm.events.get_invoices(frm); + }); + } + + if(frm.doc.docstatus==1 && frm.doc.status != "Settled") { + if(frm.doc.status == "Sanctioned") { + frm.add_custom_button(__('Disburse Loan'), function() { + frm.events.create_disbursement_entry(frm); + }).addClass("btn-primary"); + } + if(frm.doc.status == "Disbursed") { + frm.add_custom_button(__('Close Loan'), function() { + frm.events.close_loan(frm); + }).addClass("btn-primary"); + } + } + }, + + loan_start_date: (frm) => { + frm.events.set_end_date(frm); + }, + + loan_period: (frm) => { + frm.events.set_end_date(frm); + }, + + set_end_date: (frm) => { + if(frm.doc.loan_start_date && frm.doc.loan_period) { + let end_date = frappe.datetime.add_days(frm.doc.loan_start_date, frm.doc.loan_period); + frm.set_value("loan_end_date", end_date); + } + }, + + validate: (frm) => { + frm.events.calculate_total_amount(frm); + }, + + calculate_total_amount: (frm) => { + let total_amount = 0.0; + for (let row of (frm.doc.invoices || [])) { + total_amount += flt(row.outstanding_amount); + } + frm.set_value("total_amount", total_amount); + }, + + get_invoices: (frm) => { + var d = new frappe.ui.Dialog({ + title: __('Get Invoices based on Filters'), + fields: [ + { + "label": "Customer", + "fieldname": "customer", + "fieldtype": "Link", + "options": "Customer" + }, + { + "label": "From Date", + "fieldname": "from_date", + "fieldtype": "Date" + }, + { + "label": "To Date", + "fieldname": "to_date", + "fieldtype": "Date" + }, + { + "fieldname": "col_break", + "fieldtype": "Column Break", + }, + { + "label": "Min Amount", + "fieldname": "min_amount", + "fieldtype": "Currency" + }, + { + "label": "Max Amount", + "fieldname": "max_amount", + "fieldtype": "Currency" + } + ], + primary_action: function() { + var data = d.get_values(); + + frappe.call({ + method: "erpnext.accounts.doctype.invoice_discounting.invoice_discounting.get_invoices", + args: { + filters: data + }, + callback: function(r) { + if(!r.exc) { + d.hide(); + $.each(r.message, function(i, v) { + let row = frm.add_child("invoices"); + $.extend(row, v); + }) + refresh_field("invoices"); + } + } + }); + }, + primary_action_label: __('Get Invocies') + }); + d.show(); + }, + + create_disbursement_entry: (frm) => { + frappe.call({ + method:"create_disbursement_entry", + doc: frm.doc, + callback: function(r) { + if(!r.exc){ + var doc = frappe.model.sync(r.message); + frappe.set_route("Form", r.message.doctype, r.message.name); + } + } + }) + + }, + + close_loan: (frm) => { + frappe.call({ + method:"close_loan", + doc: frm.doc, + callback: function(r) { + if(!r.exc){ + var doc = frappe.model.sync(r.message); + frappe.set_route("Form", r.message.doctype, r.message.name); + } + } + }) + + }, + + show_general_ledger: (frm) => { + if(frm.doc.docstatus===1) { + cur_frm.add_custom_button(__('Accounting Ledger'), function() { + frappe.route_options = { + voucher_no: frm.doc.name, + from_date: frm.doc.posting_date, + to_date: frm.doc.posting_date, + company: frm.doc.company, + group_by: "Group by Voucher (Consolidated)" + }; + frappe.set_route("query-report", "General Ledger"); + }, __("View")); + } + } +}); + +frappe.ui.form.on('Discounted Invoice', { + sales_invoice: (frm, cdt, cdn) => { + frm.events.calculate_total_amount(frm); + }, + invoices_remove: (frm, cdt, cdn) => { + frm.events.calculate_total_amount(frm); + } +}); \ No newline at end of file diff --git a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.json b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.json new file mode 100644 index 0000000000..8927ca708d --- /dev/null +++ b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.json @@ -0,0 +1,773 @@ +{ + "allow_copy": 0, + "allow_events_in_timeline": 0, + "allow_guest_to_view": 0, + "allow_import": 1, + "allow_rename": 0, + "autoname": "ACC-INV-DISC-.YYYY.-.#####", + "beta": 0, + "creation": "2019-03-07 12:01:56.296952", + "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": "posting_date", + "fieldtype": "Date", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Posting Date", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "loan_start_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": "Loan Start Date", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "loan_period", + "fieldtype": "Int", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Loan Period", + "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": "loan_end_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": "Loan End Date", + "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 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_3", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "status", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Status", + "length": 0, + "no_copy": 1, + "options": "Draft\nSanctioned\nDisbursed\nSettled\nCancelled", + "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": "company", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Company", + "length": 0, + "no_copy": 0, + "options": "Company", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "section_break_5", + "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": "invoices", + "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": "Invoices", + "length": 0, + "no_copy": 0, + "options": "Discounted Invoice", + "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": "section_break_7", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "total_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": "Total Amount", + "length": 0, + "no_copy": 0, + "options": "Company:company:default_currency", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_9", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "bank_charges", + "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": "Bank Charges", + "length": 0, + "no_copy": 0, + "options": "Company:company:default_currency", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "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_6", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "short_term_loan", + "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": "Short Term Loan Account", + "length": 0, + "no_copy": 0, + "options": "Account", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 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": 0, + "label": "Bank Account", + "length": 0, + "no_copy": 0, + "options": "Account", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "bank_charges_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": 0, + "label": "Bank Charges Account", + "length": 0, + "no_copy": 0, + "options": "Account", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_15", + "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, + "fieldname": "accounts_receivable_credit", + "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": "Accounts Receivable Credit Account", + "length": 0, + "no_copy": 0, + "options": "Account", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "accounts_receivable_discounted", + "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": "Accounts Receivable Discounted Account", + "length": 0, + "no_copy": 0, + "options": "Account", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "accounts_receivable_unpaid", + "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": "Accounts Receivable Unpaid Account", + "length": 0, + "no_copy": 0, + "options": "Account", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "amended_from", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Amended From", + "length": 0, + "no_copy": 1, + "options": "Invoice Discounting", + "permlevel": 0, + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + } + ], + "has_web_view": 0, + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_view": 0, + "in_create": 0, + "is_submittable": 1, + "issingle": 0, + "istable": 0, + "max_attachments": 0, + "modified": "2019-03-08 14:24:31.222027", + "modified_by": "Administrator", + "module": "Accounts", + "name": "Invoice Discounting", + "name_case": "", + "owner": "Administrator", + "permissions": [ + { + "amend": 1, + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "if_owner": 0, + "import": 1, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "set_user_permissions": 0, + "share": 1, + "submit": 1, + "write": 1 + } + ], + "quick_entry": 0, + "read_only": 0, + "read_only_onload": 0, + "show_name_in_global_search": 0, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1, + "track_seen": 0, + "track_views": 0 +} \ No newline at end of file diff --git a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py new file mode 100644 index 0000000000..69cd5f63f8 --- /dev/null +++ b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py @@ -0,0 +1,194 @@ +# -*- 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, json +from frappe import _ +from frappe.utils import flt, getdate, nowdate +from erpnext.controllers.accounts_controller import AccountsController +from erpnext.accounts.general_ledger import make_gl_entries + +class InvoiceDiscounting(AccountsController): + def validate(self): + self.validate_mandatory() + self.calculate_total_amount() + self.set_status() + + def validate_mandatory(self): + if self.docstatus == 1 and not (self.loan_start_date and self.loan_period): + frappe.throw(_("Loan Start Date and Loan Period are mandatory to submit the Invoice Discounting")) + + def calculate_total_amount(self): + self.total_amount = sum([flt(d.outstanding_amount) for d in self.invoices]) + + def on_submit(self): + self.make_gl_entries() + + def on_cancel(self): + self.set_status() + self.make_gl_entries() + + def set_status(self): + self.status = "Draft" + if self.docstatus == 1: + self.status = "Sanctioned" + elif self.docstatus == 2: + self.status: "Cancelled" + + def make_gl_entries(self): + company_currency = frappe.get_cached_value('Company', self.company, "default_currency") + + gl_entries = [] + for d in self.invoices: + inv = frappe.db.get_value("Sales Invoice", d.sales_invoice, + ["debit_to", "party_account_currency", "conversion_rate", "cost_center"], as_dict=1) + + if d.outstanding_amount: + outstanding_in_company_currency = flt(d.outstanding_amount * inv.conversion_rate, + d.precision("outstanding_amount")) + ar_credit_account_currency = frappe.get_cached_value("Account", self.accounts_receivable_credit, "currency") + + gl_entries.append(self.get_gl_dict({ + "account": inv.debit_to, + "party_type": "Customer", + "party": d.customer, + "against": self.accounts_receivable_credit, + "credit": outstanding_in_company_currency, + "credit_in_account_currency": outstanding_in_company_currency \ + if inv.party_account_currency==company_currency else d.outstanding_amount, + "cost_center": inv.cost_center, + "against_voucher": d.sales_invoice, + "against_voucher_type": "Sales Invoice" + }, inv.party_account_currency)) + + gl_entries.append(self.get_gl_dict({ + "account": self.accounts_receivable_credit, + "party_type": "Customer", + "party": d.customer, + "against": inv.debit_to, + "debit": outstanding_in_company_currency, + "debit_in_account_currency": outstanding_in_company_currency \ + if ar_credit_account_currency==company_currency else d.outstanding_amount, + "cost_center": inv.cost_center, + "against_voucher": d.sales_invoice, + "against_voucher_type": "Sales Invoice" + }, ar_credit_account_currency)) + + make_gl_entries(gl_entries, cancel=(self.docstatus == 2), update_outstanding='No') + + def create_disbursement_entry(self): + je = frappe.new_doc("Journal Entry") + je.voucher_type = 'Journal Entry' + je.company = self.company + je.remark = 'Loan Disbursement entry against Invoice Discounting: ' + self.name + + je.append("accounts", { + "account": self.bank_account, + "debit_in_account_currency": flt(self.total_amount) - flt(self.bank_charges), + }) + + je.append("accounts", { + "account": self.bank_charges_account, + "debit_in_account_currency": flt(self.bank_charges) + }) + + je.append("accounts", { + "account": self.short_term_loan, + "credit_in_account_currency": flt(self.total_amount), + "reference_type": "Invoice Discounting", + "reference_name": self.name + }) + + for d in self.invoices: + je.append("accounts", { + "account": self.accounts_receivable_discounted, + "debit_in_account_currency": flt(d.outstanding_amount), + "reference_type": "Invoice Discounting", + "reference_name": self.name, + "party_type": "Customer", + "party": d.customer + }) + + je.append("accounts", { + "account": self.accounts_receivable_credit, + "credit_in_account_currency": flt(d.outstanding_amount), + "reference_type": "Invoice Discounting", + "reference_name": self.name, + "party_type": "Customer", + "party": d.customer + }) + + return je.as_dict() + + def close_loan(self): + je = frappe.new_doc("Journal Entry") + je.voucher_type = 'Journal Entry' + je.company = self.company + je.remark = 'Loan Settlement entry against Invoice Discounting: ' + self.name + + je.append("accounts", { + "account": self.short_term_loan, + "debit_in_account_currency": flt(self.total_amount), + "reference_type": "Invoice Discounting", + "reference_name": self.name, + }) + + je.append("accounts", { + "account": self.bank_account, + "credit_in_account_currency": flt(self.total_amount) + }) + + if getdate(self.loan_end_date) > getdate(nowdate()): + for d in self.invoices: + je.append("accounts", { + "account": self.accounts_receivable_discounted, + "credit_in_account_currency": flt(d.outstanding_amount), + "reference_type": "Invoice Discounting", + "reference_name": self.name, + "party_type": "Customer", + "party": d.customer + }) + + je.append("accounts", { + "account": self.accounts_receivable_unpaid, + "debit_in_account_currency": flt(d.outstanding_amount), + "reference_type": "Invoice Discounting", + "reference_name": self.name, + "party_type": "Customer", + "party": d.customer + }) + + return je.as_dict() + +@frappe.whitelist() +def get_invoices(filters): + filters = frappe._dict(json.loads(filters)) + cond = [] + if filters.customer: + cond.append("customer=%(customer)s") + if filters.from_date: + cond.append("posting_date >= %(from_date)s") + if filters.to_date: + cond.append("posting_date <= %(to_date)s") + if filters.min_amount: + cond.append("base_grand_total >= %(min_amount)s") + if filters.max_amount: + cond.append("base_grand_total <= %(max_amount)s") + + where_condition = "" + if cond: + where_condition += " and " + " and ".join(cond) + + return frappe.db.sql(""" + select + name as sales_invoice, + customer, + posting_date, + outstanding_amount + from `tabSales Invoice` + where + docstatus = 1 + and outstanding_amount > 0 + %s + """ % where_condition, filters, as_dict=1) \ No newline at end of file diff --git a/erpnext/accounts/doctype/invoice_discounting/test_invoice_discounting.py b/erpnext/accounts/doctype/invoice_discounting/test_invoice_discounting.py new file mode 100644 index 0000000000..6fd276d62e --- /dev/null +++ b/erpnext/accounts/doctype/invoice_discounting/test_invoice_discounting.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt +from __future__ import unicode_literals + +import frappe +from frappe.utils import nowdate +import unittest +from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice +from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import get_gl_entries +from erpnext.accounts.doctype.account.test_account import create_account + +class TestInvoiceDiscounting(unittest.TestCase): + def setUp(self): + self.ar_credit = create_account(account_name="_Test Accounts Receivable Credit", parent_account = "Accounts Receivable - _TC") + self.ar_discounted = create_account(account_name="_Test Accounts Receivable Discounted", parent_account = "Accounts Receivable - _TC") + self.ar_unpaid = create_account(account_name="_Test Accounts Receivable Unpaid", parent_account = "Accounts Receivable - _TC") + + + def test_total_amount(self): + inv1 = create_sales_invoice(rate=200) + inv2 = create_sales_invoice(rate=500) + + inv_disc = create_invoice_discounting([inv1.name, inv2.name], do_not_submit=True) + self.assertEqual(inv_disc.total_amount, 700) + + def test_gl_entries_in_base_currency(self): + inv = create_sales_invoice(rate=200) + inv_disc = create_invoice_discounting([inv.name], + accounts_receivable_credit=self.ar_credit, + accounts_receivable_discounted=self.ar_discounted, + accounts_receivable_unpaid=self.ar_unpaid) + + gle = get_gl_entries("Invoice Discounting", inv_disc.name) + + expected_gle = { + inv.debit_to: [0.0, 200], + self.ar_credit: [200, 0.0] + } + for i, gle in enumerate(gle): + self.assertEqual([gle.debit, gle.credit], expected_gle.get(gle.account)) + +def create_invoice_discounting(invoices, **args): + args = frappe._dict(args) + inv_disc = frappe.new_doc("Invoice Discounting") + inv_disc.posting_date = args.posting_date or nowdate() + inv_disc.company = args.company or "_Test Company" + inv_disc.bank_account = args.bank_account + inv_disc.short_term_loan = args.short_term_loan + inv_disc.accounts_receivable_credit = args.accounts_receivable_credit + inv_disc.accounts_receivable_discounted = args.accounts_receivable_discounted + inv_disc.accounts_receivable_unpaid = args.accounts_receivable_unpaid + + for d in invoices: + inv_disc.append("invoices", { + "sales_invoice": d + }) + inv_disc.insert() + if not args.do_not_submit: + inv_disc.submit() + return inv_disc diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index 3a17ce5b4b..683845f7de 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -51,6 +51,7 @@ class JournalEntry(AccountsController): self.update_expense_claim() self.update_loan() self.update_inter_company_jv() + self.update_invoice_discounting() def before_print(self): self.gl_entries = frappe.get_list("GL Entry",filters={"voucher_type": "Journal Entry", @@ -86,6 +87,18 @@ class JournalEntry(AccountsController): frappe.db.set_value("Journal Entry", self.inter_company_journal_entry_reference,\ "inter_company_journal_entry_reference", self.name) + def update_invoice_discounting(self): + invoice_discounting_list = [d.reference_name for d in self.accounts if d.reference_type=="Invoice Discounting"] + for inv_disc in invoice_discounting_list: + short_term_loan_account = frappe.db.get_value("Invoice Discounting", inv_disc, "short_term_loan") + for d in self.accounts: + if d.account == short_term_loan_account and d.reference_name == inv_disc: + if d.credit > 0: + status = "Disbursed" + elif d.debit > 0: + status = "Settled" + frappe.db.set_value("Invoice Discounting", inv_disc, "status", status) + def on_cancel(self): from erpnext.accounts.utils import unlink_ref_doc_from_payment_entries from erpnext.hr.doctype.salary_slip.salary_slip import unlink_ref_doc_from_salary_slip @@ -693,7 +706,7 @@ def get_payment_entry_against_invoice(dt, dn, amount=None, debit_in_account_cur ref_doc = frappe.get_doc(dt, dn) if dt == "Sales Invoice": party_type = "Customer" - party_account = ref_doc.debit_to + party_account = get_party_account_based_on_invoice_discounting(dn) or ref_doc.debit_to else: party_type = "Supplier" party_account = ref_doc.credit_to @@ -720,6 +733,22 @@ def get_payment_entry_against_invoice(dt, dn, amount=None, debit_in_account_cur "journal_entry": journal_entry }) +def get_party_account_based_on_invoice_discounting(sales_invoice): + party_account = None + invoice_discounting = frappe.db.sql(""" + select par.accounts_receivable_discounted, par.accounts_receivable_unpaid, par.status + from `tabInvoice Discounting` par, `tabDiscounted Invoice` ch + where par.name=ch.parent + and par.docstatus=1 + and ch.sales_invoice = %s + """, (sales_invoice), as_dict=1) + if invoice_discounting: + if invoice_discounting[0].status == "Disbursed": + party_account = invoice_discounting[0].accounts_receivable_discounted + elif invoice_discounting[0].status == "Settled": + party_account = invoice_discounting[0].accounts_receivable_unpaid + + return party_account def get_payment_entry(ref_doc, args): cost_center = ref_doc.get("cost_center") or frappe.get_cached_value('Company', ref_doc.company, "cost_center") diff --git a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json index 32e49dbde4..b9a7555bf6 100644 --- a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json +++ b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json @@ -1,929 +1,929 @@ { - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "autoname": "hash", - "beta": 0, - "creation": "2013-02-22 01:27:39", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "Document", - "editable_grid": 1, - "engine": "InnoDB", + "allow_copy": 0, + "allow_events_in_timeline": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "autoname": "hash", + "beta": 0, + "creation": "2013-02-22 01:27:39", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "Document", + "editable_grid": 1, + "engine": "InnoDB", "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 1, - "collapsible": 0, - "columns": 3, - "fieldname": "account", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 1, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Account", - "length": 0, - "no_copy": 0, - "oldfieldname": "account", - "oldfieldtype": "Link", - "options": "Account", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "print_width": "250px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 1, - "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": 3, + "fieldname": "account", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 1, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Account", + "length": 0, + "no_copy": 0, + "oldfieldname": "account", + "oldfieldtype": "Link", + "options": "Account", + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": "250px", + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 1, + "set_only_once": 0, + "translatable": 0, + "unique": 0, "width": "250px" - }, + }, { - "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": 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": "Account Type", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "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, + "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": 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": "Account Type", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "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": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "balance", - "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": "Account Balance", - "length": 0, - "no_copy": 1, - "oldfieldname": "balance", - "oldfieldtype": "Data", - "options": "account_currency", - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "balance", + "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": "Account Balance", + "length": 0, + "no_copy": 1, + "oldfieldname": "balance", + "oldfieldtype": "Data", + "options": "account_currency", + "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, - "default": ":Company", - "description": "If Income or Expense", - "fieldname": "cost_center", - "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": "Cost Center", - "length": 0, - "no_copy": 0, - "oldfieldname": "cost_center", - "oldfieldtype": "Link", - "options": "Cost Center", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "print_width": "180px", - "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": ":Company", + "description": "If Income or Expense", + "fieldname": "cost_center", + "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": "Cost Center", + "length": 0, + "no_copy": 0, + "oldfieldname": "cost_center", + "oldfieldtype": "Link", + "options": "Cost Center", + "permlevel": 0, + "print_hide": 1, + "print_hide_if_no_value": 0, + "print_width": "180px", + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0, "width": "180px" - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "col_break1", - "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, - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "col_break1", + "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, + "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": "party_type", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Party Type", - "length": 0, - "no_copy": 0, - "options": "DocType", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "party_type", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Party Type", + "length": 0, + "no_copy": 0, + "options": "DocType", + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 1, + "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": 3, - "fieldname": "party", - "fieldtype": "Dynamic Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Party", - "length": 0, - "no_copy": 0, - "options": "party_type", - "permlevel": 0, - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 3, + "fieldname": "party", + "fieldtype": "Dynamic Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Party", + "length": 0, + "no_copy": 0, + "options": "party_type", + "permlevel": 0, + "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": "party_balance", - "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": "Party Balance", - "length": 0, - "no_copy": 0, - "options": "account_currency", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "party_balance", + "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": "Party Balance", + "length": 0, + "no_copy": 0, + "options": "account_currency", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "collapsible_depends_on": "", - "columns": 0, - "depends_on": "", - "fieldname": "currency_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": "Currency", - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "collapsible_depends_on": "", + "columns": 0, + "depends_on": "", + "fieldname": "currency_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": "Currency", + "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": "account_currency", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Account Currency", - "length": 0, - "no_copy": 1, - "options": "Currency", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "account_currency", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Account Currency", + "length": 0, + "no_copy": 1, + "options": "Currency", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_10", - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_10", + "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, - "fieldname": "exchange_rate", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Exchange Rate", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "9", - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "exchange_rate", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Exchange Rate", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "9", + "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": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "sec_break1", - "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": "Amount", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "sec_break1", + "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": "Amount", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "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": 1, - "collapsible": 0, - "columns": 2, - "fieldname": "debit_in_account_currency", - "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Debit", - "length": 0, - "no_copy": 0, - "options": "account_currency", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 1, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 1, + "collapsible": 0, + "columns": 2, + "fieldname": "debit_in_account_currency", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Debit", + "length": 0, + "no_copy": 0, + "options": "account_currency", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 1, + "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, - "fieldname": "debit", - "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": "Debit in Company Currency", - "length": 0, - "no_copy": 1, - "oldfieldname": "debit", - "oldfieldtype": "Currency", - "options": "Company:company:default_currency", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 1, + "collapsible": 0, + "columns": 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": 0, + "in_standard_filter": 0, + "label": "Debit in Company Currency", + "length": 0, + "no_copy": 1, + "oldfieldname": "debit", + "oldfieldtype": "Currency", + "options": "Company:company:default_currency", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "col_break2", - "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, - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "col_break2", + "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, + "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": 1, - "collapsible": 0, - "columns": 2, - "fieldname": "credit_in_account_currency", - "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Credit", - "length": 0, - "no_copy": 0, - "options": "account_currency", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 1, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 1, + "collapsible": 0, + "columns": 2, + "fieldname": "credit_in_account_currency", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Credit", + "length": 0, + "no_copy": 0, + "options": "account_currency", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 1, + "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, - "fieldname": "credit", - "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": "Credit in Company Currency", - "length": 0, - "no_copy": 1, - "oldfieldname": "credit", - "oldfieldtype": "Currency", - "options": "Company:company:default_currency", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 1, + "collapsible": 0, + "columns": 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": 0, + "in_standard_filter": 0, + "label": "Credit in Company Currency", + "length": 0, + "no_copy": 1, + "oldfieldname": "credit", + "oldfieldtype": "Currency", + "options": "Company:company:default_currency", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "reference", - "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": "Reference", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "reference", + "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": "Reference", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "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": "reference_type", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Reference Type", - "length": 0, - "no_copy": 0, - "options": "\nSales Invoice\nPurchase Invoice\nJournal Entry\nSales Order\nPurchase Order\nExpense Claim\nAsset\nLoan\nPayroll Entry\nEmployee Advance\nExchange Rate Revaluation", - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "reference_type", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Reference Type", + "length": 0, + "no_copy": 0, + "options": "\nSales Invoice\nPurchase Invoice\nJournal Entry\nSales Order\nPurchase Order\nExpense Claim\nAsset\nLoan\nPayroll Entry\nEmployee Advance\nExchange Rate Revaluation\nInvoice Discounting", + "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": "reference_name", - "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": "Reference Name", - "length": 0, - "no_copy": 0, - "options": "reference_type", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "reference_name", + "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": "Reference Name", + "length": 0, + "no_copy": 0, + "options": "reference_type", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.reference_type&&!in_list(doc.reference_type, ['Expense Claim', 'Asset', 'Employee Loan', 'Employee Advance'])", - "fieldname": "reference_due_date", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Reference Due Date", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:doc.reference_type&&!in_list(doc.reference_type, ['Expense Claim', 'Asset', 'Employee Loan', 'Employee Advance'])", + "fieldname": "reference_due_date", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Reference Due Date", + "length": 0, + "no_copy": 0, + "options": "", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "project", - "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": "Project", - "length": 0, - "no_copy": 0, - "options": "Project", - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "project", + "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": "Project", + "length": 0, + "no_copy": 0, + "options": "Project", + "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": "col_break3", - "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, - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "col_break3", + "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, + "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": "is_advance", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Is Advance", - "length": 0, - "no_copy": 1, - "oldfieldname": "is_advance", - "oldfieldtype": "Select", - "options": "No\nYes", - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "is_advance", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Is Advance", + "length": 0, + "no_copy": 1, + "oldfieldname": "is_advance", + "oldfieldtype": "Select", + "options": "No\nYes", + "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": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "user_remark", - "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": "User Remark", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "user_remark", + "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": "User Remark", + "length": 0, + "no_copy": 1, + "permlevel": 0, + "precision": "", + "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": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "against_account", - "fieldtype": "Text", - "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": "Against Account", - "length": 0, - "no_copy": 1, - "oldfieldname": "against_account", - "oldfieldtype": "Text", - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "against_account", + "fieldtype": "Text", + "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": "Against Account", + "length": 0, + "no_copy": 1, + "oldfieldname": "against_account", + "oldfieldtype": "Text", + "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 } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 1, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 1, - "max_attachments": 0, - "modified": "2019-02-18 19:00:53.662788", - "modified_by": "Administrator", - "module": "Accounts", - "name": "Journal Entry Account", - "owner": "Administrator", - "permissions": [], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0, + ], + "has_web_view": 0, + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 1, + "image_view": 0, + "in_create": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 1, + "max_attachments": 0, + "modified": "2019-03-07 19:10:42.704280", + "modified_by": "Administrator", + "module": "Accounts", + "name": "Journal Entry Account", + "owner": "Administrator", + "permissions": [], + "quick_entry": 0, + "read_only": 0, + "read_only_onload": 0, + "show_name_in_global_search": 0, + "sort_order": "DESC", + "track_changes": 1, + "track_seen": 0, "track_views": 0 } \ No newline at end of file diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py index 28da815655..4a8fcc03fd 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py @@ -18,7 +18,7 @@ def get_data(): 'transactions': [ { 'label': _('Payment'), - 'items': ['Payment Entry', 'Payment Request', 'Journal Entry'] + 'items': ['Payment Entry', 'Payment Request', 'Journal Entry', 'Invoice Discounting'] }, { 'label': _('Reference'), From 4a538ba78a8e963c6b1d437ff1fe638f964adf86 Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Mon, 11 Mar 2019 12:30:21 +0530 Subject: [PATCH 02/12] Resolve merge conflict --- .../accounts/doctype/invoice_discounting/invoice_discounting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py index 69cd5f63f8..b047c31b1a 100644 --- a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py +++ b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py @@ -34,7 +34,7 @@ class InvoiceDiscounting(AccountsController): if self.docstatus == 1: self.status = "Sanctioned" elif self.docstatus == 2: - self.status: "Cancelled" + self.status = "Cancelled" def make_gl_entries(self): company_currency = frappe.get_cached_value('Company', self.company, "default_currency") From 6deffbd6e85ef2f4f8e129b99fd280de6b1a2c30 Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Wed, 13 Mar 2019 17:54:45 +0530 Subject: [PATCH 03/12] test: loan_return date and loan Sanctioned on submit --- .../invoice_discounting.py | 6 +- .../test_invoice_discounting.py | 64 ++++++++++++++++++- 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py index b047c31b1a..2777d0b7d2 100644 --- a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py +++ b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py @@ -5,7 +5,7 @@ from __future__ import unicode_literals import frappe, json from frappe import _ -from frappe.utils import flt, getdate, nowdate +from frappe.utils import flt, getdate, nowdate, add_days from erpnext.controllers.accounts_controller import AccountsController from erpnext.accounts.general_ledger import make_gl_entries @@ -14,6 +14,10 @@ class InvoiceDiscounting(AccountsController): self.validate_mandatory() self.calculate_total_amount() self.set_status() + self.set_end_date() + + def set_end_date(self): + self.loan_end_date = add_days(self.loan_start_date, self.loan_period) def validate_mandatory(self): if self.docstatus == 1 and not (self.loan_start_date and self.loan_period): diff --git a/erpnext/accounts/doctype/invoice_discounting/test_invoice_discounting.py b/erpnext/accounts/doctype/invoice_discounting/test_invoice_discounting.py index 6fd276d62e..96e3991fc6 100644 --- a/erpnext/accounts/doctype/invoice_discounting/test_invoice_discounting.py +++ b/erpnext/accounts/doctype/invoice_discounting/test_invoice_discounting.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import frappe -from frappe.utils import nowdate +from frappe.utils import nowdate, add_days import unittest from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import get_gl_entries @@ -15,13 +15,24 @@ class TestInvoiceDiscounting(unittest.TestCase): self.ar_credit = create_account(account_name="_Test Accounts Receivable Credit", parent_account = "Accounts Receivable - _TC") self.ar_discounted = create_account(account_name="_Test Accounts Receivable Discounted", parent_account = "Accounts Receivable - _TC") self.ar_unpaid = create_account(account_name="_Test Accounts Receivable Unpaid", parent_account = "Accounts Receivable - _TC") + self.short_term_loan = create_account(account_name="_Test Short Term Loan", parent_account = "Source of Funds (Liabilities) - _TC") + self.bank_account = create_account(account_name="_Test Bank 2", parent_account = "Bank Accounts - _TC" ) + self.bank_charges_account = create_account(account_name="_Test Bank Charges Account", parent_account = "Expenses - _TC") def test_total_amount(self): inv1 = create_sales_invoice(rate=200) inv2 = create_sales_invoice(rate=500) - inv_disc = create_invoice_discounting([inv1.name, inv2.name], do_not_submit=True) + inv_disc = create_invoice_discounting([inv1.name, inv2.name], + do_not_submit=True, + accounts_receivable_credit=self.ar_credit, + accounts_receivable_discounted=self.ar_discounted, + accounts_receivable_unpaid=self.ar_unpaid, + short_term_loan=self.short_term_loan, + bank_charges_account=self.bank_charges_account, + bank_account=self.bank_account + ) self.assertEqual(inv_disc.total_amount, 700) def test_gl_entries_in_base_currency(self): @@ -29,7 +40,11 @@ class TestInvoiceDiscounting(unittest.TestCase): inv_disc = create_invoice_discounting([inv.name], accounts_receivable_credit=self.ar_credit, accounts_receivable_discounted=self.ar_discounted, - accounts_receivable_unpaid=self.ar_unpaid) + accounts_receivable_unpaid=self.ar_unpaid, + short_term_loan=self.short_term_loan, + bank_charges_account=self.bank_charges_account, + bank_account=self.bank_account + ) gle = get_gl_entries("Invoice Discounting", inv_disc.name) @@ -40,6 +55,39 @@ class TestInvoiceDiscounting(unittest.TestCase): for i, gle in enumerate(gle): self.assertEqual([gle.debit, gle.credit], expected_gle.get(gle.account)) + def test_loan_on_submit(self): + inv = create_sales_invoice(rate=300) + inv_disc = create_invoice_discounting([inv.name], + accounts_receivable_credit=self.ar_credit, + accounts_receivable_discounted=self.ar_discounted, + accounts_receivable_unpaid=self.ar_unpaid, + short_term_loan=self.short_term_loan, + bank_charges_account=self.bank_charges_account, + bank_account=self.bank_account, + start=nowdate(), + period=60 + ) + self.assertEqual(inv_disc.status, "Sanctioned") + self.assertEqual(inv_disc.loan_end_date, add_days(inv_disc.loan_start_date, inv_disc.loan_period)) + + '''def test_on_disbursed(self): + inv = create_sales_invoice(rate=300) + inv_disc = create_invoice_discounting([inv.name], + accounts_receivable_credit=self.ar_credit, + accounts_receivable_discounted=self.ar_discounted, + accounts_receivable_unpaid=self.ar_unpaid, + short_term_loan=self.short_term_loan, + bank_charges_account=self.bank_charges_account, + bank_account=self.bank_account, + set_status='Disbursed' + ) + + gle = get_gl_entries("Invoice Discounting", inv_disc.name) + from pprint import pprint + pprint(gle)''' + + def test_on_invoice_payment + def create_invoice_discounting(invoices, **args): args = frappe._dict(args) inv_disc = frappe.new_doc("Invoice Discounting") @@ -50,12 +98,22 @@ def create_invoice_discounting(invoices, **args): inv_disc.accounts_receivable_credit = args.accounts_receivable_credit inv_disc.accounts_receivable_discounted = args.accounts_receivable_discounted inv_disc.accounts_receivable_unpaid = args.accounts_receivable_unpaid + inv_disc.short_term_loan=args.short_term_loan + inv_disc.bank_charges_account=args.bank_charges_account + inv_disc.bank_account=args.bank_account + inv_disc.loan_start_date = args.start or nowdate() + inv_disc.loan_period = args.period or 30 for d in invoices: inv_disc.append("invoices", { "sales_invoice": d }) inv_disc.insert() + if not args.do_not_submit: inv_disc.submit() + + if args.set_status: + inv_disc.status = args.set_status + return inv_disc From 1c7baaeba5e867007c4c67f9f7efaaeb60e3f733 Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Thu, 14 Mar 2019 16:02:49 +0530 Subject: [PATCH 04/12] test: tests for loan status Disbursed, Settled and on payment Entry for attached invoices --- .../invoice_discounting.py | 5 +- .../test_invoice_discounting.py | 158 ++++++++++++++++-- 2 files changed, 147 insertions(+), 16 deletions(-) diff --git a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py index 2777d0b7d2..7b1dcd4f3d 100644 --- a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py +++ b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py @@ -103,7 +103,6 @@ class InvoiceDiscounting(AccountsController): "reference_type": "Invoice Discounting", "reference_name": self.name }) - for d in self.invoices: je.append("accounts", { "account": self.accounts_receivable_discounted, @@ -123,7 +122,7 @@ class InvoiceDiscounting(AccountsController): "party": d.customer }) - return je.as_dict() + return je def close_loan(self): je = frappe.new_doc("Journal Entry") @@ -163,7 +162,7 @@ class InvoiceDiscounting(AccountsController): "party": d.customer }) - return je.as_dict() + return je @frappe.whitelist() def get_invoices(filters): diff --git a/erpnext/accounts/doctype/invoice_discounting/test_invoice_discounting.py b/erpnext/accounts/doctype/invoice_discounting/test_invoice_discounting.py index 96e3991fc6..3e194484ab 100644 --- a/erpnext/accounts/doctype/invoice_discounting/test_invoice_discounting.py +++ b/erpnext/accounts/doctype/invoice_discounting/test_invoice_discounting.py @@ -4,12 +4,12 @@ from __future__ import unicode_literals import frappe -from frappe.utils import nowdate, add_days +from frappe.utils import nowdate, add_days, flt import unittest from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import get_gl_entries from erpnext.accounts.doctype.account.test_account import create_account - +from erpnext.accounts.doctype.journal_entry.journal_entry import get_payment_entry_against_invoice class TestInvoiceDiscounting(unittest.TestCase): def setUp(self): self.ar_credit = create_account(account_name="_Test Accounts Receivable Credit", parent_account = "Accounts Receivable - _TC") @@ -19,7 +19,6 @@ class TestInvoiceDiscounting(unittest.TestCase): self.bank_account = create_account(account_name="_Test Bank 2", parent_account = "Bank Accounts - _TC" ) self.bank_charges_account = create_account(account_name="_Test Bank Charges Account", parent_account = "Expenses - _TC") - def test_total_amount(self): inv1 = create_sales_invoice(rate=200) inv2 = create_sales_invoice(rate=500) @@ -70,8 +69,9 @@ class TestInvoiceDiscounting(unittest.TestCase): self.assertEqual(inv_disc.status, "Sanctioned") self.assertEqual(inv_disc.loan_end_date, add_days(inv_disc.loan_start_date, inv_disc.loan_period)) - '''def test_on_disbursed(self): - inv = create_sales_invoice(rate=300) + + def test_on_disbursed(self): + inv = create_sales_invoice(rate=500) inv_disc = create_invoice_discounting([inv.name], accounts_receivable_credit=self.ar_credit, accounts_receivable_discounted=self.ar_discounted, @@ -79,14 +79,149 @@ class TestInvoiceDiscounting(unittest.TestCase): short_term_loan=self.short_term_loan, bank_charges_account=self.bank_charges_account, bank_account=self.bank_account, - set_status='Disbursed' ) - gle = get_gl_entries("Invoice Discounting", inv_disc.name) - from pprint import pprint - pprint(gle)''' + je = inv_disc.create_disbursement_entry() + + self.assertEqual(je.accounts[0].account, self.bank_account) + self.assertEqual(je.accounts[0].debit_in_account_currency, flt(inv_disc.total_amount) - flt(inv_disc.bank_charges)) + + self.assertEqual(je.accounts[1].account, self.bank_charges_account) + self.assertEqual(je.accounts[1].debit_in_account_currency, flt(inv_disc.bank_charges)) + + self.assertEqual(je.accounts[2].account, self.short_term_loan) + self.assertEqual(je.accounts[2].credit_in_account_currency, flt(inv_disc.total_amount)) + + self.assertEqual(je.accounts[3].account, self.ar_discounted) + self.assertEqual(je.accounts[3].debit_in_account_currency, flt(inv.outstanding_amount)) + + self.assertEqual(je.accounts[4].account, self.ar_credit) + self.assertEqual(je.accounts[4].credit_in_account_currency, flt(inv.outstanding_amount)) + + + je.posting_date = nowdate() + je.submit() + + inv_disc.reload() + + self.assertEqual(inv_disc.status, "Disbursed") + + def test_on_close_after_loan_period(self): + inv = create_sales_invoice(rate=600) + inv_disc = create_invoice_discounting([inv.name], + accounts_receivable_credit=self.ar_credit, + accounts_receivable_discounted=self.ar_discounted, + accounts_receivable_unpaid=self.ar_unpaid, + short_term_loan=self.short_term_loan, + bank_charges_account=self.bank_charges_account, + bank_account=self.bank_account, + start=nowdate(), + period=60 + ) + + inv_disc.create_disbursement_entry() + je = inv_disc.close_loan() + + self.assertEqual(je.accounts[0].account, self.short_term_loan) + self.assertEqual(je.accounts[0].debit_in_account_currency, flt(inv_disc.total_amount)) + + self.assertEqual(je.accounts[1].account, self.bank_account) + self.assertEqual(je.accounts[1].credit_in_account_currency, flt(inv_disc.total_amount)) + + self.assertEqual(je.accounts[2].account, self.ar_discounted) + self.assertEqual(je.accounts[2].credit_in_account_currency, flt(inv.outstanding_amount)) + + self.assertEqual(je.accounts[3].account, self.ar_unpaid) + self.assertEqual(je.accounts[3].debit_in_account_currency, flt(inv.outstanding_amount)) + + je.posting_date = nowdate() + je.submit() + inv_disc.reload() + + self.assertEqual(inv_disc.status, "Settled") + + def test_on_close_before_loan_period(self): + inv = create_sales_invoice(rate=700) + inv_disc = create_invoice_discounting([inv.name], + accounts_receivable_credit=self.ar_credit, + accounts_receivable_discounted=self.ar_discounted, + accounts_receivable_unpaid=self.ar_unpaid, + short_term_loan=self.short_term_loan, + bank_charges_account=self.bank_charges_account, + bank_account=self.bank_account, + start=add_days(nowdate(), -80), + period=60 + ) + + inv_disc.create_disbursement_entry() + je = inv_disc.close_loan() + + je.posting_date = nowdate() + je.submit() + + self.assertEqual(je.accounts[0].account, self.short_term_loan) + self.assertEqual(je.accounts[0].debit_in_account_currency, flt(inv_disc.total_amount)) + + self.assertEqual(je.accounts[1].account, self.bank_account) + self.assertEqual(je.accounts[1].credit_in_account_currency, flt(inv_disc.total_amount)) + + inv_disc.reload() + + self.assertEqual(inv_disc.status, "Settled") + + def test_make_payment_before_loan_period(self): + #it has problem + inv = create_sales_invoice(rate=700) + inv_disc = create_invoice_discounting([inv.name], + accounts_receivable_credit=self.ar_credit, + accounts_receivable_discounted=self.ar_discounted, + accounts_receivable_unpaid=self.ar_unpaid, + short_term_loan=self.short_term_loan, + bank_charges_account=self.bank_charges_account, + bank_account=self.bank_account + ) + je = inv_disc.create_disbursement_entry() + inv_disc.reload() + je.posting_date = nowdate() + je.submit() + + je_on_payment = get_payment_entry_against_invoice("Sales Invoice", inv.name) + + self.assertEqual(je_on_payment.accounts[0].account, self.ar_discounted) + self.assertEqual(je_on_payment.accounts[0].credit_in_account_currency, flt(inv.outstanding_amount)) + #self.assertEqual(je_on_payment.accounts[0].account, self.bank_account) + self.assertEqual(je_on_payment.accounts[1].debit_in_account_currency, flt(inv.outstanding_amount)) + + def test_make_payment_before_after_period(self): + #it has problem + inv = create_sales_invoice(rate=700) + inv_disc = create_invoice_discounting([inv.name], + accounts_receivable_credit=self.ar_credit, + accounts_receivable_discounted=self.ar_discounted, + accounts_receivable_unpaid=self.ar_unpaid, + short_term_loan=self.short_term_loan, + bank_charges_account=self.bank_charges_account, + bank_account=self.bank_account, + loan_start_date=add_days(nowdate(), -10), + period=5 + ) + je = inv_disc.create_disbursement_entry() + inv_disc.reload() + je.posting_date = nowdate() + je.submit() + + je = inv_disc.close_loan() + inv_disc.reload() + je.posting_date = nowdate() + je.submit() + + je_on_payment = get_payment_entry_against_invoice("Sales Invoice", inv.name) + + self.assertEqual(je_on_payment.accounts[0].account, self.ar_unpaid) + self.assertEqual(je_on_payment.accounts[0].credit_in_account_currency, flt(inv.outstanding_amount)) + #self.assertEqual(je_on_payment.accounts[0].account, self.bank_account) + self.assertEqual(je_on_payment.accounts[1].debit_in_account_currency, flt(inv.outstanding_amount)) - def test_on_invoice_payment def create_invoice_discounting(invoices, **args): args = frappe._dict(args) @@ -113,7 +248,4 @@ def create_invoice_discounting(invoices, **args): if not args.do_not_submit: inv_disc.submit() - if args.set_status: - inv_disc.status = args.set_status - return inv_disc From ed190bb32941758773ee1516c34adb9d7d98d416 Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Thu, 14 Mar 2019 17:46:59 +0530 Subject: [PATCH 05/12] fix: codacy --- .../invoice_discounting.js | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js index 872072c91d..e63bc50f3c 100644 --- a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js +++ b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js @@ -3,14 +3,14 @@ frappe.ui.form.on('Invoice Discounting', { setup: (frm) => { - frm.set_query("sales_invoice", "invoices", (doc, cdt, cdn) => { + frm.set_query("sales_invoice", "invoices", (doc) => { return { "filters": { "docstatus": 1, "company": doc.company, "outstanding_amount": [">", 0] } - } + }; }); frm.events.filter_accounts("bank_account", frm, {"account_type": "Bank"}); @@ -35,13 +35,13 @@ frappe.ui.form.on('Invoice Discounting', { refresh: (frm) => { frm.events.show_general_ledger(frm); - if(frm.doc.docstatus == 0) { + if(frm.doc.docstatus === 0) { frm.add_custom_button(__('Get Invoices'), function() { frm.events.get_invoices(frm); }); } - if(frm.doc.docstatus==1 && frm.doc.status != "Settled") { + if(frm.doc.docstatus === 1 && frm.doc.status !== "Settled") { if(frm.doc.status == "Sanctioned") { frm.add_custom_button(__('Disburse Loan'), function() { frm.events.create_disbursement_entry(frm); @@ -131,7 +131,7 @@ frappe.ui.form.on('Invoice Discounting', { $.each(r.message, function(i, v) { let row = frm.add_child("invoices"); $.extend(row, v); - }) + }); refresh_field("invoices"); } } @@ -148,11 +148,10 @@ frappe.ui.form.on('Invoice Discounting', { doc: frm.doc, callback: function(r) { if(!r.exc){ - var doc = frappe.model.sync(r.message); frappe.set_route("Form", r.message.doctype, r.message.name); } } - }) + }); }, @@ -162,11 +161,10 @@ frappe.ui.form.on('Invoice Discounting', { doc: frm.doc, callback: function(r) { if(!r.exc){ - var doc = frappe.model.sync(r.message); frappe.set_route("Form", r.message.doctype, r.message.name); } } - }) + }); }, @@ -187,10 +185,10 @@ frappe.ui.form.on('Invoice Discounting', { }); frappe.ui.form.on('Discounted Invoice', { - sales_invoice: (frm, cdt, cdn) => { + sales_invoice: (frm) => { frm.events.calculate_total_amount(frm); }, - invoices_remove: (frm, cdt, cdn) => { + invoices_remove: (frm) => { frm.events.calculate_total_amount(frm); } }); \ No newline at end of file From 78903b1e579b2e0f2e40191d9501ca2569efffe4 Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Tue, 26 Mar 2019 12:59:30 +0530 Subject: [PATCH 06/12] fix: test for invoice payment by setting default Bank Account --- .../doctype/invoice_discounting/test_invoice_discounting.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/invoice_discounting/test_invoice_discounting.py b/erpnext/accounts/doctype/invoice_discounting/test_invoice_discounting.py index 3e194484ab..92b0385364 100644 --- a/erpnext/accounts/doctype/invoice_discounting/test_invoice_discounting.py +++ b/erpnext/accounts/doctype/invoice_discounting/test_invoice_discounting.py @@ -18,6 +18,7 @@ class TestInvoiceDiscounting(unittest.TestCase): self.short_term_loan = create_account(account_name="_Test Short Term Loan", parent_account = "Source of Funds (Liabilities) - _TC") self.bank_account = create_account(account_name="_Test Bank 2", parent_account = "Bank Accounts - _TC" ) self.bank_charges_account = create_account(account_name="_Test Bank Charges Account", parent_account = "Expenses - _TC") + frappe.db.set_value("Company", "_Test Company", "default_bank_account", self.bank_account) def test_total_amount(self): inv1 = create_sales_invoice(rate=200) @@ -189,7 +190,7 @@ class TestInvoiceDiscounting(unittest.TestCase): self.assertEqual(je_on_payment.accounts[0].account, self.ar_discounted) self.assertEqual(je_on_payment.accounts[0].credit_in_account_currency, flt(inv.outstanding_amount)) - #self.assertEqual(je_on_payment.accounts[0].account, self.bank_account) + self.assertEqual(je_on_payment.accounts[1].account, self.bank_account) self.assertEqual(je_on_payment.accounts[1].debit_in_account_currency, flt(inv.outstanding_amount)) def test_make_payment_before_after_period(self): @@ -219,7 +220,7 @@ class TestInvoiceDiscounting(unittest.TestCase): self.assertEqual(je_on_payment.accounts[0].account, self.ar_unpaid) self.assertEqual(je_on_payment.accounts[0].credit_in_account_currency, flt(inv.outstanding_amount)) - #self.assertEqual(je_on_payment.accounts[0].account, self.bank_account) + self.assertEqual(je_on_payment.accounts[1].account, self.bank_account) self.assertEqual(je_on_payment.accounts[1].debit_in_account_currency, flt(inv.outstanding_amount)) From 702c6e00daf490bc23d9ab2b64bfb649d9b66117 Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Tue, 26 Mar 2019 16:00:43 +0530 Subject: [PATCH 07/12] fix: route on loan Disbursement and Closing --- .../doctype/invoice_discounting/invoice_discounting.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js index e63bc50f3c..328df4f813 100644 --- a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js +++ b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js @@ -148,7 +148,8 @@ frappe.ui.form.on('Invoice Discounting', { doc: frm.doc, callback: function(r) { if(!r.exc){ - frappe.set_route("Form", r.message.doctype, r.message.name); + var doclist = frappe.model.sync(r.message); + frappe.set_route("Form", doclist[0].doctype, doclist[0].name); } } }); @@ -161,7 +162,8 @@ frappe.ui.form.on('Invoice Discounting', { doc: frm.doc, callback: function(r) { if(!r.exc){ - frappe.set_route("Form", r.message.doctype, r.message.name); + var doclist = frappe.model.sync(r.message); + frappe.set_route("Form", doclist[0].doctype, doclist[0].name); } } }); From ca4117e652f9c651165d6dbc15d132256d316a9d Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Tue, 26 Mar 2019 16:03:00 +0530 Subject: [PATCH 08/12] feat: seting status and indicators on list view --- .../invoice_discounting_list.js | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 erpnext/accounts/doctype/invoice_discounting/invoice_discounting_list.js diff --git a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting_list.js b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting_list.js new file mode 100644 index 0000000000..a72023d8e1 --- /dev/null +++ b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting_list.js @@ -0,0 +1,21 @@ +frappe.listview_settings['Invoice Discounting'] = { + add_fields: ["status"], + get_indicator: function(doc) + { + if(doc.status == "Draft") { + return [__("Draft"), "red", "status,=,Draft"]; + } + else if(doc.status == "Sanctioned") { + return [__("Sanctioned"), "green", "status,=,Sanctioned"]; + } + else if(doc.status == "Disbursed") { + return [__("Disbursed"), "blue", "status,=,Disbursed"]; + } + else if(doc.status == "Settled") { + return [__("Settled"), "orange", "status,=,Settled"]; + } + else if(doc.status == "Canceled") { + return [__("Canceled"), "red", "status,=,Canceled"]; + } + } +}; \ No newline at end of file From 10c1db1b2831123f2c7c904c876b8de4bbb26f25 Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Tue, 26 Mar 2019 16:30:31 +0530 Subject: [PATCH 09/12] fix: removed empty row on getting invoices --- .../accounts/doctype/invoice_discounting/invoice_discounting.js | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js index 328df4f813..88cb939678 100644 --- a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js +++ b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js @@ -129,6 +129,7 @@ frappe.ui.form.on('Invoice Discounting', { if(!r.exc) { d.hide(); $.each(r.message, function(i, v) { + frm.doc.invoices = frm.doc.invoices.filter(row => row.sales_invoice); let row = frm.add_child("invoices"); $.extend(row, v); }); From accf310aa3af6d98a039ef9d2918aaf359668de5 Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Thu, 11 Apr 2019 11:08:07 +0530 Subject: [PATCH 10/12] fix: start date and loan period should be mandatory --- .../accounts/doctype/invoice_discounting/invoice_discounting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py index 7b1dcd4f3d..d1ed430829 100644 --- a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py +++ b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py @@ -20,7 +20,7 @@ class InvoiceDiscounting(AccountsController): self.loan_end_date = add_days(self.loan_start_date, self.loan_period) def validate_mandatory(self): - if self.docstatus == 1 and not (self.loan_start_date and self.loan_period): + if not (self.loan_start_date and self.loan_period): frappe.throw(_("Loan Start Date and Loan Period are mandatory to submit the Invoice Discounting")) def calculate_total_amount(self): From 4c29d80cf1260e58bf4c2d0a6e0805d88c070a78 Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Thu, 11 Apr 2019 11:09:57 +0530 Subject: [PATCH 11/12] fix: minor fixes --- .../accounts/doctype/invoice_discounting/invoice_discounting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py index d1ed430829..f5fc92cd68 100644 --- a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py +++ b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py @@ -21,7 +21,7 @@ class InvoiceDiscounting(AccountsController): def validate_mandatory(self): if not (self.loan_start_date and self.loan_period): - frappe.throw(_("Loan Start Date and Loan Period are mandatory to submit the Invoice Discounting")) + frappe.throw(_("Loan Start Date and Loan Period are mandatory to save the Invoice Discounting")) def calculate_total_amount(self): self.total_amount = sum([flt(d.outstanding_amount) for d in self.invoices]) From 076cc38c294c0b00196d93378961aecc382d9d76 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 15 Apr 2019 18:42:10 +0530 Subject: [PATCH 12/12] fix: Outstanding amount on making payment against discounted invoice --- erpnext/accounts/doctype/gl_entry/gl_entry.py | 11 ++++-- .../invoice_discounting.js | 2 +- .../invoice_discounting.py | 5 +-- .../test_invoice_discounting.py | 35 ++++++++++++++----- .../doctype/journal_entry/journal_entry.py | 6 +++- 5 files changed, 44 insertions(+), 15 deletions(-) diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py index e264467a5a..3ced9a39eb 100644 --- a/erpnext/accounts/doctype/gl_entry/gl_entry.py +++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py @@ -175,13 +175,20 @@ def update_outstanding_amt(account, party_type, party, against_voucher_type, aga else: party_condition = "" + if against_voucher_type == "Sales Invoice": + party_account = frappe.db.get_value(against_voucher_type, against_voucher, "debit_to") + account_condition = "and account in ({0}, {1})".format(frappe.db.escape(account), frappe.db.escape(party_account)) + else: + account_condition = " and account = {0}".format(frappe.db.escape(account)) + # get final outstanding amt bal = flt(frappe.db.sql(""" select sum(debit_in_account_currency) - sum(credit_in_account_currency) from `tabGL Entry` where against_voucher_type=%s and against_voucher=%s - and account = %s {0}""".format(party_condition), - (against_voucher_type, against_voucher, account))[0][0] or 0.0) + and voucher_type != 'Invoice Discounting' + {0} {1}""".format(party_condition, account_condition), + (against_voucher_type, against_voucher))[0][0] or 0.0) if against_voucher_type == 'Purchase Invoice': bal = -bal diff --git a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js index 88cb939678..5563f031bb 100644 --- a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js +++ b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js @@ -9,7 +9,7 @@ frappe.ui.form.on('Invoice Discounting', { "docstatus": 1, "company": doc.company, "outstanding_amount": [">", 0] - } + }, }; }); diff --git a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py index f5fc92cd68..64aa4e4af6 100644 --- a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py +++ b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py @@ -17,10 +17,11 @@ class InvoiceDiscounting(AccountsController): self.set_end_date() def set_end_date(self): - self.loan_end_date = add_days(self.loan_start_date, self.loan_period) + if self.loan_start_date and self.loan_period: + self.loan_end_date = add_days(self.loan_start_date, self.loan_period) def validate_mandatory(self): - if not (self.loan_start_date and self.loan_period): + if self.docstatus == 1 and not (self.loan_start_date and self.loan_period): frappe.throw(_("Loan Start Date and Loan Period are mandatory to save the Invoice Discounting")) def calculate_total_amount(self): diff --git a/erpnext/accounts/doctype/invoice_discounting/test_invoice_discounting.py b/erpnext/accounts/doctype/invoice_discounting/test_invoice_discounting.py index 92b0385364..4f93e11def 100644 --- a/erpnext/accounts/doctype/invoice_discounting/test_invoice_discounting.py +++ b/erpnext/accounts/doctype/invoice_discounting/test_invoice_discounting.py @@ -12,12 +12,12 @@ from erpnext.accounts.doctype.account.test_account import create_account from erpnext.accounts.doctype.journal_entry.journal_entry import get_payment_entry_against_invoice class TestInvoiceDiscounting(unittest.TestCase): def setUp(self): - self.ar_credit = create_account(account_name="_Test Accounts Receivable Credit", parent_account = "Accounts Receivable - _TC") - self.ar_discounted = create_account(account_name="_Test Accounts Receivable Discounted", parent_account = "Accounts Receivable - _TC") - self.ar_unpaid = create_account(account_name="_Test Accounts Receivable Unpaid", parent_account = "Accounts Receivable - _TC") - self.short_term_loan = create_account(account_name="_Test Short Term Loan", parent_account = "Source of Funds (Liabilities) - _TC") - self.bank_account = create_account(account_name="_Test Bank 2", parent_account = "Bank Accounts - _TC" ) - self.bank_charges_account = create_account(account_name="_Test Bank Charges Account", parent_account = "Expenses - _TC") + self.ar_credit = create_account(account_name="_Test Accounts Receivable Credit", parent_account = "Accounts Receivable - _TC", company="_Test Company") + self.ar_discounted = create_account(account_name="_Test Accounts Receivable Discounted", parent_account = "Accounts Receivable - _TC", company="_Test Company") + self.ar_unpaid = create_account(account_name="_Test Accounts Receivable Unpaid", parent_account = "Accounts Receivable - _TC", company="_Test Company") + self.short_term_loan = create_account(account_name="_Test Short Term Loan", parent_account = "Source of Funds (Liabilities) - _TC", company="_Test Company") + self.bank_account = create_account(account_name="_Test Bank 2", parent_account = "Bank Accounts - _TC", company="_Test Company") + self.bank_charges_account = create_account(account_name="_Test Bank Charges Account", parent_account = "Expenses - _TC", company="_Test Company") frappe.db.set_value("Company", "_Test Company", "default_bank_account", self.bank_account) def test_total_amount(self): @@ -104,9 +104,11 @@ class TestInvoiceDiscounting(unittest.TestCase): je.submit() inv_disc.reload() - self.assertEqual(inv_disc.status, "Disbursed") + inv.reload() + self.assertEqual(inv.outstanding_amount, 500) + def test_on_close_after_loan_period(self): inv = create_sales_invoice(rate=600) inv_disc = create_invoice_discounting([inv.name], @@ -186,13 +188,21 @@ class TestInvoiceDiscounting(unittest.TestCase): je.posting_date = nowdate() je.submit() - je_on_payment = get_payment_entry_against_invoice("Sales Invoice", inv.name) + je_on_payment = frappe.get_doc(get_payment_entry_against_invoice("Sales Invoice", inv.name)) + je_on_payment.posting_date = nowdate() + je_on_payment.cheque_no = "126981" + je_on_payment.cheque_date = nowdate() + je_on_payment.save() + je_on_payment.submit() self.assertEqual(je_on_payment.accounts[0].account, self.ar_discounted) self.assertEqual(je_on_payment.accounts[0].credit_in_account_currency, flt(inv.outstanding_amount)) self.assertEqual(je_on_payment.accounts[1].account, self.bank_account) self.assertEqual(je_on_payment.accounts[1].debit_in_account_currency, flt(inv.outstanding_amount)) + inv.reload() + self.assertEqual(inv.outstanding_amount, 0) + def test_make_payment_before_after_period(self): #it has problem inv = create_sales_invoice(rate=700) @@ -216,13 +226,20 @@ class TestInvoiceDiscounting(unittest.TestCase): je.posting_date = nowdate() je.submit() - je_on_payment = get_payment_entry_against_invoice("Sales Invoice", inv.name) + je_on_payment = frappe.get_doc(get_payment_entry_against_invoice("Sales Invoice", inv.name)) + je_on_payment.posting_date = nowdate() + je_on_payment.cheque_no = "126981" + je_on_payment.cheque_date = nowdate() + je_on_payment.submit() self.assertEqual(je_on_payment.accounts[0].account, self.ar_unpaid) self.assertEqual(je_on_payment.accounts[0].credit_in_account_currency, flt(inv.outstanding_amount)) self.assertEqual(je_on_payment.accounts[1].account, self.bank_account) self.assertEqual(je_on_payment.accounts[1].debit_in_account_currency, flt(inv.outstanding_amount)) + inv.reload() + self.assertEqual(inv.outstanding_amount, 0) + def create_invoice_discounting(invoices, **args): args = frappe._dict(args) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index d3f75f65f1..28869d86d9 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -259,7 +259,11 @@ class JournalEntry(AccountsController): # check if party and account match if d.reference_type in ("Sales Invoice", "Purchase Invoice"): - if (against_voucher[0] != d.party or against_voucher[1] != d.account): + if d.reference_type == "Sales Invoice": + party_account = get_party_account_based_on_invoice_discounting(d.reference_name) or against_voucher[1] + else: + party_account = against_voucher[1] + if (against_voucher[0] != d.party or party_account != d.account): frappe.throw(_("Row {0}: Party / Account does not match with {1} / {2} in {3} {4}") .format(d.idx, field_dict.get(d.reference_type)[0], field_dict.get(d.reference_type)[1], d.reference_type, d.reference_name))