Ability to hold payment for disputed invoices #12048 (#13298)

* add new fields to Supplier Master:
- on_hold: To signal the Customer is blocked from completing certain transactions
- hold_type: 3 options - All, invoices and payments

* sanitize `on_hold` field input

* show hold status in list view

* add `release_date` field to Supplier Master:
- specifies the date when transaction restraint will be removed

* reset release date if supplier is not on hold

* add validation to stop transactions when Supplier is blocked

* add test cases

* return empty list for outstanding references if supplier is blocked

* block make button:payment if supplier is blocked

* adjust test cases

* PEP 8 clean up

* more tests

* adds new fields to Purchase Invoice:
- release_date: once set, invoice will be on hold until set date
- hold_comment: so user can add comment pertaining to why invoice is on hold

* implement individual purchase invoice on hold logic

* allow user to change release date

* update manual

* final cleanup including more validation and tests

* update supplier manual

* make default for release_date argument todays date

* remove Auto Repeat added by mistake

* add on_hold_field to purchase invoice

* add 'On Hold' or 'Temporarily on Hold' status for purchase invoice in list view

* implement explicit payment hold in purchase invoice

* update manual

* add dialog for saving comment

* bug fix, refactor, clean up

* more test cases
This commit is contained in:
tundebabzy
2018-05-16 07:01:41 +01:00
committed by Rushabh Mehta
parent 1906cadd94
commit ad08d4ce96
16 changed files with 865 additions and 38 deletions

View File

@@ -572,6 +572,22 @@ def get_stock_rbnb_difference(posting_date, company):
return flt(stock_rbnb) + flt(sys_bal)
def get_held_invoices(party_type, party):
"""
Returns a list of names Purchase Invoices for the given party that are on hold
"""
held_invoices = None
if party_type == 'Supplier':
held_invoices = frappe.db.sql(
'select name from `tabPurchase Invoice` where release_date IS NOT NULL and release_date > CURDATE()',
as_dict=1
)
held_invoices = [d['name'] for d in held_invoices]
return held_invoices
def get_outstanding_invoices(party_type, party, account, condition=None):
outstanding_invoices = []
precision = frappe.get_precision("Sales Invoice", "outstanding_amount")
@@ -584,7 +600,9 @@ def get_outstanding_invoices(party_type, party, account, condition=None):
payment_dr_or_cr = "payment_gl_entry.debit_in_account_currency - payment_gl_entry.credit_in_account_currency"
invoice = 'Sales Invoice' if erpnext.get_party_account_type(party_type) == 'Receivable' else 'Purchase Invoice'
invoice_list = frappe.db.sql("""
held_invoices = get_held_invoices(party_type, party)
invoice_list = frappe.db.sql("""
select
voucher_no, voucher_type, posting_date, ifnull(sum({dr_or_cr}), 0) as invoice_amount,
(
@@ -622,20 +640,21 @@ def get_outstanding_invoices(party_type, party, account, condition=None):
}, as_dict=True)
for d in invoice_list:
due_date = frappe.db.get_value(d.voucher_type, d.voucher_no,
"posting_date" if party_type == "Employee" else "due_date")
if not d.voucher_type == "Purchase Invoice" or d.voucher_no not in held_invoices:
due_date = frappe.db.get_value(
d.voucher_type, d.voucher_no, "posting_date" if party_type == "Employee" else "due_date")
outstanding_invoices.append(
frappe._dict({
'voucher_no': d.voucher_no,
'voucher_type': d.voucher_type,
'posting_date': d.posting_date,
'invoice_amount': flt(d.invoice_amount),
'payment_amount': flt(d.payment_amount),
'outstanding_amount': flt(d.invoice_amount - d.payment_amount, precision),
'due_date': due_date
})
)
outstanding_invoices.append(
frappe._dict({
'voucher_no': d.voucher_no,
'voucher_type': d.voucher_type,
'posting_date': d.posting_date,
'invoice_amount': flt(d.invoice_amount),
'payment_amount': flt(d.payment_amount),
'outstanding_amount': flt(d.invoice_amount - d.payment_amount, precision),
'due_date': due_date
})
)
outstanding_invoices = sorted(outstanding_invoices, key=lambda k: k['due_date'] or getdate(nowdate()))