* validate schedule dates in non-invoice documents * change query for orders * take care of orders with/without payment schedule * clean up, refactor, PEP8
This commit is contained in:
parent
41d2feab35
commit
dbd068c44b
@ -541,11 +541,14 @@ def get_outstanding_reference_documents(args):
|
|||||||
|
|
||||||
return negative_outstanding_invoices + outstanding_invoices + orders_to_be_billed
|
return negative_outstanding_invoices + outstanding_invoices + orders_to_be_billed
|
||||||
|
|
||||||
|
|
||||||
def get_orders_to_be_billed(posting_date, party_type, party, party_account_currency, company_currency):
|
def get_orders_to_be_billed(posting_date, party_type, party, party_account_currency, company_currency):
|
||||||
if party_type == "Customer":
|
if party_type == "Customer":
|
||||||
voucher_type = 'Sales Order'
|
voucher_type = 'Sales Order'
|
||||||
|
payment_dr_or_cr = "credit_in_account_currency - debit_in_account_currency"
|
||||||
elif party_type == "Supplier":
|
elif party_type == "Supplier":
|
||||||
voucher_type = 'Purchase Order'
|
voucher_type = 'Purchase Order'
|
||||||
|
payment_dr_or_cr = "debit_in_account_currency - credit_in_account_currency"
|
||||||
elif party_type == "Employee":
|
elif party_type == "Employee":
|
||||||
voucher_type = None
|
voucher_type = None
|
||||||
|
|
||||||
@ -554,26 +557,93 @@ def get_orders_to_be_billed(posting_date, party_type, party, party_account_curre
|
|||||||
ref_field = "base_grand_total" if party_account_currency == company_currency else "grand_total"
|
ref_field = "base_grand_total" if party_account_currency == company_currency else "grand_total"
|
||||||
|
|
||||||
orders = frappe.db.sql("""
|
orders = frappe.db.sql("""
|
||||||
|
select
|
||||||
|
name as voucher_no,
|
||||||
|
{ref_field} as invoice_amount,
|
||||||
|
({ref_field} - advance_paid) as outstanding_amount,
|
||||||
|
transaction_date as posting_date
|
||||||
|
from
|
||||||
|
`tab{voucher_type}`
|
||||||
|
where
|
||||||
|
{party_type} = %s
|
||||||
|
and docstatus = 1
|
||||||
|
and ifnull(status, "") != "Closed"
|
||||||
|
and {ref_field} > advance_paid
|
||||||
|
and abs(100 - per_billed) > 0.01
|
||||||
|
order by
|
||||||
|
transaction_date, name
|
||||||
|
""".format(**{
|
||||||
|
"ref_field": ref_field,
|
||||||
|
"voucher_type": voucher_type,
|
||||||
|
"party_type": scrub(party_type)
|
||||||
|
}), party, as_dict=True)
|
||||||
|
|
||||||
|
if voucher_type and party_type is not "Employee":
|
||||||
|
ref_field = "base_grand_total" if party_account_currency == company_currency else "grand_total"
|
||||||
|
|
||||||
|
# find orders without considering if they have Payment Schedule
|
||||||
|
orders_without_schedule = frappe.db.sql("""
|
||||||
|
select
|
||||||
|
name as voucher_no,
|
||||||
|
{ref_field} as invoice_amount,
|
||||||
|
({ref_field} - advance_paid) as outstanding_amount,
|
||||||
|
transaction_date as posting_date
|
||||||
|
from
|
||||||
|
`tab{voucher_type}`
|
||||||
|
where
|
||||||
|
{party_type} = %s
|
||||||
|
and docstatus = 1
|
||||||
|
and ifnull(status, "") != "Closed"
|
||||||
|
and {ref_field} > advance_paid
|
||||||
|
and abs(100 - per_billed) > 0.01
|
||||||
|
order by
|
||||||
|
transaction_date, name
|
||||||
|
""".format(**{
|
||||||
|
"ref_field": ref_field,
|
||||||
|
"voucher_type": voucher_type,
|
||||||
|
"party_type": scrub(party_type)
|
||||||
|
}), party, as_dict=True)
|
||||||
|
|
||||||
|
# find orders considering if they have Payment Schedule
|
||||||
|
if voucher_type and party_type is not "Employee":
|
||||||
|
ref_field = "base_grand_total" if party_account_currency == company_currency else "grand_total"
|
||||||
|
|
||||||
|
orders_with_schedule = frappe.db.sql("""
|
||||||
select
|
select
|
||||||
name as voucher_no,
|
VT.name as voucher_no,
|
||||||
{ref_field} as invoice_amount,
|
PS.payment_amount as invoice_amount,
|
||||||
({ref_field} - advance_paid) as outstanding_amount,
|
PS.payment_amount - (select
|
||||||
transaction_date as posting_date
|
ifnull(sum({payment_dr_or_cr}), 0)
|
||||||
|
from `tabGL Entry`
|
||||||
|
where
|
||||||
|
against_voucher = VT.name
|
||||||
|
and due_date = PS.due_date
|
||||||
|
) as outstanding_amount,
|
||||||
|
VT.transaction_date as posting_date,
|
||||||
|
PS.due_date
|
||||||
from
|
from
|
||||||
`tab{voucher_type}`
|
`tab{voucher_type}` VT
|
||||||
|
join
|
||||||
|
`tabPayment Schedule` PS on VT.name = PS.parent
|
||||||
where
|
where
|
||||||
{party_type} = %s
|
{party_type} = %s
|
||||||
and docstatus = 1
|
and VT.docstatus = 1
|
||||||
and ifnull(status, "") != "Closed"
|
and ifnull(status, "") != "Closed"
|
||||||
and {ref_field} > advance_paid
|
and {ref_field} > advance_paid
|
||||||
and abs(100 - per_billed) > 0.01
|
and abs(100 - per_billed) > 0.01
|
||||||
order by
|
order by
|
||||||
transaction_date, name
|
VT.transaction_date, VT.name
|
||||||
""".format(**{
|
""".format(**{
|
||||||
"ref_field": ref_field,
|
"ref_field": ref_field,
|
||||||
"voucher_type": voucher_type,
|
"voucher_type": voucher_type,
|
||||||
"party_type": scrub(party_type)
|
"party_type": scrub(party_type),
|
||||||
}), party, as_dict = True)
|
"payment_dr_or_cr": payment_dr_or_cr
|
||||||
|
}), party, as_dict=True)
|
||||||
|
|
||||||
|
# reconcile both results such that we have a list that contains unique entries.
|
||||||
|
# Where both lists contain a record that is common, we select the one with
|
||||||
|
# linked Payment Schedule
|
||||||
|
orders = _merge_query_results(orders_without_schedule, orders_with_schedule, 'voucher_no')
|
||||||
|
|
||||||
order_list = []
|
order_list = []
|
||||||
for d in orders:
|
for d in orders:
|
||||||
@ -585,6 +655,33 @@ def get_orders_to_be_billed(posting_date, party_type, party, party_account_curre
|
|||||||
|
|
||||||
return order_list
|
return order_list
|
||||||
|
|
||||||
|
|
||||||
|
def _merge_query_results(result1, result2, dict_key):
|
||||||
|
"""
|
||||||
|
Merges two list of query results that are dictionaries.
|
||||||
|
For every item in result1 that is found in result2, the item is removed from
|
||||||
|
result1. At the end of processing result1, result1 and result2 are concatenated
|
||||||
|
and returned.
|
||||||
|
|
||||||
|
:param result1: List of dict
|
||||||
|
:param result2: List of dict
|
||||||
|
:return: List of dict
|
||||||
|
"""
|
||||||
|
for item in result1[:]:
|
||||||
|
found = False
|
||||||
|
for item2 in result2:
|
||||||
|
if item[dict_key] == item2[dict_key]:
|
||||||
|
found = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if found:
|
||||||
|
result1.remove(item)
|
||||||
|
|
||||||
|
final_result = result1 + result2
|
||||||
|
|
||||||
|
return final_result
|
||||||
|
|
||||||
|
|
||||||
def get_negative_outstanding_invoices(party_type, party, party_account, party_account_currency, company_currency):
|
def get_negative_outstanding_invoices(party_type, party, party_account, party_account_currency, company_currency):
|
||||||
voucher_type = "Sales Invoice" if party_type == "Customer" else "Purchase Invoice"
|
voucher_type = "Sales Invoice" if party_type == "Customer" else "Purchase Invoice"
|
||||||
if party_account_currency == company_currency:
|
if party_account_currency == company_currency:
|
||||||
@ -614,6 +711,7 @@ def get_negative_outstanding_invoices(party_type, party, party_account, party_ac
|
|||||||
"party_account": "debit_to" if party_type == "Customer" else "credit_to"
|
"party_account": "debit_to" if party_type == "Customer" else "credit_to"
|
||||||
}), (party, party_account), as_dict=True)
|
}), (party, party_account), as_dict=True)
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_party_details(company, party_type, party, date):
|
def get_party_details(company, party_type, party, date):
|
||||||
if not frappe.db.exists(party_type, party):
|
if not frappe.db.exists(party_type, party):
|
||||||
@ -635,6 +733,7 @@ def get_party_details(company, party_type, party, date):
|
|||||||
"account_balance": account_balance
|
"account_balance": account_balance
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_account_details(account, date):
|
def get_account_details(account, date):
|
||||||
frappe.has_permission('Payment Entry', throw=True)
|
frappe.has_permission('Payment Entry', throw=True)
|
||||||
@ -644,6 +743,7 @@ def get_account_details(account, date):
|
|||||||
"account_type": frappe.db.get_value("Account", account, "account_type")
|
"account_type": frappe.db.get_value("Account", account, "account_type")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_company_defaults(company):
|
def get_company_defaults(company):
|
||||||
fields = ["write_off_account", "exchange_gain_loss_account", "cost_center"]
|
fields = ["write_off_account", "exchange_gain_loss_account", "cost_center"]
|
||||||
@ -656,6 +756,7 @@ def get_company_defaults(company):
|
|||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_reference_details(reference_doctype, reference_name, party_account_currency):
|
def get_reference_details(reference_doctype, reference_name, party_account_currency):
|
||||||
total_amount = outstanding_amount = exchange_rate = None
|
total_amount = outstanding_amount = exchange_rate = None
|
||||||
@ -701,6 +802,7 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre
|
|||||||
"exchange_rate": exchange_rate
|
"exchange_rate": exchange_rate
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=None):
|
def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=None):
|
||||||
doc = frappe.get_doc(dt, dn)
|
doc = frappe.get_doc(dt, dn)
|
||||||
|
@ -71,6 +71,7 @@ class AccountsController(TransactionBase):
|
|||||||
self.validate_advance_entries()
|
self.validate_advance_entries()
|
||||||
|
|
||||||
def validate_non_invoice_documents_schedule(self):
|
def validate_non_invoice_documents_schedule(self):
|
||||||
|
self.validate_payment_schedule_dates()
|
||||||
self.validate_invoice_portion()
|
self.validate_invoice_portion()
|
||||||
self.set_payment_schedule()
|
self.set_payment_schedule()
|
||||||
self.validate_payment_schedule_amount()
|
self.validate_payment_schedule_amount()
|
||||||
@ -672,15 +673,15 @@ class AccountsController(TransactionBase):
|
|||||||
def validate_payment_schedule_dates(self):
|
def validate_payment_schedule_dates(self):
|
||||||
dates = []
|
dates = []
|
||||||
li = []
|
li = []
|
||||||
if self.due_date and getdate(self.due_date) < getdate(self.posting_date):
|
if self.get('posting_date'):
|
||||||
frappe.throw(_("Due Date cannot be before posting date"))
|
if self.due_date and getdate(self.due_date) < getdate(self.posting_date):
|
||||||
|
frappe.throw(_("Due Date cannot be before posting date"))
|
||||||
|
|
||||||
for d in self.get("payment_schedule"):
|
for d in self.get("payment_schedule"):
|
||||||
if getdate(d.due_date) < getdate(self.posting_date):
|
if self.get('posting_date') and getdate(d.due_date) < getdate(self.posting_date):
|
||||||
frappe.throw(_("Row {0}: Due Date cannot be before posting date").format(d.idx))
|
frappe.throw(_("Row {0}: Due Date cannot be before posting date").format(d.idx))
|
||||||
elif d.due_date in dates:
|
elif d.due_date in dates:
|
||||||
li.append('{0} in row {1}'.format(d.due_date, d.idx))
|
li.append('{0} in row {1}'.format(d.due_date, d.idx))
|
||||||
# frappe.throw(_("Row {0}: Duplicate due date found").format(d.idx))
|
|
||||||
dates.append(d.due_date)
|
dates.append(d.due_date)
|
||||||
|
|
||||||
if li:
|
if li:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user