perf: improve gl entry submission (#20676)

* perf: improve gl entry submission

* perf: add indexes

* fix: replace **kwargs with *args

* fix: syntax error

* fix: remove cypress

* fix: travis

* chore: remove purchase invoice from status updater

* fix: set_staus args

Co-Authored-By: Nabin Hait <nabinhait@gmail.com>

* fix: only update status for invoices & fees

Co-authored-by: Nabin Hait <nabinhait@gmail.com>
This commit is contained in:
Saqib 2020-02-27 18:32:19 +05:30 committed by GitHub
parent d42a4a6234
commit fb35a54bee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 155 additions and 64 deletions

View File

@ -18,7 +18,8 @@
"in_list_view": 1, "in_list_view": 1,
"label": "Invoice", "label": "Invoice",
"options": "Sales Invoice", "options": "Sales Invoice",
"reqd": 1 "reqd": 1,
"search_index": 1
}, },
{ {
"fetch_from": "sales_invoice.customer", "fetch_from": "sales_invoice.customer",
@ -60,7 +61,7 @@
} }
], ],
"istable": 1, "istable": 1,
"modified": "2019-09-26 11:05:36.016772", "modified": "2020-02-20 16:16:20.724620",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Discounted Invoice", "name": "Discounted Invoice",

View File

@ -232,11 +232,36 @@ def update_outstanding_amt(account, party_type, party, against_voucher_type, aga
if bal < 0 and not on_cancel: if bal < 0 and not on_cancel:
frappe.throw(_("Outstanding for {0} cannot be less than zero ({1})").format(against_voucher, fmt_money(bal))) frappe.throw(_("Outstanding for {0} cannot be less than zero ({1})").format(against_voucher, fmt_money(bal)))
# Update outstanding amt on against voucher
if against_voucher_type in ["Sales Invoice", "Purchase Invoice", "Fees"]: if against_voucher_type in ["Sales Invoice", "Purchase Invoice", "Fees"]:
update_outstanding_amt_in_ref(against_voucher, against_voucher_type, bal)
def update_outstanding_amt_in_ref(against_voucher, against_voucher_type, bal):
data = []
# Update outstanding amt on against voucher
if against_voucher_type == "Fees":
ref_doc = frappe.get_doc(against_voucher_type, against_voucher) ref_doc = frappe.get_doc(against_voucher_type, against_voucher)
ref_doc.db_set('outstanding_amount', bal) ref_doc.db_set('outstanding_amount', bal)
ref_doc.set_status(update=True) ref_doc.set_status(update=True)
return
elif against_voucher_type == "Purchase Invoice":
from erpnext.accounts.doctype.purchase_invoice.purchase_invoice import get_status
data = frappe.db.get_value(against_voucher_type, against_voucher,
["name as purchase_invoice", "outstanding_amount",
"is_return", "due_date", "docstatus"])
elif against_voucher_type == "Sales Invoice":
from erpnext.accounts.doctype.sales_invoice.sales_invoice import get_status
data = frappe.db.get_value(against_voucher_type, against_voucher,
["name as sales_invoice", "outstanding_amount", "is_discounted",
"is_return", "due_date", "docstatus"])
precision = frappe.get_precision(against_voucher_type, "outstanding_amount")
data = list(data)
data.append(precision)
status = get_status(data)
frappe.db.set_value(against_voucher_type, against_voucher, {
'outstanding_amount': bal,
'status': status
})
def validate_frozen_account(account, adv_adj=None): def validate_frozen_account(account, adv_adj=None):
frozen_account = frappe.db.get_value("Account", account, "freeze_account") frozen_account = frappe.db.get_value("Account", account, "freeze_account")
@ -274,6 +299,9 @@ def update_against_account(voucher_type, voucher_no):
if d.against != new_against: if d.against != new_against:
frappe.db.set_value("GL Entry", d.name, "against", new_against) frappe.db.set_value("GL Entry", d.name, "against", new_against)
def on_doctype_update():
frappe.db.add_index("GL Entry", ["against_voucher_type", "against_voucher"])
frappe.db.add_index("GL Entry", ["voucher_type", "voucher_no"])
def rename_gle_sle_docs(): def rename_gle_sle_docs():
for doctype in ["GL Entry", "Stock Ledger Entry"]: for doctype in ["GL Entry", "Stock Ledger Entry"]:

View File

@ -125,6 +125,27 @@ class PurchaseInvoice(BuyingController):
else: else:
self.remarks = _("No Remarks") self.remarks = _("No Remarks")
def set_status(self, update=False, status=None, update_modified=True):
if self.is_new():
if self.get('amended_from'):
self.status = 'Draft'
return
if not status:
precision = self.precision("outstanding_amount")
args = [
self.name,
self.outstanding_amount,
self.is_return,
self.due_date,
self.docstatus,
precision
]
status = get_status(args)
if update:
self.db_set('status', status, update_modified = update_modified)
def set_missing_values(self, for_validate=False): def set_missing_values(self, for_validate=False):
if not self.credit_to: if not self.credit_to:
self.credit_to = get_party_account("Supplier", self.supplier, self.company) self.credit_to = get_party_account("Supplier", self.supplier, self.company)
@ -1007,6 +1028,34 @@ class PurchaseInvoice(BuyingController):
# calculate totals again after applying TDS # calculate totals again after applying TDS
self.calculate_taxes_and_totals() self.calculate_taxes_and_totals()
def get_status(*args):
purchase_invoice, outstanding_amount, is_return, due_date, docstatus, precision = args[0]
outstanding_amount = flt(outstanding_amount, precision)
due_date = getdate(due_date)
now_date = getdate()
if docstatus == 2:
status = "Cancelled"
elif docstatus == 1:
if outstanding_amount > 0 and due_date < now_date:
status = "Overdue"
elif outstanding_amount > 0 and due_date >= now_date:
status = "Unpaid"
#Check if outstanding amount is 0 due to debit note issued against invoice
elif outstanding_amount <= 0 and is_return == 0 and frappe.db.get_value('Purchase Invoice', {'is_return': 1, 'return_against': purchase_invoice, 'docstatus': 1}):
status = "Debit Note Issued"
elif is_return == 1:
status = "Return"
elif outstanding_amount <=0:
status = "Paid"
else:
status = "Submitted"
else:
status = "Draft"
return status
def get_list_context(context=None): def get_list_context(context=None):
from erpnext.controllers.website_list_for_contact import get_list_context from erpnext.controllers.website_list_for_contact import get_list_context
list_context = get_list_context(context) list_context = get_list_context(context)

View File

@ -1217,9 +1217,31 @@ class SalesInvoice(SellingController):
self.set_missing_values(for_validate = True) self.set_missing_values(for_validate = True)
def get_discounting_status(self): def set_status(self, update=False, status=None, update_modified=True):
if self.is_new():
if self.get('amended_from'):
self.status = 'Draft'
return
if not status:
precision = self.precision("outstanding_amount")
args = [
self.name,
self.outstanding_amount,
self.is_discounted,
self.is_return,
self.due_date,
self.docstatus,
precision,
]
status = get_status(args)
if update:
self.db_set('status', status, update_modified = update_modified)
def get_discounting_status(sales_invoice):
status = None status = None
if self.is_discounted:
invoice_discounting_list = frappe.db.sql(""" invoice_discounting_list = frappe.db.sql("""
select status select status
from `tabInvoice Discounting` id, `tabDiscounted Invoice` d from `tabInvoice Discounting` id, `tabDiscounted Invoice` d
@ -1228,51 +1250,50 @@ class SalesInvoice(SellingController):
and d.sales_invoice=%s and d.sales_invoice=%s
and id.docstatus=1 and id.docstatus=1
and status in ('Disbursed', 'Settled') and status in ('Disbursed', 'Settled')
""", self.name) """, sales_invoice)
for d in invoice_discounting_list: for d in invoice_discounting_list:
status = d[0] status = d[0]
if status == "Disbursed": if status == "Disbursed":
break break
return status return status
def set_status(self, update=False, status=None, update_modified=True): def get_status(*args):
if self.is_new(): sales_invoice, outstanding_amount, is_discounted, is_return, due_date, docstatus, precision = args[0]
if self.get('amended_from'):
self.status = 'Draft'
return
precision = self.precision("outstanding_amount") discounting_status = None
outstanding_amount = flt(self.outstanding_amount, precision) if is_discounted:
due_date = getdate(self.due_date) discounting_status = get_discounting_status(sales_invoice)
nowdate = getdate()
discountng_status = self.get_discounting_status()
if not status: outstanding_amount = flt(outstanding_amount, precision)
if self.docstatus == 2: due_date = getdate(due_date)
now_date = getdate()
if docstatus == 2:
status = "Cancelled" status = "Cancelled"
elif self.docstatus == 1: elif docstatus == 1:
if outstanding_amount > 0 and due_date < nowdate and self.is_discounted and discountng_status=='Disbursed': if outstanding_amount > 0 and due_date < now_date and is_discounted and discounting_status=='Disbursed':
self.status = "Overdue and Discounted" status = "Overdue and Discounted"
elif outstanding_amount > 0 and due_date < nowdate: elif outstanding_amount > 0 and due_date < now_date:
self.status = "Overdue" status = "Overdue"
elif outstanding_amount > 0 and due_date >= nowdate and self.is_discounted and discountng_status=='Disbursed': elif outstanding_amount > 0 and due_date >= now_date and is_discounted and discounting_status=='Disbursed':
self.status = "Unpaid and Discounted" status = "Unpaid and Discounted"
elif outstanding_amount > 0 and due_date >= nowdate: elif outstanding_amount > 0 and due_date >= now_date:
self.status = "Unpaid" status = "Unpaid"
#Check if outstanding amount is 0 due to credit note issued against invoice #Check if outstanding amount is 0 due to credit note issued against invoice
elif outstanding_amount <= 0 and self.is_return == 0 and frappe.db.get_value('Sales Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1}): elif outstanding_amount <= 0 and is_return == 0 and frappe.db.get_value('Sales Invoice', {'is_return': 1, 'return_against': sales_invoice, 'docstatus': 1}):
self.status = "Credit Note Issued" status = "Credit Note Issued"
elif self.is_return == 1: elif is_return == 1:
self.status = "Return" status = "Return"
elif outstanding_amount <=0: elif outstanding_amount <=0:
self.status = "Paid" status = "Paid"
else: else:
self.status = "Submitted" status = "Submitted"
else: else:
self.status = "Draft" status = "Draft"
if update: return status
self.db_set('status', self.status, update_modified = update_modified)
def validate_inter_company_party(doctype, party, company, inter_company_reference): def validate_inter_company_party(doctype, party, company, inter_company_reference):
if not party: if not party:

View File

@ -140,8 +140,11 @@ def make_entry(args, adv_adj, update_outstanding, from_repost=False):
gle = frappe.get_doc(args) gle = frappe.get_doc(args)
gle.flags.ignore_permissions = 1 gle.flags.ignore_permissions = 1
gle.flags.from_repost = from_repost gle.flags.from_repost = from_repost
gle.insert() gle.validate()
gle.flags.ignore_permissions = True
gle.db_insert()
gle.run_method("on_update_with_args", adv_adj, update_outstanding, from_repost) gle.run_method("on_update_with_args", adv_adj, update_outstanding, from_repost)
gle.flags.ignore_validate = True
gle.submit() gle.submit()
def validate_account_for_perpetual_inventory(gl_map): def validate_account_for_perpetual_inventory(gl_map):

View File

@ -44,17 +44,6 @@ status_map = {
["Closed", "eval:self.status=='Closed'"], ["Closed", "eval:self.status=='Closed'"],
["On Hold", "eval:self.status=='On Hold'"], ["On Hold", "eval:self.status=='On Hold'"],
], ],
"Purchase Invoice": [
["Draft", None],
["Submitted", "eval:self.docstatus==1"],
["Paid", "eval:self.outstanding_amount==0 and self.docstatus==1"],
["Return", "eval:self.is_return==1 and self.docstatus==1"],
["Debit Note Issued",
"eval:self.outstanding_amount <= 0 and self.docstatus==1 and self.is_return==0 and get_value('Purchase Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1})"],
["Unpaid", "eval:self.outstanding_amount > 0 and getdate(self.due_date) >= getdate(nowdate()) and self.docstatus==1"],
["Overdue", "eval:self.outstanding_amount > 0 and getdate(self.due_date) < getdate(nowdate()) and self.docstatus==1"],
["Cancelled", "eval:self.docstatus==2"],
],
"Purchase Order": [ "Purchase Order": [
["Draft", None], ["Draft", None],
["To Receive and Bill", "eval:self.per_received < 100 and self.per_billed < 100 and self.docstatus == 1"], ["To Receive and Bill", "eval:self.per_received < 100 and self.per_billed < 100 and self.docstatus == 1"],