Merge pull request #23243 from Anurag810/overlap_for_additional_salary
feat: Overlap validation additional salary
diff --git a/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py b/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py
index 0fe57c3..2754633 100644
--- a/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py
+++ b/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py
@@ -91,15 +91,11 @@
self.assertEqual(frappe.db.get_value("Bank Transaction", bank_transaction.name, "unallocated_amount"), 0)
self.assertTrue(frappe.db.get_value("Sales Invoice Payment", dict(parent=payment.name), "clearance_date") is not None)
-def add_transactions():
- if frappe.flags.test_bank_transactions_created:
- return
-
- frappe.set_user("Administrator")
+def create_bank_account(bank_name="Citi Bank", account_name="_Test Bank - _TC"):
try:
frappe.get_doc({
"doctype": "Bank",
- "bank_name":"Citi Bank",
+ "bank_name":bank_name,
}).insert()
except frappe.DuplicateEntryError:
pass
@@ -108,12 +104,19 @@
frappe.get_doc({
"doctype": "Bank Account",
"account_name":"Checking Account",
- "bank": "Citi Bank",
- "account": "_Test Bank - _TC"
+ "bank": bank_name,
+ "account": account_name
}).insert()
except frappe.DuplicateEntryError:
pass
+def add_transactions():
+ if frappe.flags.test_bank_transactions_created:
+ return
+
+ frappe.set_user("Administrator")
+ create_bank_account()
+
doc = frappe.get_doc({
"doctype": "Bank Transaction",
"description":"1512567 BG/000002918 OPSKATTUZWXXX AT776000000098709837 Herr G",
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index 842c64f..bb312bf 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -1172,30 +1172,23 @@
from frappe.model.mapper import get_mapped_doc
def set_missing_values(source, target):
target.payment_order_type = "Payment Entry"
+ target.append('references', dict(
+ reference_doctype="Payment Entry",
+ reference_name=source.name,
+ bank_account=source.party_bank_account,
+ amount=source.paid_amount,
+ account=source.paid_to,
+ supplier=source.party,
+ mode_of_payment=source.mode_of_payment,
+ ))
- def update_item(source_doc, target_doc, source_parent):
- target_doc.bank_account = source_parent.party_bank_account
- target_doc.amount = source_doc.allocated_amount
- target_doc.account = source_parent.paid_to
- target_doc.payment_entry = source_parent.name
- target_doc.supplier = source_parent.party
- target_doc.mode_of_payment = source_parent.mode_of_payment
-
-
- doclist = get_mapped_doc("Payment Entry", source_name, {
+ doclist = get_mapped_doc("Payment Entry", source_name, {
"Payment Entry": {
"doctype": "Payment Order",
"validation": {
"docstatus": ["=", 1]
- }
- },
- "Payment Entry Reference": {
- "doctype": "Payment Order Reference",
- "validation": {
- "docstatus": ["=", 1]
},
- "postprocess": update_item
- },
+ }
}, target_doc, set_missing_values)
diff --git a/erpnext/accounts/doctype/payment_order/payment_order.py b/erpnext/accounts/doctype/payment_order/payment_order.py
index e5880aa..8d29ae7 100644
--- a/erpnext/accounts/doctype/payment_order/payment_order.py
+++ b/erpnext/accounts/doctype/payment_order/payment_order.py
@@ -21,10 +21,15 @@
if cancel:
status = 'Initiated'
- ref_field = "status" if self.payment_order_type == "Payment Request" else "payment_order_status"
+ if self.payment_order_type == "Payment Request":
+ ref_field = "status"
+ ref_doc_field = frappe.scrub(self.payment_order_type)
+ else:
+ ref_field = "payment_order_status"
+ ref_doc_field = "reference_name"
for d in self.references:
- frappe.db.set_value(self.payment_order_type, d.get(frappe.scrub(self.payment_order_type)), ref_field, status)
+ frappe.db.set_value(self.payment_order_type, d.get(ref_doc_field), ref_field, status)
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
diff --git a/erpnext/accounts/doctype/payment_order/test_payment_order.py b/erpnext/accounts/doctype/payment_order/test_payment_order.py
index 711c4cc..1c23e2a 100644
--- a/erpnext/accounts/doctype/payment_order/test_payment_order.py
+++ b/erpnext/accounts/doctype/payment_order/test_payment_order.py
@@ -5,6 +5,45 @@
import frappe
import unittest
+from frappe.utils import getdate
+from erpnext.accounts.doctype.bank_transaction.test_bank_transaction import create_bank_account
+from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry, make_payment_order
+from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
class TestPaymentOrder(unittest.TestCase):
- pass
+ def setUp(self):
+ create_bank_account()
+
+ def tearDown(self):
+ for bt in frappe.get_all("Payment Order"):
+ doc = frappe.get_doc("Payment Order", bt.name)
+ doc.cancel()
+ doc.delete()
+
+ def test_payment_order_creation_against_payment_entry(self):
+ purchase_invoice = make_purchase_invoice()
+ payment_entry = get_payment_entry("Purchase Invoice", purchase_invoice.name, bank_account="_Test Bank - _TC")
+ payment_entry.reference_no = "_Test_Payment_Order"
+ payment_entry.reference_date = getdate()
+ payment_entry.party_bank_account = "Checking Account - Citi Bank"
+ payment_entry.insert()
+ payment_entry.submit()
+
+ doc = create_payment_order_against_payment_entry(payment_entry, "Payment Entry")
+ reference_doc = doc.get("references")[0]
+ self.assertEquals(reference_doc.reference_name, payment_entry.name)
+ self.assertEquals(reference_doc.reference_doctype, "Payment Entry")
+ self.assertEquals(reference_doc.supplier, "_Test Supplier")
+ self.assertEquals(reference_doc.amount, 250)
+
+def create_payment_order_against_payment_entry(ref_doc, order_type):
+ payment_order = frappe.get_doc(dict(
+ doctype="Payment Order",
+ company="_Test Company",
+ payment_order_type=order_type,
+ company_bank_account="Checking Account - Citi Bank"
+ ))
+ doc = make_payment_order(ref_doc.name, payment_order)
+ doc.save()
+ doc.submit()
+ return doc
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/payment_order_reference/payment_order_reference.json b/erpnext/accounts/doctype/payment_order_reference/payment_order_reference.json
index db0b761..d94ba74 100644
--- a/erpnext/accounts/doctype/payment_order_reference/payment_order_reference.json
+++ b/erpnext/accounts/doctype/payment_order_reference/payment_order_reference.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"creation": "2018-07-20 16:38:06.630813",
"doctype": "DocType",
"editable_grid": 1,
@@ -10,7 +11,6 @@
"column_break_4",
"supplier",
"payment_request",
- "payment_entry",
"mode_of_payment",
"bank_account_details",
"bank_account",
@@ -103,17 +103,12 @@
"no_copy": 1,
"print_hide": 1,
"read_only": 1
- },
- {
- "fieldname": "payment_entry",
- "fieldtype": "Link",
- "label": "Payment Entry",
- "options": "Payment Entry",
- "read_only": 1
}
],
+ "index_web_pages_for_search": 1,
"istable": 1,
- "modified": "2019-05-08 13:56:25.724557",
+ "links": [],
+ "modified": "2020-09-04 08:29:51.014390",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Order Reference",
diff --git a/erpnext/accounts/doctype/process_deferred_accounting/process_deferred_accounting.js b/erpnext/accounts/doctype/process_deferred_accounting/process_deferred_accounting.js
index 2800c19..1ec6805 100644
--- a/erpnext/accounts/doctype/process_deferred_accounting/process_deferred_accounting.js
+++ b/erpnext/accounts/doctype/process_deferred_accounting/process_deferred_accounting.js
@@ -10,13 +10,15 @@
}
};
});
+ },
- if (frm.doc.company) {
+ type: function(frm) {
+ if (frm.doc.company && frm.doc.type) {
frm.set_query("account", function() {
return {
filters: {
'company': frm.doc.company,
- 'root_type': 'Liability',
+ 'root_type': frm.doc.type === 'Income' ? 'Liability' : 'Asset',
'is_group': 0
}
};
diff --git a/erpnext/accounts/doctype/process_deferred_accounting/process_deferred_accounting.json b/erpnext/accounts/doctype/process_deferred_accounting/process_deferred_accounting.json
index 4daafef..457e98c 100644
--- a/erpnext/accounts/doctype/process_deferred_accounting/process_deferred_accounting.json
+++ b/erpnext/accounts/doctype/process_deferred_accounting/process_deferred_accounting.json
@@ -60,6 +60,7 @@
"reqd": 1
},
{
+ "depends_on": "eval: doc.type",
"fieldname": "account",
"fieldtype": "Link",
"label": "Account",
@@ -73,9 +74,10 @@
"reqd": 1
}
],
+ "index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2020-02-06 18:18:09.852844",
+ "modified": "2020-09-03 18:07:02.463754",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Process Deferred Accounting",
diff --git a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
index 219871b..d011689 100644
--- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
+++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
@@ -256,7 +256,7 @@
"""accumulate children's values in parent accounts"""
for d in reversed(accounts):
if d.parent_account:
- account = d.parent_account.split('-')[0].strip()
+ account = d.parent_account.split(' - ')[0].strip()
if not accounts_by_name.get(account):
continue
diff --git a/erpnext/hr/doctype/attendance/attendance.py b/erpnext/hr/doctype/attendance/attendance.py
index 45b7060..373b940 100644
--- a/erpnext/hr/doctype/attendance/attendance.py
+++ b/erpnext/hr/doctype/attendance/attendance.py
@@ -98,7 +98,8 @@
e = {
"name": d.name,
"doctype": "Attendance",
- "date": d.attendance_date,
+ "start": d.attendance_date,
+ "end": d.attendance_date,
"title": cstr(d.status),
"docstatus": d.docstatus
}
diff --git a/erpnext/hr/doctype/attendance/attendance_calendar.js b/erpnext/hr/doctype/attendance/attendance_calendar.js
index 104f09d..4566489 100644
--- a/erpnext/hr/doctype/attendance/attendance_calendar.js
+++ b/erpnext/hr/doctype/attendance/attendance_calendar.js
@@ -1,12 +1,6 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.views.calendar["Attendance"] = {
- field_map: {
- "start": "attendance_date",
- "end": "attendance_date",
- "id": "name",
- "docstatus": 1
- },
options: {
header: {
left: 'prev,next today',
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
index a5ac3f3..4abba5f 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
@@ -1,5 +1,4 @@
{
- "actions": [],
"creation": "2019-05-09 15:47:39.760406",
"doctype": "DocType",
"engine": "InnoDB",
@@ -54,6 +53,7 @@
{
"fieldname": "transaction_type",
"fieldtype": "Link",
+ "in_standard_filter": 1,
"label": "Transaction Type",
"options": "DocType"
},
@@ -109,9 +109,9 @@
}
],
"in_create": 1,
+ "index_web_pages_for_search": 1,
"is_submittable": 1,
- "links": [],
- "modified": "2020-02-27 14:40:10.502605",
+ "modified": "2020-09-04 12:16:36.569066",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Ledger Entry",
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry_list.js b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry_list.js
new file mode 100644
index 0000000..889325b
--- /dev/null
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry_list.js
@@ -0,0 +1,13 @@
+frappe.listview_settings['Leave Ledger Entry'] = {
+ onload: function(listview) {
+ if(listview.page.fields_dict.transaction_type) {
+ listview.page.fields_dict.transaction_type.get_query = function() {
+ return {
+ "filters": {
+ "name": ["in", ["Leave Allocation", "Leave Application", "Leave Encashment"]],
+ }
+ };
+ };
+ }
+ }
+};
diff --git a/erpnext/hr/doctype/shift_assignment/shift_assignment.py b/erpnext/hr/doctype/shift_assignment/shift_assignment.py
index f8b7334..2c385e8 100644
--- a/erpnext/hr/doctype/shift_assignment/shift_assignment.py
+++ b/erpnext/hr/doctype/shift_assignment/shift_assignment.py
@@ -103,7 +103,7 @@
"doctype": "Shift Assignment",
"start_date": d.start_date,
"end_date": d.end_date if d.end_date else nowdate(),
- "title": cstr(d.employee_name) + \
+ "title": cstr(d.employee_name) + ": "+ \
cstr(d.shift_type),
"docstatus": d.docstatus
}
diff --git a/erpnext/loan_management/doctype/loan/loan.js b/erpnext/loan_management/doctype/loan/loan.js
index ffef60b..9b4c217 100644
--- a/erpnext/loan_management/doctype/loan/loan.js
+++ b/erpnext/loan_management/doctype/loan/loan.js
@@ -73,8 +73,8 @@
loan_type: function(frm) {
frm.toggle_reqd("repayment_method", frm.doc.is_term_loan);
- frm.toggle_display("repayment_method", 1 - frm.doc.is_term_loan);
- frm.toggle_display("repayment_periods", s1 - frm.doc.is_term_loan);
+ frm.toggle_display("repayment_method", frm.doc.is_term_loan);
+ frm.toggle_display("repayment_periods", frm.doc.is_term_loan);
},
@@ -119,12 +119,10 @@
create_loan_security_unpledge: function(frm) {
frappe.call({
- method: "erpnext.loan_management.doctype.loan.loan.create_loan_security_unpledge",
+ method: "erpnext.loan_management.doctype.loan.loan.unpledge_security",
args : {
"loan": frm.doc.name,
- "applicant_type": frm.doc.applicant_type,
- "applicant": frm.doc.applicant,
- "company": frm.doc.company
+ "as_dict": 1
},
callback: function(r) {
if (r.message)
diff --git a/erpnext/loan_management/doctype/loan/loan.py b/erpnext/loan_management/doctype/loan/loan.py
index e20b484..d1b7589 100644
--- a/erpnext/loan_management/doctype/loan/loan.py
+++ b/erpnext/loan_management/doctype/loan/loan.py
@@ -7,7 +7,7 @@
import erpnext
from frappe import _
from frappe.utils import flt, rounded, add_months, nowdate, getdate, now_datetime
-
+from erpnext.loan_management.doctype.loan_security_unpledge.loan_security_unpledge import get_pledged_security_qty
from erpnext.controllers.accounts_controller import AccountsController
class Loan(AccountsController):
@@ -223,30 +223,56 @@
return repayment_entry
@frappe.whitelist()
-def create_loan_security_unpledge(loan, applicant_type, applicant, company, as_dict=1):
- loan_security_pledge_details = frappe.db.sql("""
- SELECT p.loan_security, sum(p.qty) as qty
- FROM `tabLoan Security Pledge` lsp , `tabPledge` p
- WHERE p.parent = lsp.name AND lsp.loan = %s AND lsp.docstatus = 1
- GROUP BY p.loan_security
- """,(loan), as_dict=1)
+def unpledge_security(loan=None, loan_security_pledge=None, as_dict=0, save=0, submit=0, approve=0):
+ # if loan is passed it will be considered as full unpledge
+ if loan:
+ pledge_qty_map = get_pledged_security_qty(loan)
+ loan_doc = frappe.get_doc('Loan', loan)
+ unpledge_request = create_loan_security_unpledge(pledge_qty_map, loan_doc.name, loan_doc.company,
+ loan_doc.applicant_type, loan_doc.applicant)
+ # will unpledge qty based on loan security pledge
+ elif loan_security_pledge:
+ security_map = {}
+ pledge_doc = frappe.get_doc('Loan Security Pledge', loan_security_pledge)
+ for security in pledge_doc.securities:
+ security_map.setdefault(security.loan_security, security.qty)
+ unpledge_request = create_loan_security_unpledge(security_map, pledge_doc.loan,
+ pledge_doc.company, pledge_doc.applicant_type, pledge_doc.applicant)
+
+ if save:
+ unpledge_request.save()
+
+ if submit:
+ unpledge_request.submit()
+
+ if approve:
+ if unpledge_request.docstatus == 1:
+ unpledge_request.status = 'Approved'
+ unpledge_request.save()
+ else:
+ frappe.throw(_('Only submittted unpledge requests can be approved'))
+
+ if as_dict:
+ return unpledge_request
+ else:
+ return unpledge_request
+
+def create_loan_security_unpledge(unpledge_map, loan, company, applicant_type, applicant):
unpledge_request = frappe.new_doc("Loan Security Unpledge")
unpledge_request.applicant_type = applicant_type
unpledge_request.applicant = applicant
unpledge_request.loan = loan
unpledge_request.company = company
- for loan_security in loan_security_pledge_details:
- unpledge_request.append('securities', {
- "loan_security": loan_security.loan_security,
- "qty": loan_security.qty
- })
+ for security, qty in unpledge_map.items():
+ if qty:
+ unpledge_request.append('securities', {
+ "loan_security": security,
+ "qty": qty
+ })
- if as_dict:
- return unpledge_request.as_dict()
- else:
- return unpledge_request
+ return unpledge_request
diff --git a/erpnext/loan_management/doctype/loan/test_loan.py b/erpnext/loan_management/doctype/loan/test_loan.py
index 2f6cd25..f225409 100644
--- a/erpnext/loan_management/doctype/loan/test_loan.py
+++ b/erpnext/loan_management/doctype/loan/test_loan.py
@@ -14,7 +14,7 @@
process_loan_interest_accrual_for_term_loans)
from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import days_in_year
from erpnext.loan_management.doctype.process_loan_security_shortfall.process_loan_security_shortfall import create_process_loan_security_shortfall
-from erpnext.loan_management.doctype.loan.loan import create_loan_security_unpledge
+from erpnext.loan_management.doctype.loan.loan import unpledge_security
from erpnext.loan_management.doctype.loan_security_unpledge.loan_security_unpledge import get_pledged_security_qty
from erpnext.loan_management.doctype.loan_application.loan_application import create_pledge
from erpnext.loan_management.doctype.loan_disbursement.loan_disbursement import get_disbursal_amount
@@ -199,10 +199,9 @@
"Loan Closure", flt(loan.loan_amount + accrued_interest_amount))
repayment_entry.submit()
- amounts = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['paid_interest_amount',
- 'paid_principal_amount'])
+ amount = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['sum(paid_interest_amount)'])
- self.assertEquals(flt(amounts[0], 2),flt(accrued_interest_amount, 2))
+ self.assertEquals(flt(amount, 2),flt(accrued_interest_amount, 2))
self.assertEquals(flt(repayment_entry.penalty_amount, 5), 0)
loan.load_from_db()
@@ -307,7 +306,7 @@
loan.load_from_db()
self.assertEquals(loan.status, "Loan Closure Requested")
- unpledge_request = create_loan_security_unpledge(loan.name, loan.applicant_type, loan.applicant, loan.company, as_dict=0)
+ unpledge_request = unpledge_security(loan=loan.name, save=1)
unpledge_request.submit()
unpledge_request.status = 'Approved'
unpledge_request.save()
diff --git a/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py b/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py
index 1d3fa71..2d959bf 100644
--- a/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py
+++ b/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py
@@ -213,7 +213,8 @@
WHERE loan = %s""", (loan.name))
if last_posting_date[0][0]:
- return last_posting_date[0][0]
+ # interest for last interest accrual date is already booked, so add 1 day
+ return add_days(last_posting_date[0][0], 1)
else:
return loan.disbursement_date
diff --git a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
index 7d83e32..47fb885 100644
--- a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
+++ b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
@@ -13,6 +13,7 @@
from erpnext.controllers.accounts_controller import AccountsController
from erpnext.accounts.general_ledger import make_gl_entries
from erpnext.loan_management.doctype.loan_security_shortfall.loan_security_shortfall import update_shortfall_status
+from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_demand_loans
class LoanRepayment(AccountsController):
@@ -22,6 +23,9 @@
self.validate_amount()
self.allocate_amounts(amounts['pending_accrual_entries'])
+ def before_submit(self):
+ self.book_unaccrued_interest()
+
def on_submit(self):
self.update_paid_amount()
self.make_gl_entries()
@@ -72,6 +76,26 @@
msg = _("Amount of {0} is required for Loan closure").format(self.payable_amount)
frappe.throw(msg)
+ def book_unaccrued_interest(self):
+ if self.payment_type == 'Loan Closure':
+ total_interest_paid = 0
+ for payment in self.repayment_details:
+ total_interest_paid += payment.paid_interest_amount
+
+ if total_interest_paid < self.interest_payable:
+ if not self.is_term_loan:
+ process = process_loan_interest_accrual_for_demand_loans(posting_date=self.posting_date,
+ loan=self.against_loan)
+
+ lia = frappe.db.get_value('Loan Interest Accrual', {'process_loan_interest_accrual':
+ process}, ['name', 'interest_amount', 'payable_principal_amount'], as_dict=1)
+
+ self.append('repayment_details', {
+ 'loan_interest_accrual': lia.name,
+ 'paid_interest_amount': lia.interest_amount,
+ 'paid_principal_amount': lia.payable_principal_amount
+ })
+
def update_paid_amount(self):
precision = cint(frappe.db.get_default("currency_precision")) or 2
@@ -148,8 +172,6 @@
if self.payment_type == 'Loan Closure' and total_interest_paid < self.interest_payable:
unaccrued_interest = self.interest_payable - total_interest_paid
interest_paid -= unaccrued_interest
- if self.repayment_details:
- self.repayment_details[-1].paid_interest_amount += unaccrued_interest
if interest_paid:
self.principal_amount_paid += interest_paid
diff --git a/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.json b/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.json
index 4572e99..7dd5725 100644
--- a/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.json
+++ b/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.json
@@ -21,6 +21,10 @@
"total_security_value",
"column_break_11",
"maximum_loan_value",
+ "more_information_section",
+ "reference_no",
+ "column_break_18",
+ "description",
"amended_from"
],
"fields": [
@@ -129,11 +133,34 @@
"label": "Applicant Type",
"options": "Employee\nMember\nCustomer",
"reqd": 1
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "more_information_section",
+ "fieldtype": "Section Break",
+ "label": "More Information"
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "reference_no",
+ "fieldtype": "Data",
+ "label": "Reference No"
+ },
+ {
+ "fieldname": "column_break_18",
+ "fieldtype": "Column Break"
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "description",
+ "fieldtype": "Text",
+ "label": "Description"
}
],
+ "index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2020-07-02 23:38:24.002382",
+ "modified": "2020-09-04 22:38:19.894488",
"modified_by": "Administrator",
"module": "Loan Management",
"name": "Loan Security Pledge",
diff --git a/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.json b/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.json
index aece46f..2e2b251 100644
--- a/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.json
+++ b/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.json
@@ -16,6 +16,10 @@
"status",
"loan_security_details_section",
"securities",
+ "more_information_section",
+ "reference_no",
+ "column_break_13",
+ "description",
"amended_from"
],
"fields": [
@@ -95,11 +99,34 @@
"label": "Applicant Type",
"options": "Employee\nMember\nCustomer",
"reqd": 1
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "more_information_section",
+ "fieldtype": "Section Break",
+ "label": "More Information"
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "reference_no",
+ "fieldtype": "Data",
+ "label": "Reference No"
+ },
+ {
+ "fieldname": "column_break_13",
+ "fieldtype": "Column Break"
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "description",
+ "fieldtype": "Text",
+ "label": "Description"
}
],
+ "index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2020-05-05 07:23:18.440058",
+ "modified": "2020-09-04 22:39:57.756146",
"modified_by": "Administrator",
"module": "Loan Management",
"name": "Loan Security Unpledge",
diff --git a/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.py b/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.py
index f6b28da..b3eb600 100644
--- a/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.py
+++ b/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.py
@@ -17,7 +17,6 @@
self.validate_unpledge_qty()
def on_cancel(self):
- self.update_loan_security_pledge(cancel=1)
self.update_loan_status(cancel=1)
self.db_set('status', 'Requested')
@@ -50,8 +49,7 @@
security_value = 0
for security in self.securities:
- pledged_qty = pledge_qty_map.get(security.loan_security)
-
+ pledged_qty = pledge_qty_map.get(security.loan_security, 0)
if security.qty > pledged_qty:
frappe.throw(_("""Row {0}: {1} {2} of {3} is pledged against Loan {4}.
You are trying to unpledge more""").format(security.idx, pledged_qty, security.uom,
@@ -60,16 +58,23 @@
qty_after_unpledge = pledged_qty - security.qty
ltv_ratio = ltv_ratio_map.get(security.loan_security_type)
- security_value += qty_after_unpledge * loan_security_price_map.get(security.loan_security)
+ current_price = loan_security_price_map.get(security.loan_security)
+ if not current_price:
+ frappe.throw(_("No valid Loan Security Price found for {0}").format(frappe.bold(security.loan_security)))
+
+ security_value += qty_after_unpledge * current_price
if not security_value and flt(pending_principal_amount, 2) > 0:
frappe.throw("Cannot Unpledge, loan to value ratio is breaching")
- if security_value and (pending_principal_amount/security_value) * 100 > ltv_ratio:
+ if security_value and flt(pending_principal_amount/security_value) * 100 > ltv_ratio:
frappe.throw("Cannot Unpledge, loan to value ratio is breaching")
def on_update_after_submit(self):
- if self.status == "Approved":
+ self.approve()
+
+ def approve(self):
+ if self.status == "Approved" and not self.unpledge_time:
self.update_loan_status()
self.db_set('unpledge_time', get_datetime())
diff --git a/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.py b/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.py
index cd3cf7e..0fa9686 100644
--- a/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.py
+++ b/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.py
@@ -36,6 +36,8 @@
loan_process.submit()
+ return loan_process.name
+
def process_loan_interest_accrual_for_term_loans(posting_date=None, loan_type=None, loan=None):
if not term_loan_accrual_pending(posting_date or nowdate()):
@@ -49,6 +51,8 @@
loan_process.submit()
+ return loan_process.name
+
def term_loan_accrual_pending(date):
pending_accrual = frappe.db.get_value('Repayment Schedule', {
'payment_date': ('<=', date),
diff --git a/erpnext/non_profit/doctype/member/member.py b/erpnext/non_profit/doctype/member/member.py
index 797736a..44b975e 100644
--- a/erpnext/non_profit/doctype/member/member.py
+++ b/erpnext/non_profit/doctype/member/member.py
@@ -158,7 +158,7 @@
return subscription
-@frappe.whitelist(allow_guest=True)
+@frappe.whitelist()
def register_member(fullname, email, rzpay_plan_id, subscription_id, pan=None, mobile=None):
plan = get_membership_type(rzpay_plan_id)
if not plan:
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 771babe..aa7996e 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -632,7 +632,7 @@
execute:frappe.reload_doc('desk', 'doctype', 'dashboard_chart')
execute:frappe.reload_doc('desk', 'doctype', 'dashboard_chart_field')
erpnext.patches.v12_0.remove_bank_remittance_custom_fields
-erpnext.patches.v12_0.generate_leave_ledger_entries
+erpnext.patches.v12_0.generate_leave_ledger_entries #27-08-2020
execute:frappe.delete_doc_if_exists("Report", "Loan Repayment")
erpnext.patches.v12_0.move_credit_limit_to_customer_credit_limit
erpnext.patches.v12_0.add_variant_of_in_item_attribute_table
diff --git a/erpnext/patches/v12_0/generate_leave_ledger_entries.py b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
index c5bec19..342c129 100644
--- a/erpnext/patches/v12_0/generate_leave_ledger_entries.py
+++ b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
@@ -36,8 +36,7 @@
for allocation in allocation_list:
if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Allocation', 'transaction_name': allocation.name}):
- allocation.update(dict(doctype="Leave Allocation"))
- allocation_obj = frappe.get_doc(allocation)
+ allocation_obj = frappe.get_doc("Leave Allocation", allocation)
allocation_obj.create_leave_ledger_entry()
def generate_application_leave_ledger_entries():
@@ -46,8 +45,7 @@
for application in leave_applications:
if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Application', 'transaction_name': application.name}):
- application.update(dict(doctype="Leave Application"))
- frappe.get_doc(application).create_leave_ledger_entry()
+ frappe.get_doc("Leave Application", application.name).create_leave_ledger_entry()
def generate_encashment_leave_ledger_entries():
''' fix ledger entries for missing leave encashment transaction '''
@@ -55,8 +53,7 @@
for encashment in leave_encashments:
if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Encashment', 'transaction_name': encashment.name}):
- encashment.update(dict(doctype="Leave Encashment"))
- frappe.get_doc(encashment).create_leave_ledger_entry()
+ frappe.get_doc("Leave Enchashment", encashment).create_leave_ledger_entry()
def generate_expiry_allocation_ledger_entries():
''' fix ledger entries for missing leave allocation transaction '''
@@ -65,24 +62,16 @@
for allocation in allocation_list:
if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Allocation', 'transaction_name': allocation.name, 'is_expired': 1}):
- allocation.update(dict(doctype="Leave Allocation"))
- allocation_obj = frappe.get_doc(allocation)
+ allocation_obj = frappe.get_doc("Leave Allocation", allocation)
if allocation_obj.to_date <= getdate(today()):
expire_allocation(allocation_obj)
def get_allocation_records():
- return frappe.get_all("Leave Allocation", filters={
- "docstatus": 1
- }, fields=['name', 'employee', 'leave_type', 'new_leaves_allocated',
- 'unused_leaves', 'from_date', 'to_date', 'carry_forward'
- ], order_by='to_date ASC')
+ return frappe.get_all("Leave Allocation", filters={"docstatus": 1},
+ fields=['name'], order_by='to_date ASC')
def get_leaves_application_records():
- return frappe.get_all("Leave Application", filters={
- "docstatus": 1
- }, fields=['name', 'employee', 'leave_type', 'total_leave_days', 'from_date', 'to_date'])
+ return frappe.get_all("Leave Application", filters={"docstatus": 1}, fields=['name'])
def get_leave_encashment_records():
- return frappe.get_all("Leave Encashment", filters={
- "docstatus": 1
- }, fields=['name', 'employee', 'leave_type', 'encashable_days', 'encashment_date'])
+ return frappe.get_all("Leave Encashment", filters={"docstatus": 1}, fields=['name'])
diff --git a/erpnext/setup/install.py b/erpnext/setup/install.py
index 4f0f572..2225fe1 100644
--- a/erpnext/setup/install.py
+++ b/erpnext/setup/install.py
@@ -20,6 +20,7 @@
frappe.get_doc({'doctype': "Role", "role_name": "Analytics"}).insert()
set_single_defaults()
create_compact_item_print_custom_field()
+ create_print_uom_after_qty_custom_field()
create_print_zero_amount_taxes_custom_field()
add_all_roles_to("Administrator")
create_default_cash_flow_mapper_templates()
@@ -66,6 +67,16 @@
})
+def create_print_uom_after_qty_custom_field():
+ create_custom_field('Print Settings', {
+ 'label': _('Print UOM after Quantity'),
+ 'fieldname': 'print_uom_after_quantity',
+ 'fieldtype': 'Check',
+ 'default': 0,
+ 'insert_after': 'compact_item_print'
+ })
+
+
def create_print_zero_amount_taxes_custom_field():
create_custom_field('Print Settings', {
'label': _('Print taxes with zero amount'),
diff --git a/erpnext/startup/leaderboard.py b/erpnext/startup/leaderboard.py
index 5545f13..ef238f1 100644
--- a/erpnext/startup/leaderboard.py
+++ b/erpnext/startup/leaderboard.py
@@ -123,7 +123,8 @@
if field == "outstanding_amount":
filters = [['docstatus', '=', '1'], ['company', '=', company]]
if date_range:
- filters.append(['posting_date', 'between' [date_range[0], date_range[1]]])
+ date_range = frappe.parse_json(date_range)
+ filters.append(['posting_date', 'between', [date_range[0], date_range[1]]])
return frappe.db.get_all('Purchase Invoice',
fields = ['supplier as name', 'sum(outstanding_amount) as value'],
filters = filters,
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index 30bcccd..a92d04f 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -513,7 +513,7 @@
d.basic_amount = flt((raw_material_cost - scrap_material_cost), d.precision("basic_amount"))
elif self.purpose == "Repack" and total_fg_qty and not d.set_basic_rate_manually:
d.basic_rate = flt(raw_material_cost) / flt(total_fg_qty)
- d.basic_amount = d.basic_rate * d.qty
+ d.basic_amount = d.basic_rate * flt(d.qty)
def distribute_additional_costs(self):
if self.purpose == "Material Issue":
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
index 43fbc00..b81f8a0 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
@@ -258,6 +258,7 @@
sl_entries.append(args)
+ qty_after_transaction = 0
for serial_no in serial_nos:
args = self.get_sle_for_items(row, [serial_no])
@@ -271,11 +272,19 @@
if previous_sle and row.warehouse != previous_sle.get("warehouse"):
# If serial no exists in different warehouse
+ warehouse = previous_sle.get("warehouse", '') or row.warehouse
+
+ if not qty_after_transaction:
+ qty_after_transaction = get_stock_balance(row.item_code,
+ warehouse, self.posting_date, self.posting_time)
+
+ qty_after_transaction -= 1
+
new_args = args.copy()
new_args.update({
'actual_qty': -1,
- 'qty_after_transaction': cint(previous_sle.get('qty_after_transaction')) - 1,
- 'warehouse': previous_sle.get("warehouse", '') or row.warehouse,
+ 'qty_after_transaction': qty_after_transaction,
+ 'warehouse': warehouse,
'valuation_rate': previous_sle.get("valuation_rate")
})
diff --git a/erpnext/templates/print_formats/includes/item_table_qty.html b/erpnext/templates/print_formats/includes/item_table_qty.html
index 239859e..ecaaef4 100644
--- a/erpnext/templates/print_formats/includes/item_table_qty.html
+++ b/erpnext/templates/print_formats/includes/item_table_qty.html
@@ -1,6 +1,15 @@
-{% if (doc.uom and not doc.is_print_hide("uom")) %}
- <small class="pull-left">{{ _(doc.uom) }}</small>
-{% elif (doc.stock_uom and not doc.is_print_hide("stock_uom")) %}
- <small class="pull-left">{{ _(doc.stock_uom) }}</small>
+{% set qty_first=frappe.db.get_single_value("Print Settings", "print_uom_after_quantity") %}
+{% if qty_first %}
+ {{ doc.get_formatted("qty", doc) }}
+ {% if (doc.uom and not doc.is_print_hide("uom")) %} {{ _(doc.uom) }}
+ {% elif (doc.stock_uom and not doc.is_print_hide("stock_uom")) %} {{ _(doc.stock_uom) }}
+ {%- endif %}
+{% else %}
+ {% if (doc.uom and not doc.is_print_hide("uom")) %}
+ <small class="pull-left">{{ _(doc.uom) }}</small>
+ {% elif (doc.stock_uom and not doc.is_print_hide("stock_uom")) %}
+ <small class="pull-left">{{ _(doc.stock_uom) }}</small>
+ {%- endif %}
+ {{ doc.get_formatted("qty", doc) }}
{%- endif %}
-{{ doc.get_formatted("qty", doc) }}
+
diff --git a/erpnext/utilities/product.py b/erpnext/utilities/product.py
index c23c1f7..66d6cd3 100644
--- a/erpnext/utilities/product.py
+++ b/erpnext/utilities/product.py
@@ -82,6 +82,7 @@
pricing_rule = get_pricing_rule_for_item(frappe._dict({
"item_code": item_code,
"qty": qty,
+ "stock_qty": qty,
"transaction_type": "selling",
"price_list": price_list,
"customer_group": customer_group,
diff --git a/yarn.lock b/yarn.lock
index b19f566..97a0635 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -282,9 +282,9 @@
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
bl@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/bl/-/bl-3.0.0.tgz#3611ec00579fd18561754360b21e9f784500ff88"
- integrity sha512-EUAyP5UHU5hxF8BPT0LKW8gjYLhq1DQIcneOX/pL/m2Alo+OYDQAJlHq+yseMP50Os2nHXOSic6Ss3vSQeyf4A==
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/bl/-/bl-3.0.1.tgz#1cbb439299609e419b5a74d7fce2f8b37d8e5c6f"
+ integrity sha512-jrCW5ZhfQ/Vt07WX1Ngs+yn9BDqPL/gw28S7s9H6QK/gupnizNzJAss5akW20ISgOrbLTlXOOCTJeNUQqruAWQ==
dependencies:
readable-stream "^3.0.1"
@@ -866,12 +866,12 @@
once "^1.3.0"
wrappy "1"
-inherits@2, inherits@^2.0.3, inherits@~2.0.3:
+inherits@2, inherits@~2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
-inherits@2.0.4, inherits@~2.0.1:
+inherits@2.0.4, inherits@^2.0.3, inherits@~2.0.1:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@@ -1447,9 +1447,9 @@
util-deprecate "~1.0.1"
readable-stream@^3.0.1, readable-stream@^3.1.1:
- version "3.5.0"
- resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.5.0.tgz#465d70e6d1087f6162d079cd0b5db7fbebfd1606"
- integrity sha512-gSz026xs2LfxBPudDuI41V1lka8cxg64E66SGe78zJlsUofOg/yqwezdIcdfwik6B4h8LFmWPA9ef9X3FiNFLA==
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
+ integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
dependencies:
inherits "^2.0.3"
string_decoder "^1.1.1"
@@ -1505,9 +1505,9 @@
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
safe-buffer@~5.2.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
- integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
+ integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
"safer-buffer@>= 2.1.2 < 3":
version "2.1.2"