Reverted gl entry splitting based on payment terms (#12117)

* Reverted gl entry splitting based on payment terms

* changed modified date
This commit is contained in:
Nabin Hait 2017-12-21 11:37:18 +05:30 committed by GitHub
parent 2f9f4f9c01
commit a5cc84f8af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 70 additions and 601 deletions

View File

@ -74,36 +74,6 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "due_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": "Due 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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@ -748,7 +718,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-08-10 18:06:44.904081",
"modified": "2017-12-20 12:40:09.611951",
"modified_by": "Administrator",
"module": "Accounts",
"name": "GL Entry",
@ -824,4 +794,4 @@
"sort_order": "DESC",
"track_changes": 0,
"track_seen": 0
}
}

View File

@ -61,16 +61,6 @@ frappe.ui.form.on("Journal Entry", {
}
}
});
},
accounts_on_form_rendered: function(frm) {
const options = frm.doc.__onload;
if (options && frm.cur_grid) {
frm.cur_grid.get_field("reference_due_date")
.df.options = options[frm.cur_grid.get_field('reference_name').value];
frm.cur_grid.refresh_field('reference_due_date');
}
}
});
@ -204,39 +194,8 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
})
},
due_date_options_cache: {},
reference_name: function(doc, cdt, cdn) {
var d = frappe.get_doc(cdt, cdn);
var me = this;
const get_invoice_due_dates = invoice_name => {
const options = this.due_date_options_cache[invoice_name];
const input = $(cur_frm.fields_dict["accounts"].wrapper).find("select[data-fieldname=reference_due_date]");
if (options) {
input.empty();
input.add_options(options);
frappe.model.set_value(cdt, cdn, "reference_due_date", options[0]);
}
else {
frappe.call({
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_invoice_due_dates",
args: {name: invoice_name},
callback: function(r) {
const options = [];
$.each(r.message, function(key, value) {
options.push(value.due_date);
});
input.empty();
input.add_options(options);
frappe.model.set_value(cdt, cdn, "reference_due_date", options[0]);
me.frm.cur_grid.get_field("reference_due_date").df.options = options.join('\n');
me.due_date_options_cache[d.reference_name] = options;
}
});
}
}
if(d.reference_name) {
if (d.reference_type==="Purchase Invoice" && !flt(d.debit)) {
@ -246,32 +205,6 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
} else if (d.reference_type==="Journal Entry" && !flt(d.credit) && !flt(d.debit)) {
this.get_outstanding('Journal Entry', d.reference_name, doc.company, d);
}
if( in_list(["Sales Invoice", "Purchase Invoice"]), d.reference_type) {
get_invoice_due_dates(d.reference_name);
}
}
},
reference_due_date: function(doc, cdt, cdn) {
const d = frappe.get_doc(cdt, cdn);
if (d.reference_type && d.reference_name && d.reference_due_date) {
if (in_list(["Sales Invoice", "Purchase Invoice"], d.reference_type)) {
frappe.model.set_value(cdt, cdn, 'debit_in_account_currency', '');
frappe.model.set_value(cdt, cdn, 'credit_in_account_currency', '');
}
if (d.reference_type==="Purchase Invoice") {
this.get_outstanding(
'Purchase Invoice', d.reference_name, doc.company, d, d.reference_due_date
);
} else if (d.reference_type==="Sales Invoice") {
this.get_outstanding(
'Sales Invoice', d.reference_name, doc.company, d, d.reference_due_date
);
}
frappe.model.set_value(cdt, cdn, 'reference_due_date', d.reference_due_date);
}
},
@ -286,8 +219,6 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
"company": company
}
if (due_date) args.due_date = due_date;
return frappe.call({
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_outstanding",
args: { args: args},

View File

@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe, erpnext, json
from frappe.utils import cstr, flt, fmt_money, formatdate, getdate, DATE_FORMAT
from frappe.utils import cstr, flt, fmt_money, formatdate, getdate
from frappe import msgprint, _, scrub
from erpnext.controllers.accounts_controller import AccountsController
from erpnext.accounts.utils import get_balance_on, get_account_currency
@ -434,8 +434,7 @@ class JournalEntry(AccountsController):
"against_voucher": d.reference_name,
"remarks": self.remark,
"cost_center": d.cost_center,
"project": d.project,
"due_date": d.reference_due_date
"project": d.project
})
)
@ -687,54 +686,22 @@ def get_payment_entry(ref_doc, args):
"remark": args.get("remarks")
})
if not ref_doc.payment_schedule:
je.append("accounts", {
"account": args.get("party_account"),
"party_type": args.get("party_type"),
"party": ref_doc.get(args.get("party_type").lower()),
"cost_center": cost_center,
"account_type": frappe.db.get_value("Account", args.get("party_account"), "account_type"),
"account_currency": args.get("party_account_currency") or \
get_account_currency(args.get("party_account")),
"balance": get_balance_on(args.get("party_account")),
"party_balance": get_balance_on(party=args.get("party"), party_type=args.get("party_type")),
"exchange_rate": exchange_rate,
args.get("amount_field_party"): args.get("amount"),
"is_advance": args.get("is_advance"),
"reference_type": ref_doc.doctype,
"reference_name": ref_doc.name
})
else:
options_ref_name_list = [
d.due_date.strftime(DATE_FORMAT) for d in ref_doc.payment_schedule
if d.get('due_date')
]
for payment_term in ref_doc.payment_schedule:
je.append("accounts", {
"account": args.get("party_account"),
"party_type": args.get("party_type"),
"party": ref_doc.get(args.get("party_type").lower()),
"cost_center": cost_center,
"account_type": frappe.db.get_value("Account", args.get("party_account"), "account_type"),
"account_currency": args.get("party_account_currency") or \
get_account_currency(args.get("party_account")),
"balance": get_balance_on(args.get("party_account")),
"party_balance": get_balance_on(party=args.get("party"), party_type=args.get("party_type")),
"exchange_rate": exchange_rate,
args.get("amount_field_party"): payment_term.payment_amount,
"is_advance": args.get("is_advance"),
"reference_type": ref_doc.doctype,
"reference_name": ref_doc.name,
"reference_due_date": payment_term.due_date
})
je.set_onload(ref_doc.name, '\n'.join(options_ref_name_list))
# First multi currency check
for row in je.accounts:
if row.account_currency != ref_doc.company_currency:
je.multi_currency = 1
party_row = je.append("accounts", {
"account": args.get("party_account"),
"party_type": args.get("party_type"),
"party": ref_doc.get(args.get("party_type").lower()),
"cost_center": cost_center,
"account_type": frappe.db.get_value("Account", args.get("party_account"), "account_type"),
"account_currency": args.get("party_account_currency") or \
get_account_currency(args.get("party_account")),
"balance": get_balance_on(args.get("party_account")),
"party_balance": get_balance_on(party=args.get("party"), party_type=args.get("party_type")),
"exchange_rate": exchange_rate,
args.get("amount_field_party"): args.get("amount"),
"is_advance": args.get("is_advance"),
"reference_type": ref_doc.doctype,
"reference_name": ref_doc.name
})
bank_row = je.append("accounts")
@ -758,8 +725,8 @@ def get_payment_entry(ref_doc, args):
bank_row.set(args.get("amount_field_bank"), amount * exchange_rate)
# Multi currency check again
if not je.multi_currency:
if bank_row.account_currency and bank_row.account_currency != ref_doc.company_currency:
if party_row.account_currency != ref_doc.company_currency \
or (bank_row.account_currency and bank_row.account_currency != ref_doc.company_currency):
je.multi_currency = 1
je.set_amounts_in_company_currency()
@ -816,7 +783,8 @@ def get_outstanding(args):
}
elif args.get("doctype") in ("Sales Invoice", "Purchase Invoice"):
party_type = "Customer" if args.get("doctype") == "Sales Invoice" else "Supplier"
invoice = frappe.get_doc(args['doctype'], args['docname']).as_dict()
invoice = frappe.db.get_value(args["doctype"], args["docname"],
["outstanding_amount", "conversion_rate", scrub(party_type)], as_dict=1)
exchange_rate = invoice.conversion_rate if (args.get("account_currency") != company_currency) else 1
@ -827,23 +795,13 @@ def get_outstanding(args):
amount_field = "debit_in_account_currency" \
if flt(invoice.outstanding_amount) > 0 else "credit_in_account_currency"
if args.get('due_date'):
outstanding = ''
for d in invoice.payment_schedule:
if d.due_date == getdate(args['due_date']):
outstanding = abs(flt(d.payment_amount))
break
else:
outstanding = abs(flt(invoice.outstanding_amount))
return {
amount_field: outstanding,
amount_field: abs(flt(invoice.outstanding_amount)),
"exchange_rate": exchange_rate,
"party_type": party_type,
"party": invoice.get(scrub(party_type))
}
@frappe.whitelist()
def get_party_account_and_balance(company, party_type, party):
if not frappe.has_permission("Account"):
@ -941,15 +899,4 @@ def get_average_exchange_rate(account):
bank_balance_in_company_currency = get_balance_on(account, in_account_currency=False)
exchange_rate = bank_balance_in_company_currency / bank_balance_in_account_currency
return exchange_rate
@frappe.whitelist()
def get_invoice_due_dates(name):
result = frappe.get_list(
doctype='GL Entry',
filters={'voucher_no': name, "ifnull(due_date, '')": ('!=', '')},
fields=['due_date'], distinct=True
)
return result
return exchange_rate

View File

@ -661,39 +661,7 @@
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 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,
"unique": 0
},
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,

View File

@ -71,9 +71,10 @@ class PaymentEntry(AccountsController):
def validate_duplicate_entry(self):
reference_names = []
for d in self.get("references"):
if (d.reference_doctype, d.reference_name, d.due_date) in reference_names:
frappe.throw(_("Row #{0}: Duplicate entry in References {1} {2}").format(d.idx, d.reference_doctype, d.reference_name))
reference_names.append((d.reference_doctype, d.reference_name, d.due_date))
if (d.reference_doctype, d.reference_name) in reference_names:
frappe.throw(_("Row #{0}: Duplicate entry in References {1} {2}")
.format(d.idx, d.reference_doctype, d.reference_name))
reference_names.append((d.reference_doctype, d.reference_name))
def validate_allocated_amount(self):
for d in self.get("references"):
@ -413,8 +414,7 @@ class PaymentEntry(AccountsController):
gle = party_gl_dict.copy()
gle.update({
"against_voucher_type": d.reference_doctype,
"against_voucher": d.reference_name,
"due_date": d.due_date
"against_voucher": d.reference_name
})
allocated_amount_in_company_currency = flt(flt(d.allocated_amount) * flt(d.exchange_rate),
@ -545,10 +545,8 @@ def get_outstanding_reference_documents(args):
def get_orders_to_be_billed(posting_date, party_type, party, party_account_currency, company_currency):
if party_type == "Customer":
voucher_type = 'Sales Order'
payment_dr_or_cr = "credit_in_account_currency - debit_in_account_currency"
elif party_type == "Supplier":
voucher_type = 'Purchase Order'
payment_dr_or_cr = "debit_in_account_currency - credit_in_account_currency"
elif party_type == "Employee":
voucher_type = None
@ -557,131 +555,36 @@ 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"
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
VT.name as voucher_no,
PS.payment_amount as invoice_amount,
PS.payment_amount - (select
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
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}` VT
join
`tabPayment Schedule` PS on VT.name = PS.parent
`tab{voucher_type}`
where
{party_type} = %s
and VT.docstatus = 1
and docstatus = 1
and ifnull(status, "") != "Closed"
and {ref_field} > advance_paid
and abs(100 - per_billed) > 0.01
order by
VT.transaction_date, VT.name
""".format(**{
"ref_field": ref_field,
"voucher_type": voucher_type,
"party_type": scrub(party_type),
"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')
transaction_date, name
""".format(**{
"ref_field": ref_field,
"voucher_type": voucher_type,
"party_type": scrub(party_type)
}), party, as_dict=True)
order_list = []
for d in orders:
d["voucher_type"] = voucher_type
# This assumes that the exchange rate required is the one in the SO
d["exchange_rate"] = get_exchange_rate(party_account_currency,
company_currency, posting_date)
d["exchange_rate"] = get_exchange_rate(party_account_currency, company_currency, posting_date)
order_list.append(d)
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):
voucher_type = "Sales Invoice" if party_type == "Customer" else "Purchase Invoice"
if party_account_currency == company_currency:
@ -900,40 +803,15 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
pe.allocate_payment_amount = 1
pe.letter_head = doc.get("letter_head")
if dt == "Employee Advance":
pe.append("references", {
'reference_doctype': dt,
'reference_name': dn,
'total_amount': grand_total,
'outstanding_amount': outstanding_amount,
'allocated_amount': outstanding_amount
})
else:
args = {
'party_account': party_account,
'company': pe.company,
'party_type': pe.party_type,
'party': pe.party,
'posting_date': pe.posting_date,
'voucher_type': dt,
'voucher_no': dn
}
references = get_outstanding_reference_documents(args=args)
for reference in references:
if reference.voucher_no == dn:
allocated_amount = min(paid_amount, reference.outstanding_amount)
pe.append("references", {
'reference_doctype': reference.voucher_type,
'reference_name': reference.voucher_no,
'due_date': reference.due_date,
'total_amount': reference.invoice_amount,
'outstanding_amount': reference.outstanding_amount,
'allocated_amount': allocated_amount,
"bill_no": reference.get("bill_no")
})
if paid_amount:
paid_amount -= allocated_amount
pe.append("references", {
'reference_doctype': dt,
'reference_name': dn,
"bill_no": doc.get("bill_no"),
"due_date": doc.get("due_date"),
'total_amount': grand_total,
'outstanding_amount': outstanding_amount,
'allocated_amount': outstanding_amount
})
pe.setup_party_account_field()
pe.set_missing_values()

View File

@ -66,18 +66,6 @@ class TestPaymentEntry(unittest.TestCase):
outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"))
self.assertEqual(outstanding_amount, 100)
def test_payment_entry_against_si_multi_due_dates(self):
si = create_sales_invoice(do_not_save=1)
si.payment_terms_template = '_Test Payment Term Template'
si.insert()
si.submit()
pe = get_payment_entry(si.doctype, si.name)
pe.reference_no = "1"
pe.reference_date = "2016-01-01"
pe.insert()
pe.submit()
def test_payment_entry_against_pi(self):
pi = make_purchase_invoice(supplier="_Test Supplier USD", debit_to="_Test Payable USD - _TC",
currency="USD", conversion_rate=50)

View File

@ -363,27 +363,7 @@ class PurchaseInvoice(BuyingController):
def make_supplier_gl_entry(self, gl_entries):
grand_total = self.rounded_total or self.grand_total
if self.get("payment_schedule"):
for d in self.get("payment_schedule"):
payment_amount_in_company_currency = flt(d.payment_amount * self.conversion_rate,
d.precision("payment_amount"))
gl_entries.append(
self.get_gl_dict({
"account": self.credit_to,
"party_type": "Supplier",
"party": self.supplier,
"due_date": d.due_date,
"against": self.against_expense_account,
"credit": payment_amount_in_company_currency,
"credit_in_account_currency": payment_amount_in_company_currency \
if self.party_account_currency==self.company_currency else d.payment_amount,
"against_voucher": self.return_against if cint(self.is_return) else self.name,
"against_voucher_type": self.doctype
}, self.party_account_currency)
)
elif grand_total:
if grand_total:
# Didnot use base_grand_total to book rounding loss gle
grand_total_in_company_currency = flt(grand_total * self.conversion_rate,
self.precision("grand_total"))

View File

@ -6,7 +6,7 @@ from __future__ import unicode_literals
import unittest
import frappe, erpnext
import frappe.model
from frappe.utils import cint, flt, today, nowdate, getdate, add_days
from frappe.utils import cint, flt, today, nowdate, add_days
import frappe.defaults
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory, \
test_records as pr_test_records
@ -647,39 +647,6 @@ class TestPurchaseInvoice(unittest.TestCase):
self.assertEquals(pi.total_taxes_and_charges, 462.3)
self.assertEquals(pi.grand_total, 1712.3)
def test_gl_entry_based_on_payment_schedule(self):
pi = make_purchase_invoice(do_not_save=True, supplier="_Test Supplier P")
pi.append("payment_schedule", {
"due_date": add_days(nowdate(), 15),
"payment_amount": 100,
"invoice_portion": 40.00
})
pi.append("payment_schedule", {
"due_date": add_days(nowdate(), 25),
"payment_amount": 150,
"invoice_portion": 60.00
})
pi.save()
pi.submit()
gl_entries = frappe.db.sql("""select account, debit, credit, due_date
from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
order by account asc, debit asc""", pi.name, as_dict=1)
self.assertTrue(gl_entries)
expected_gl_entries = sorted([
[pi.credit_to, 0.0, 100.0, add_days(nowdate(), 15)],
[pi.credit_to, 0.0, 150.0, add_days(nowdate(), 25)],
["_Test Account Cost for Goods Sold - _TC", 250.0, 0.0, None]
])
for i, gle in enumerate(sorted(gl_entries, key=lambda gle: gle.account)):
self.assertEquals(expected_gl_entries[i][0], gle.account)
self.assertEquals(expected_gl_entries[i][1], gle.debit)
self.assertEquals(expected_gl_entries[i][2], gle.credit)
self.assertEquals(getdate(expected_gl_entries[i][3]), getdate(gle.due_date))
def test_make_pi_without_terms(self):
pi = make_purchase_invoice(do_not_save=1)

View File

@ -637,27 +637,7 @@ class SalesInvoice(SellingController):
def make_customer_gl_entry(self, gl_entries):
grand_total = self.rounded_total or self.grand_total
if self.get("payment_schedule"):
for d in self.get("payment_schedule"):
payment_amount_in_company_currency = flt(d.payment_amount * self.conversion_rate,
d.precision("payment_amount"))
gl_entries.append(
self.get_gl_dict({
"account": self.debit_to,
"party_type": "Customer",
"party": self.customer,
"due_date": d.due_date,
"against": self.against_income_account,
"debit": payment_amount_in_company_currency,
"debit_in_account_currency": payment_amount_in_company_currency \
if self.party_account_currency==self.company_currency else d.payment_amount,
"against_voucher": self.return_against if cint(self.is_return) else self.name,
"against_voucher_type": self.doctype
}, self.party_account_currency)
)
elif grand_total:
if grand_total:
# Didnot use base_grand_total to book rounding loss gle
grand_total_in_company_currency = flt(grand_total * self.conversion_rate,
self.precision("grand_total"))

View File

@ -5,7 +5,7 @@ from __future__ import unicode_literals
import frappe
import unittest, copy, time
from frappe.utils import nowdate, add_days, flt, getdate, cint
from frappe.utils import nowdate, flt, getdate, cint
from frappe.model.dynamic_links import get_dynamic_link_map
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry, get_qty_after_transaction
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import unlink_payment_on_cancel_of_invoice
@ -1321,40 +1321,6 @@ class TestSalesInvoice(unittest.TestCase):
})
si.insert()
return si
def test_gl_entry_based_on_payment_schedule(self):
si = create_sales_invoice(do_not_save=True, customer="_Test Customer P")
si.append("payment_schedule", {
"due_date": add_days(nowdate(), 15),
"payment_amount": 20,
"invoice_portion": 20.00
})
si.append("payment_schedule", {
"due_date": add_days(nowdate(), 45),
"payment_amount": 80,
"invoice_portion": 80.00
})
si.save()
si.submit()
gl_entries = frappe.db.sql("""select account, debit, credit, due_date
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
order by account asc, debit asc""", si.name, as_dict=1)
self.assertTrue(gl_entries)
expected_gl_entries = sorted([
[si.debit_to, 20.0, 0.0, add_days(nowdate(), 15)],
[si.debit_to, 80.0, 0.0, add_days(nowdate(), 45)],
["Sales - _TC", 0.0, 100.0, None]
])
for i, gle in enumerate(sorted(gl_entries, key=lambda gle: gle.account)):
self.assertEquals(expected_gl_entries[i][0], gle.account)
self.assertEquals(expected_gl_entries[i][1], gle.debit)
self.assertEquals(expected_gl_entries[i][2], gle.credit)
self.assertEquals(getdate(expected_gl_entries[i][3]), getdate(gle.due_date))
def test_company_monthly_sales(self):
existing_current_month_sales = frappe.db.get_value("Company", "_Test Company", "total_monthly_sales")

View File

@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe, erpnext
from frappe.utils import flt, cstr, cint, getdate
from frappe.utils import flt, cstr, cint
from frappe import _
from frappe.model.meta import get_field_precision
from erpnext.accounts.doctype.budget.budget import validate_expense_against_budget
@ -75,8 +75,7 @@ def check_if_in_list(gle, gl_map):
and cstr(e.get('against_voucher'))==cstr(gle.get('against_voucher')) \
and cstr(e.get('against_voucher_type')) == cstr(gle.get('against_voucher_type')) \
and cstr(e.get('cost_center')) == cstr(gle.get('cost_center')) \
and cstr(e.get('project')) == cstr(gle.get('project')) \
and getdate(e.get('due_date')) == getdate(gle.get('due_date')):
and cstr(e.get('project')) == cstr(gle.get('project')):
return e
def save_entries(gl_map, adv_adj, update_outstanding, from_repost=False):

View File

@ -113,7 +113,7 @@ class ReceivablePayableReport(object):
row += [self.get_party_name(gle.party_type, gle.party)]
# get due date
due_date = gle.due_date or voucher_details.get(gle.voucher_no, {}).get("due_date", "")
due_date = voucher_details.get(gle.voucher_no, {}).get("due_date", "")
row += [gle.voucher_type, gle.voucher_no, due_date]
@ -188,8 +188,7 @@ class ReceivablePayableReport(object):
reverse_dr_or_cr = "credit" if dr_or_cr=="debit" else "debit"
for e in self.get_gl_entries_for(gle.party, gle.party_type, gle.voucher_type, gle.voucher_no):
if getdate(e.posting_date) <= report_date and e.name!=gle.name \
and (not gle.due_date or getdate(e.due_date) == getdate(gle.due_date)):
if getdate(e.posting_date) <= report_date and e.name!=gle.name:
amount = flt(e.get(reverse_dr_or_cr)) - flt(e.get(dr_or_cr))
if e.voucher_no not in return_entries:
payment_amount += amount
@ -251,11 +250,11 @@ class ReceivablePayableReport(object):
select_fields = "sum(debit) as debit, sum(credit) as credit"
self.gl_entries = frappe.db.sql("""select name, posting_date, account, party_type, party,
voucher_type, voucher_no, against_voucher_type, against_voucher, due_date,
voucher_type, voucher_no, against_voucher_type, against_voucher,
account_currency, remarks, {0}
from `tabGL Entry`
where docstatus < 2 and party_type=%s and (party is not null and party != '') {1}
group by voucher_type, voucher_no, against_voucher_type, against_voucher, party, due_date
group by voucher_type, voucher_no, against_voucher_type, against_voucher, party
order by posting_date, party"""
.format(select_fields, conditions), values, as_dict=True)

View File

@ -583,9 +583,10 @@ def get_outstanding_invoices(party_type, party, account, condition=None):
dr_or_cr = "credit_in_account_currency - debit_in_account_currency"
payment_dr_or_cr = "payment_gl_entry.debit_in_account_currency - payment_gl_entry.credit_in_account_currency"
invoice = 'Sales Invoice' if party_type == 'Customer' else 'Purchase Invoice'
invoice_list = frappe.db.sql("""
select
voucher_no, voucher_type, posting_date, ifnull(sum({dr_or_cr}), 0) as invoice_amount, due_date,
voucher_no, voucher_type, posting_date, ifnull(sum({dr_or_cr}), 0) as invoice_amount,
(
select ifnull(sum({payment_dr_or_cr}), 0)
from `tabGL Entry` payment_gl_entry
@ -596,7 +597,6 @@ def get_outstanding_invoices(party_type, party, account, condition=None):
and payment_gl_entry.party_type = invoice_gl_entry.party_type
and payment_gl_entry.party = invoice_gl_entry.party
and payment_gl_entry.account = invoice_gl_entry.account
and payment_gl_entry.due_date = invoice_gl_entry.due_date
and {payment_dr_or_cr} > 0
) as payment_amount
from
@ -608,10 +608,11 @@ def get_outstanding_invoices(party_type, party, account, condition=None):
and ((voucher_type = 'Journal Entry'
and (against_voucher = '' or against_voucher is null))
or (voucher_type not in ('Journal Entry', 'Payment Entry')))
group by voucher_type, voucher_no, due_date
group by voucher_type, voucher_no
having (invoice_amount - payment_amount) > 0.005
order by posting_date, name, due_date""".format(
dr_or_cr=dr_or_cr,
invoice = invoice,
payment_dr_or_cr=payment_dr_or_cr,
condition=condition or ""
), {
@ -621,12 +622,8 @@ def get_outstanding_invoices(party_type, party, account, condition=None):
}, as_dict=True)
for d in invoice_list:
due_date = d.due_date or (
frappe.db.get_value(
d.voucher_type, d.voucher_no,
"posting_date" if party_type == "Employee" else "due_date"
)
)
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({

View File

@ -485,4 +485,3 @@ erpnext.patches.v10_0.enabled_regional_print_format_based_on_country
erpnext.patches.v10_0.update_asset_calculate_depreciation
erpnext.patches.v10_0.enabled_regional_print_format_based_on_country
erpnext.patches.v10_0.update_asset_calculate_depreciation
erpnext.patches.v10_0.update_due_date_in_gle_and_payment_entries

View File

@ -1,100 +0,0 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import update_progress_bar
def execute():
frappe.reload_doc("accounts", "doctype", "gl_entry")
frappe.reload_doc("accounts", "doctype", "payment_entry_reference")
frappe.reload_doc("accounts", "doctype", "journal_entry_account")
print "Updating Due Date in GL Entry, Journal Entry and Payment Entry"
for doctype in ("Sales Invoice", "Purchase Invoice"):
invoice_due_dates = frappe.db.sql("""select name, due_date from `tab{0}`
where docstatus=1 order by name""".format(doctype))
# update gle
count = 0
total_count = len(invoice_due_dates)
batch_size = 1000
while(count < total_count):
update_progress_bar("Based on {0}".format(doctype), count, total_count)
sub_set = invoice_due_dates[count:count+batch_size]
invoices = [d[0] for d in sub_set]
update_gl_entries(doctype, invoices, sub_set)
update_payment_entries(doctype, invoices, sub_set)
count += batch_size
def update_gl_entries(doctype, invoices, invoice_due_dates):
when_then = get_when_then_for_gle(doctype, invoice_due_dates)
frappe.db.sql("""
UPDATE `tabGL Entry`
SET due_date = CASE
%s
ELSE `due_date` END
WHERE
(
(voucher_type = %s and voucher_no in (%s))
or (voucher_type in ('Journal Entry', 'Payment Entry')
and against_voucher in (%s))
)
and ifnull(party, '') != ''
and ifnull(due_date, '') = ''
""" % (when_then, '%s', ', '.join(['%s']*len(invoices)), ', '.join(['%s']*len(invoices))),
tuple([doctype] + invoices + invoices))
def get_when_then_for_gle(doctype, data):
cond = ""
for d in data:
cond += """
WHEN (
(voucher_type = '{voucher_type}' and voucher_no = '{voucher_no}')
or (voucher_type in ('Journal Entry', 'Payment Entry')
and against_voucher = '{voucher_no}')
) THEN '{date}'
""".format(voucher_type=doctype, voucher_no=frappe.db.escape(d[0]), date=d[1])
return cond
def update_payment_entries(ref_doctype, invoices, invoice_due_dates):
for d in (
("Payment Entry Reference", "reference_doctype", "due_date"),
("Journal Entry Account", "reference_type", "reference_due_date")):
when_then = get_when_then_for_payment_entries(ref_doctype, d[1], invoice_due_dates)
frappe.db.sql("""
UPDATE `tab{doctype}`
SET {due_date_field} = CASE
{when_then}
ELSE `{due_date_field}` END
WHERE
{ref_doctype_fieldname} = '{ref_doctype}'
and reference_name in ({reference_names})
and ifnull({due_date_field}, '') = ''
""".format(
doctype = d[0],
due_date_field = d[2],
when_then = when_then,
ref_doctype_fieldname = d[1],
ref_doctype = ref_doctype,
reference_names = ', '.join(['%s']*len(invoices))
), tuple(invoices))
def get_when_then_for_payment_entries(ref_doctype, ref_doctype_fieldname, data):
cond = ""
for d in data:
cond += """
WHEN {ref_doctype_fieldname} = '{ref_doctype}'
and reference_name = '{voucher_no}'
THEN '{date}'
""".format(
ref_doctype_fieldname=ref_doctype_fieldname,
ref_doctype=ref_doctype,
voucher_no=frappe.db.escape(d[0]),
date=d[1])
return cond