Post GL Entry based on rounded total in Sales/Purchase Invoice (#11542)

This commit is contained in:
Nabin Hait 2017-11-17 12:27:43 +05:30 committed by GitHub
parent 1783549e75
commit 877e1bb377
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 232 additions and 86 deletions

View File

@ -17,12 +17,13 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
if(!this.frm.doc.supplier && this.frm.doc.credit_to) { if(!this.frm.doc.supplier && this.frm.doc.credit_to) {
this.frm.set_df_property("credit_to", "print_hide", 0); this.frm.set_df_property("credit_to", "print_hide", 0);
} }
} else {
this.frm.set_value("disable_rounded_total", frappe.sys_defaults.disable_rounded_total);
} }
// formatter for material request item // formatter for material request item
this.frm.set_indicator_formatter('item_code', this.frm.set_indicator_formatter('item_code',
function(doc) { return (doc.qty<=doc.received_qty) ? "green" : "orange" }) function(doc) { return (doc.qty<=doc.received_qty) ? "green" : "orange" })
}, },
refresh: function(doc) { refresh: function(doc) {

View File

@ -2104,6 +2104,38 @@
"set_only_once": 0, "set_only_once": 0,
"unique": 0 "unique": 0
}, },
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:!doc.disable_rounded_total",
"fieldname": "base_rounded_total",
"fieldtype": "Currency",
"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": "Rounded Total (Company Currency)",
"length": 0,
"no_copy": 1,
"options": "Company:company:default_currency",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
@ -2229,6 +2261,38 @@
"set_only_once": 0, "set_only_once": 0,
"unique": 0 "unique": 0
}, },
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:!doc.disable_rounded_total",
"fieldname": "rounded_total",
"fieldtype": "Currency",
"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": "Rounded Total",
"length": 0,
"no_copy": 1,
"options": "currency",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
@ -2324,6 +2388,37 @@
"set_only_once": 0, "set_only_once": 0,
"unique": 0 "unique": 0
}, },
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "grand_total",
"fieldname": "disable_rounded_total",
"fieldtype": "Check",
"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": "Disable Rounded Total",
"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_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
@ -3576,7 +3671,7 @@
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"menu_index": 0, "menu_index": 0,
"modified": "2017-11-15 01:04:15.308603", "modified": "2017-11-16 01:04:15.308603",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Purchase Invoice", "name": "Purchase Invoice",

View File

@ -77,8 +77,10 @@ class PurchaseInvoice(BuyingController):
if not self.cash_bank_account and flt(self.paid_amount): if not self.cash_bank_account and flt(self.paid_amount):
frappe.throw(_("Cash or Bank Account is mandatory for making payment entry")) frappe.throw(_("Cash or Bank Account is mandatory for making payment entry"))
if flt(self.paid_amount) + flt(self.write_off_amount) \ if (flt(self.paid_amount) + flt(self.write_off_amount)
- flt(self.grand_total) > 1/(10**(self.precision("base_grand_total") + 1)): - flt(self.get("rounded_total") or self.grand_total)
> 1/(10**(self.precision("base_grand_total") + 1))):
frappe.throw(_("""Paid amount + Write Off Amount can not be greater than Grand Total""")) frappe.throw(_("""Paid amount + Write Off Amount can not be greater than Grand Total"""))
def create_remarks(self): def create_remarks(self):
@ -359,9 +361,10 @@ class PurchaseInvoice(BuyingController):
return gl_entries return gl_entries
def make_supplier_gl_entry(self, gl_entries): def make_supplier_gl_entry(self, gl_entries):
if self.grand_total: grand_total = self.rounded_total or self.grand_total
if grand_total:
# Didnot use base_grand_total to book rounding loss gle # Didnot use base_grand_total to book rounding loss gle
grand_total_in_company_currency = flt(self.grand_total * self.conversion_rate, grand_total_in_company_currency = flt(grand_total * self.conversion_rate,
self.precision("grand_total")) self.precision("grand_total"))
gl_entries.append( gl_entries.append(
self.get_gl_dict({ self.get_gl_dict({
@ -371,7 +374,7 @@ class PurchaseInvoice(BuyingController):
"against": self.against_expense_account, "against": self.against_expense_account,
"credit": grand_total_in_company_currency, "credit": grand_total_in_company_currency,
"credit_in_account_currency": grand_total_in_company_currency \ "credit_in_account_currency": grand_total_in_company_currency \
if self.party_account_currency==self.company_currency else self.grand_total, if self.party_account_currency==self.company_currency else grand_total,
"against_voucher": self.return_against if cint(self.is_return) else self.name, "against_voucher": self.return_against if cint(self.is_return) else self.name,
"against_voucher_type": self.doctype, "against_voucher_type": self.doctype,
}, self.party_account_currency) }, self.party_account_currency)

View File

@ -35,7 +35,7 @@ class TestPurchaseInvoice(unittest.TestCase):
dl = wrapper dl = wrapper
expected_gl_entries = { expected_gl_entries = {
"_Test Payable - _TC": [0, 1512.30], "_Test Payable - _TC": [0, 1512.0],
"_Test Account Cost for Goods Sold - _TC": [1250, 0], "_Test Account Cost for Goods Sold - _TC": [1250, 0],
"_Test Account Shipping Charges - _TC": [100, 0], "_Test Account Shipping Charges - _TC": [100, 0],
"_Test Account Excise Duty - _TC": [140, 0], "_Test Account Excise Duty - _TC": [140, 0],
@ -44,6 +44,7 @@ class TestPurchaseInvoice(unittest.TestCase):
"_Test Account CST - _TC": [29.88, 0], "_Test Account CST - _TC": [29.88, 0],
"_Test Account VAT - _TC": [156.25, 0], "_Test Account VAT - _TC": [156.25, 0],
"_Test Account Discount - _TC": [0, 168.03], "_Test Account Discount - _TC": [0, 168.03],
"Round Off - _TC": [0, 0.3]
} }
gl_entries = frappe.db.sql("""select account, debit, credit from `tabGL Entry` gl_entries = frappe.db.sql("""select account, debit, credit from `tabGL Entry`
where voucher_type = 'Purchase Invoice' and voucher_no = %s""", dl.name, as_dict=1) where voucher_type = 'Purchase Invoice' and voucher_no = %s""", dl.name, as_dict=1)
@ -233,6 +234,7 @@ class TestPurchaseInvoice(unittest.TestCase):
jv.submit() jv.submit()
pi = frappe.copy_doc(test_records[0]) pi = frappe.copy_doc(test_records[0])
pi.disable_rounded_total = 1
pi.append("advances", { pi.append("advances", {
"reference_type": "Journal Entry", "reference_type": "Journal Entry",
"reference_name": jv.name, "reference_name": jv.name,
@ -242,6 +244,13 @@ class TestPurchaseInvoice(unittest.TestCase):
"remarks": jv.remark "remarks": jv.remark
}) })
pi.insert() pi.insert()
self.assertEqual(pi.outstanding_amount, 1212.30)
pi.disable_rounded_total = 0
pi.save()
self.assertEqual(pi.outstanding_amount, 1212.0)
pi.submit() pi.submit()
pi.load_from_db() pi.load_from_db()
@ -249,8 +258,6 @@ class TestPurchaseInvoice(unittest.TestCase):
where reference_type='Purchase Invoice' where reference_type='Purchase Invoice'
and reference_name=%s and debit_in_account_currency=300""", pi.name)) and reference_name=%s and debit_in_account_currency=300""", pi.name))
self.assertEqual(pi.outstanding_amount, 1212.30)
pi.cancel() pi.cancel()
self.assertFalse(frappe.db.sql("""select name from `tabJournal Entry Account` self.assertFalse(frappe.db.sql("""select name from `tabJournal Entry Account`
@ -491,7 +498,7 @@ class TestPurchaseInvoice(unittest.TestCase):
pi.load_from_db() pi.load_from_db()
#check outstanding after advance allocation #check outstanding after advance allocation
self.assertEqual(flt(pi.outstanding_amount), flt(pi.grand_total - pi.total_advance)) self.assertEqual(flt(pi.outstanding_amount), flt(pi.rounded_total - pi.total_advance))
#added to avoid Document has been modified exception #added to avoid Document has been modified exception
jv = frappe.get_doc("Journal Entry", jv.name) jv = frappe.get_doc("Journal Entry", jv.name)
@ -499,7 +506,7 @@ class TestPurchaseInvoice(unittest.TestCase):
pi.load_from_db() pi.load_from_db()
#check outstanding after advance cancellation #check outstanding after advance cancellation
self.assertEqual(flt(pi.outstanding_amount), flt(pi.grand_total + pi.total_advance)) self.assertEqual(flt(pi.outstanding_amount), flt(pi.rounded_total + pi.total_advance))
def test_outstanding_amount_after_advance_payment_entry_cancelation(self): def test_outstanding_amount_after_advance_payment_entry_cancelation(self):
pe = frappe.get_doc({ pe = frappe.get_doc({
@ -521,7 +528,7 @@ class TestPurchaseInvoice(unittest.TestCase):
}) })
pe.insert() pe.insert()
pe.submit() pe.submit()
pi = frappe.copy_doc(test_records[0]) pi = frappe.copy_doc(test_records[0])
pi.is_pos = 0 pi.is_pos = 0
pi.append("advances", { pi.append("advances", {
@ -534,19 +541,19 @@ class TestPurchaseInvoice(unittest.TestCase):
}) })
pi.insert() pi.insert()
pi.submit() pi.submit()
pi.load_from_db() pi.load_from_db()
#check outstanding after advance allocation #check outstanding after advance allocation
self.assertEqual(flt(pi.outstanding_amount), flt(pi.grand_total - pi.total_advance)) self.assertEqual(flt(pi.outstanding_amount), flt(pi.rounded_total - pi.total_advance))
#added to avoid Document has been modified exception #added to avoid Document has been modified exception
pe = frappe.get_doc("Payment Entry", pe.name) pe = frappe.get_doc("Payment Entry", pe.name)
pe.cancel() pe.cancel()
pi.load_from_db() pi.load_from_db()
#check outstanding after advance cancellation #check outstanding after advance cancellation
self.assertEqual(flt(pi.outstanding_amount), flt(pi.grand_total + pi.total_advance)) self.assertEqual(flt(pi.outstanding_amount), flt(pi.rounded_total + pi.total_advance))
def unlink_payment_on_cancel_of_invoice(enable=1): def unlink_payment_on_cancel_of_invoice(enable=1):
accounts_settings = frappe.get_doc("Accounts Settings") accounts_settings = frappe.get_doc("Accounts Settings")

View File

@ -632,9 +632,10 @@ class SalesInvoice(SellingController):
return gl_entries return gl_entries
def make_customer_gl_entry(self, gl_entries): def make_customer_gl_entry(self, gl_entries):
if self.grand_total: grand_total = self.rounded_total or self.grand_total
if grand_total:
# Didnot use base_grand_total to book rounding loss gle # Didnot use base_grand_total to book rounding loss gle
grand_total_in_company_currency = flt(self.grand_total * self.conversion_rate, grand_total_in_company_currency = flt(grand_total * self.conversion_rate,
self.precision("grand_total")) self.precision("grand_total"))
gl_entries.append( gl_entries.append(
@ -645,7 +646,7 @@ class SalesInvoice(SellingController):
"against": self.against_income_account, "against": self.against_income_account,
"debit": grand_total_in_company_currency, "debit": grand_total_in_company_currency,
"debit_in_account_currency": grand_total_in_company_currency \ "debit_in_account_currency": grand_total_in_company_currency \
if self.party_account_currency==self.company_currency else self.grand_total, if self.party_account_currency==self.company_currency else grand_total,
"against_voucher": self.return_against if cint(self.is_return) else self.name, "against_voucher": self.return_against if cint(self.is_return) else self.name,
"against_voucher_type": self.doctype "against_voucher_type": self.doctype
}, self.party_account_currency) }, self.party_account_currency)

View File

@ -546,7 +546,7 @@ class TestSalesInvoice(unittest.TestCase):
def test_outstanding(self): def test_outstanding(self):
w = self.make() w = self.make()
self.assertEquals(w.outstanding_amount, w.base_grand_total) self.assertEquals(w.outstanding_amount, w.base_rounded_total)
def test_payment(self): def test_payment(self):
w = self.make() w = self.make()
@ -560,7 +560,7 @@ class TestSalesInvoice(unittest.TestCase):
jv.insert() jv.insert()
jv.submit() jv.submit()
self.assertEquals(frappe.db.get_value("Sales Invoice", w.name, "outstanding_amount"), 161.8) self.assertEquals(frappe.db.get_value("Sales Invoice", w.name, "outstanding_amount"), 162.0)
link_data = get_dynamic_link_map().get('Sales Invoice', []) link_data = get_dynamic_link_map().get('Sales Invoice', [])
link_doctypes = [d.parent for d in link_data] link_doctypes = [d.parent for d in link_data]
@ -569,7 +569,7 @@ class TestSalesInvoice(unittest.TestCase):
self.assertTrue(link_doctypes.index('GL Entry') > link_doctypes.index('Journal Entry Account')) self.assertTrue(link_doctypes.index('GL Entry') > link_doctypes.index('Journal Entry Account'))
jv.cancel() jv.cancel()
self.assertEquals(frappe.db.get_value("Sales Invoice", w.name, "outstanding_amount"), 561.8) self.assertEquals(frappe.db.get_value("Sales Invoice", w.name, "outstanding_amount"), 562.0)
def test_sales_invoice_gl_entry_without_perpetual_inventory(self): def test_sales_invoice_gl_entry_without_perpetual_inventory(self):
si = frappe.copy_doc(test_records[1]) si = frappe.copy_doc(test_records[1])
@ -848,7 +848,7 @@ class TestSalesInvoice(unittest.TestCase):
self.assertTrue(frappe.db.sql("""select name from `tabJournal Entry Account` self.assertTrue(frappe.db.sql("""select name from `tabJournal Entry Account`
where reference_name=%s and credit_in_account_currency=300""", si.name)) where reference_name=%s and credit_in_account_currency=300""", si.name))
self.assertEqual(si.outstanding_amount, 261.8) self.assertEqual(si.outstanding_amount, 262.0)
si.cancel() si.cancel()
@ -1152,7 +1152,8 @@ class TestSalesInvoice(unittest.TestCase):
si.load_from_db() si.load_from_db()
#check outstanding after advance allocation #check outstanding after advance allocation
self.assertEqual(flt(si.outstanding_amount), flt(si.grand_total - si.total_advance, si.precision("outstanding_amount"))) self.assertEqual(flt(si.outstanding_amount),
flt(si.rounded_total - si.total_advance, si.precision("outstanding_amount")))
#added to avoid Document has been modified exception #added to avoid Document has been modified exception
jv = frappe.get_doc("Journal Entry", jv.name) jv = frappe.get_doc("Journal Entry", jv.name)
@ -1160,7 +1161,8 @@ class TestSalesInvoice(unittest.TestCase):
si.load_from_db() si.load_from_db()
#check outstanding after advance cancellation #check outstanding after advance cancellation
self.assertEqual(flt(si.outstanding_amount), flt(si.grand_total + si.total_advance, si.precision("outstanding_amount"))) self.assertEqual(flt(si.outstanding_amount),
flt(si.rounded_total + si.total_advance, si.precision("outstanding_amount")))
def test_outstanding_amount_after_advance_payment_entry_cancelation(self): def test_outstanding_amount_after_advance_payment_entry_cancelation(self):
pe = frappe.get_doc({ pe = frappe.get_doc({
@ -1199,7 +1201,8 @@ class TestSalesInvoice(unittest.TestCase):
si.load_from_db() si.load_from_db()
#check outstanding after advance allocation #check outstanding after advance allocation
self.assertEqual(flt(si.outstanding_amount), flt(si.grand_total - si.total_advance, si.precision("outstanding_amount"))) self.assertEqual(flt(si.outstanding_amount),
flt(si.rounded_total - si.total_advance, si.precision("outstanding_amount")))
#added to avoid Document has been modified exception #added to avoid Document has been modified exception
pe = frappe.get_doc("Payment Entry", pe.name) pe = frappe.get_doc("Payment Entry", pe.name)
@ -1207,7 +1210,8 @@ class TestSalesInvoice(unittest.TestCase):
si.load_from_db() si.load_from_db()
#check outstanding after advance cancellation #check outstanding after advance cancellation
self.assertEqual(flt(si.outstanding_amount), flt(si.grand_total + si.total_advance, si.precision("outstanding_amount"))) self.assertEqual(flt(si.outstanding_amount),
flt(si.rounded_total + si.total_advance, si.precision("outstanding_amount")))
def test_multiple_uom_in_selling(self): def test_multiple_uom_in_selling(self):
frappe.db.sql("""delete from `tabItem Price` frappe.db.sql("""delete from `tabItem Price`

View File

@ -66,9 +66,9 @@ class AccountsController(TransactionBase):
if cint(is_paid) == 1: if cint(is_paid) == 1:
if flt(self.paid_amount) == 0 and flt(self.outstanding_amount) > 0: if flt(self.paid_amount) == 0 and flt(self.outstanding_amount) > 0:
if self.cash_bank_account: if self.cash_bank_account:
self.paid_amount = flt(flt(self.grand_total) - flt(self.write_off_amount), self.paid_amount = flt(flt(self.outstanding_amount), self.precision("paid_amount"))
self.precision("paid_amount")) self.base_paid_amount = flt(self.paid_amount * self.conversion_rate,
self.base_paid_amount = flt(self.paid_amount * self.conversion_rate, self.precision("base_paid_amount")) self.precision("base_paid_amount"))
else: else:
# show message that the amount is not paid # show message that the amount is not paid
self.paid_amount = 0 self.paid_amount = 0
@ -598,6 +598,12 @@ class AccountsController(TransactionBase):
for item in duplicate_list: for item in duplicate_list:
self.remove(item) self.remove(item)
def is_rounded_total_disabled(self):
if self.meta.get_field("disable_rounded_total"):
return self.disable_rounded_total
else:
return frappe.db.get_single_value("Global Defaults", "disable_rounded_total")
@frappe.whitelist() @frappe.whitelist()
def get_tax_rate(account_head): def get_tax_rate(account_head):
return frappe.db.get_value("Account", account_head, ["tax_rate", "account_name"], as_dict=True) return frappe.db.get_value("Account", account_head, ["tax_rate", "account_name"], as_dict=True)

View File

@ -28,8 +28,7 @@ class SellingController(StockController):
super(SellingController, self).onload() super(SellingController, self).onload()
if self.doctype in ("Sales Order", "Delivery Note", "Sales Invoice"): if self.doctype in ("Sales Order", "Delivery Note", "Sales Invoice"):
for item in self.get("items"): for item in self.get("items"):
item.update(get_bin_details(item.item_code, item.update(get_bin_details(item.item_code, item.warehouse))
item.warehouse))
def validate(self): def validate(self):
super(SellingController, self).validate() super(SellingController, self).validate()
@ -114,14 +113,15 @@ class SellingController(StockController):
def set_total_in_words(self): def set_total_in_words(self):
from frappe.utils import money_in_words from frappe.utils import money_in_words
disable_rounded_total = cint(frappe.db.get_value("Global Defaults", None, "disable_rounded_total"))
if self.meta.get_field("base_in_words"): if self.meta.get_field("base_in_words"):
self.base_in_words = money_in_words(disable_rounded_total and base_amount = abs(self.base_grand_total
abs(self.base_grand_total) or abs(self.base_rounded_total), self.company_currency) if self.is_rounded_total_disabled() else self.base_rounded_total)
self.base_in_words = money_in_words(base_amount, self.company_currency)
if self.meta.get_field("in_words"): if self.meta.get_field("in_words"):
self.in_words = money_in_words(disable_rounded_total and amount = abs(self.grand_total if self.is_rounded_total_disabled() else self.rounded_total)
abs(self.grand_total) or abs(self.rounded_total), self.currency) self.in_words = money_in_words(amount, self.currency)
def calculate_commission(self): def calculate_commission(self):
if self.meta.get_field("commission_rate"): if self.meta.get_field("commission_rate"):

View File

@ -328,14 +328,18 @@ class calculate_taxes_and_totals(object):
self.set_rounded_total() self.set_rounded_total()
def set_rounded_total(self): def set_rounded_total(self):
if frappe.db.get_single_value("Global Defaults", "disable_rounded_total"):
self.doc.rounded_total = self.doc.base_rounded_total = 0
return
if self.doc.meta.get_field("rounded_total"): if self.doc.meta.get_field("rounded_total"):
if self.doc.is_rounded_total_disabled():
self.doc.rounded_total = self.doc.base_rounded_total = 0
return
self.doc.rounded_total = round_based_on_smallest_currency_fraction(self.doc.grand_total, self.doc.rounded_total = round_based_on_smallest_currency_fraction(self.doc.grand_total,
self.doc.currency, self.doc.precision("rounded_total")) self.doc.currency, self.doc.precision("rounded_total"))
#if print_in_rate is set, we would have already calculated rounding adjustment
self.doc.rounding_adjustment += flt(self.doc.rounded_total - self.doc.grand_total,
self.doc.precision("rounding_adjustment"))
if self.doc.meta.get_field("base_rounded_total"): if self.doc.meta.get_field("base_rounded_total"):
company_currency = erpnext.get_company_currency(self.doc.company) company_currency = erpnext.get_company_currency(self.doc.company)
@ -343,6 +347,9 @@ class calculate_taxes_and_totals(object):
round_based_on_smallest_currency_fraction(self.doc.base_grand_total, round_based_on_smallest_currency_fraction(self.doc.base_grand_total,
company_currency, self.doc.precision("base_rounded_total")) company_currency, self.doc.precision("base_rounded_total"))
self.doc.base_rounding_adjustment += flt(self.doc.base_rounded_total - self.doc.base_grand_total,
self.doc.precision("base_rounding_adjustment"))
def _cleanup(self): def _cleanup(self):
for tax in self.doc.get("taxes"): for tax in self.doc.get("taxes"):
tax.item_wise_tax_detail = json.dumps(tax.item_wise_tax_detail, separators=(',', ':')) tax.item_wise_tax_detail = json.dumps(tax.item_wise_tax_detail, separators=(',', ':'))
@ -404,7 +411,8 @@ class calculate_taxes_and_totals(object):
actual_tax_amount = flt(actual_taxes_dict.get(tax.row_id, 0)) * flt(tax.rate) / 100 actual_tax_amount = flt(actual_taxes_dict.get(tax.row_id, 0)) * flt(tax.rate) / 100
actual_taxes_dict.setdefault(tax.idx, actual_tax_amount) actual_taxes_dict.setdefault(tax.idx, actual_tax_amount)
return flt(self.doc.grand_total - sum(actual_taxes_dict.values()), self.doc.precision("grand_total")) return flt(self.doc.grand_total - sum(actual_taxes_dict.values()),
self.doc.precision("grand_total"))
def calculate_total_advance(self): def calculate_total_advance(self):
@ -442,30 +450,31 @@ class calculate_taxes_and_totals(object):
self.doc.round_floats_in(self.doc, ["grand_total", "total_advance", "write_off_amount"]) self.doc.round_floats_in(self.doc, ["grand_total", "total_advance", "write_off_amount"])
self._set_in_company_currency(self.doc, ['write_off_amount']) self._set_in_company_currency(self.doc, ['write_off_amount'])
if self.doc.party_account_currency == self.doc.currency: if self.doc.doctype in ["Sales Invoice", "Purchase Invoice"]:
total_amount_to_pay = flt(self.doc.grand_total - self.doc.total_advance grand_total = self.doc.rounded_total or self.doc.grand_total
- flt(self.doc.write_off_amount), self.doc.precision("grand_total")) if self.doc.party_account_currency == self.doc.currency:
else: total_amount_to_pay = flt(grand_total - self.doc.total_advance
total_amount_to_pay = flt(flt(self.doc.grand_total * - flt(self.doc.write_off_amount), self.doc.precision("grand_total"))
self.doc.conversion_rate, self.doc.precision("grand_total")) - self.doc.total_advance else:
- flt(self.doc.base_write_off_amount), self.doc.precision("grand_total")) total_amount_to_pay = flt(flt(grand_total *
self.doc.conversion_rate, self.doc.precision("grand_total")) - self.doc.total_advance
- flt(self.doc.base_write_off_amount), self.doc.precision("grand_total"))
if self.doc.doctype == "Sales Invoice":
self.doc.round_floats_in(self.doc, ["paid_amount"]) self.doc.round_floats_in(self.doc, ["paid_amount"])
self.calculate_write_off_amount() change_amount = 0
self.calculate_change_amount()
if self.doc.doctype == "Sales Invoice":
self.calculate_write_off_amount()
self.calculate_change_amount()
change_amount = self.doc.change_amount \
if self.doc.party_account_currency == self.doc.currency else self.doc.base_change_amount
paid_amount = self.doc.paid_amount \ paid_amount = self.doc.paid_amount \
if self.doc.party_account_currency == self.doc.currency else self.doc.base_paid_amount if self.doc.party_account_currency == self.doc.currency else self.doc.base_paid_amount
change_amount = self.doc.change_amount \
if self.doc.party_account_currency == self.doc.currency else self.doc.base_change_amount
self.doc.outstanding_amount = flt(total_amount_to_pay - flt(paid_amount) +
flt(change_amount), self.doc.precision("outstanding_amount"))
elif self.doc.doctype == "Purchase Invoice": self.doc.outstanding_amount = flt(total_amount_to_pay - flt(paid_amount) + flt(change_amount),
self.doc.outstanding_amount = flt(total_amount_to_pay, self.doc.precision("outstanding_amount")) self.doc.precision("outstanding_amount"))
def calculate_paid_amount(self): def calculate_paid_amount(self):
paid_amount = base_paid_amount = 0.0 paid_amount = base_paid_amount = 0.0
@ -485,7 +494,9 @@ class calculate_taxes_and_totals(object):
def calculate_change_amount(self): def calculate_change_amount(self):
self.doc.change_amount = 0.0 self.doc.change_amount = 0.0
self.doc.base_change_amount = 0.0 self.doc.base_change_amount = 0.0
if self.doc.paid_amount > self.doc.grand_total and not self.doc.is_return \
if self.doc.doctype == "Sales Invoice" \
and self.doc.paid_amount > self.doc.grand_total and not self.doc.is_return \
and any([d.type == "Cash" for d in self.doc.payments]): and any([d.type == "Cash" for d in self.doc.payments]):
self.doc.change_amount = flt(self.doc.paid_amount - self.doc.grand_total + self.doc.change_amount = flt(self.doc.paid_amount - self.doc.grand_total +
@ -496,8 +507,8 @@ class calculate_taxes_and_totals(object):
def calculate_write_off_amount(self): def calculate_write_off_amount(self):
if flt(self.doc.change_amount) > 0: if flt(self.doc.change_amount) > 0:
self.doc.write_off_amount = flt(self.doc.grand_total - self.doc.paid_amount + self.doc.change_amount, self.doc.write_off_amount = flt(self.doc.grand_total - self.doc.paid_amount
self.doc.precision("write_off_amount")) + self.doc.change_amount, self.doc.precision("write_off_amount"))
self.doc.base_write_off_amount = flt(self.doc.write_off_amount * self.doc.conversion_rate, self.doc.base_write_off_amount = flt(self.doc.write_off_amount * self.doc.conversion_rate,
self.doc.precision("base_write_off_amount")) self.doc.precision("base_write_off_amount"))

View File

@ -422,13 +422,27 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
frappe.model.round_floats_in(this.frm.doc, ["grand_total", "base_grand_total"]); frappe.model.round_floats_in(this.frm.doc, ["grand_total", "base_grand_total"]);
// rounded totals // rounded totals
this.set_rounded_total() this.set_rounded_total();
}, },
set_rounded_total: function() { set_rounded_total: function() {
var disable_rounded_total = 0;
if(frappe.meta.get_docfield(this.frm.doc.doctype, "disable_rounded_total", this.frm.doc.name)) {
disable_rounded_total = this.frm.doc.disable_rounded_total;
} else if (frappe.sys_defaults.disable_rounded_total) {
disable_rounded_total = frappe.sys_defaults.disable_rounded_total;
}
if(disable_rounded_total) {
this.frm.doc.rounded_total = 0;
this.frm.doc.base_rounded_total = 0;
return;
}
if(frappe.meta.get_docfield(this.frm.doc.doctype, "rounded_total", this.frm.doc.name)) { if(frappe.meta.get_docfield(this.frm.doc.doctype, "rounded_total", this.frm.doc.name)) {
this.frm.doc.rounded_total = round_based_on_smallest_currency_fraction(this.frm.doc.grand_total, this.frm.doc.rounded_total = round_based_on_smallest_currency_fraction(this.frm.doc.grand_total,
this.frm.doc.currency, precision("rounded_total")); this.frm.doc.currency, precision("rounded_total"));
this.frm.doc.rounding_adjustment += flt(this.frm.doc.rounded_total - this.frm.doc.grand_total,
precision("rounding_adjustment"));
} }
if(frappe.meta.get_docfield(this.frm.doc.doctype, "base_rounded_total", this.frm.doc.name)) { if(frappe.meta.get_docfield(this.frm.doc.doctype, "base_rounded_total", this.frm.doc.name)) {
var company_currency = this.get_company_currency(); var company_currency = this.get_company_currency();
@ -436,6 +450,9 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
this.frm.doc.base_rounded_total = this.frm.doc.base_rounded_total =
round_based_on_smallest_currency_fraction(this.frm.doc.base_grand_total, round_based_on_smallest_currency_fraction(this.frm.doc.base_grand_total,
company_currency, precision("base_rounded_total")); company_currency, precision("base_rounded_total"));
this.frm.doc.base_rounding_adjustment += flt(this.frm.doc.base_rounded_total -
this.frm.doc.base_grand_total, precision("rounding_adjustment"));
} }
}, },
@ -560,20 +577,22 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
if(this.frm.doc.is_return || this.frm.doc.docstatus > 0) return; if(this.frm.doc.is_return || this.frm.doc.docstatus > 0) return;
frappe.model.round_floats_in(this.frm.doc, ["grand_total", "total_advance", "write_off_amount"]); frappe.model.round_floats_in(this.frm.doc, ["grand_total", "total_advance", "write_off_amount"]);
if(this.frm.doc.party_account_currency == this.frm.doc.currency) {
var total_amount_to_pay = flt((this.frm.doc.grand_total - this.frm.doc.total_advance
- this.frm.doc.write_off_amount), precision("grand_total"));
} else {
var total_amount_to_pay = flt(
(flt(this.frm.doc.grand_total*this.frm.doc.conversion_rate, precision("grand_total"))
- this.frm.doc.total_advance - this.frm.doc.base_write_off_amount),
precision("base_grand_total")
);
}
if(this.frm.doc.doctype == "Sales Invoice" || this.frm.doc.doctype == "Purchase Invoice") { if(in_list(["Sales Invoice", "Purchase Invoice"], this.frm.doc.doctype)) {
var grand_total = this.frm.doc.rounded_total || this.frm.doc.grand_total;
if(this.frm.doc.party_account_currency == this.frm.doc.currency) {
var total_amount_to_pay = flt((grand_total - this.frm.doc.total_advance
- this.frm.doc.write_off_amount), precision("grand_total"));
} else {
var total_amount_to_pay = flt(
(flt(grand_total*this.frm.doc.conversion_rate, precision("grand_total"))
- this.frm.doc.total_advance - this.frm.doc.base_write_off_amount),
precision("base_grand_total")
);
}
frappe.model.round_floats_in(this.frm.doc, ["paid_amount"]); frappe.model.round_floats_in(this.frm.doc, ["paid_amount"]);
this.set_in_company_currency(this.frm.doc, ["paid_amount"]); this.set_in_company_currency(this.frm.doc, ["paid_amount"]);
if(this.frm.refresh_field){ if(this.frm.refresh_field){
@ -581,11 +600,10 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
this.frm.refresh_field("base_paid_amount"); this.frm.refresh_field("base_paid_amount");
} }
if(this.frm.doc.doctype == "Sales Invoice"){ if(this.frm.doc.doctype == "Sales Invoice") {
this.set_default_payment(total_amount_to_pay, update_paid_amount); this.set_default_payment(total_amount_to_pay, update_paid_amount);
this.calculate_paid_amount(); this.calculate_paid_amount();
} }
this.calculate_change_amount(); this.calculate_change_amount();
var paid_amount = (this.frm.doc.party_account_currency == this.frm.doc.currency) ? var paid_amount = (this.frm.doc.party_account_currency == this.frm.doc.currency) ?
@ -593,9 +611,6 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
this.frm.doc.outstanding_amount = flt(total_amount_to_pay - flt(paid_amount) + this.frm.doc.outstanding_amount = flt(total_amount_to_pay - flt(paid_amount) +
flt(this.frm.doc.change_amount * this.frm.doc.conversion_rate), precision("outstanding_amount")); flt(this.frm.doc.change_amount * this.frm.doc.conversion_rate), precision("outstanding_amount"));
} else if(this.frm.doc.doctype == "Purchase Invoice") {
this.frm.doc.outstanding_amount = flt(total_amount_to_pay, precision("outstanding_amount"));
} }
}, },
@ -636,7 +651,9 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
calculate_change_amount: function(){ calculate_change_amount: function(){
this.frm.doc.change_amount = 0.0; this.frm.doc.change_amount = 0.0;
this.frm.doc.base_change_amount = 0.0; this.frm.doc.base_change_amount = 0.0;
if(this.frm.doc.paid_amount > this.frm.doc.grand_total && !this.frm.doc.is_return) { if(this.frm.doc.doctype == "Sales Invoice"
&& this.frm.doc.paid_amount > this.frm.doc.grand_total && !this.frm.doc.is_return) {
var payment_types = $.map(this.frm.doc.payments, function(d) { return d.type; }); var payment_types = $.map(this.frm.doc.payments, function(d) { return d.type; });
if (in_list(payment_types, 'Cash')) { if (in_list(payment_types, 'Cash')) {
this.frm.doc.change_amount = flt(this.frm.doc.paid_amount - this.frm.doc.grand_total + this.frm.doc.change_amount = flt(this.frm.doc.paid_amount - this.frm.doc.grand_total +

View File

@ -57,7 +57,8 @@ class GlobalDefaults(Document):
self.disable_rounded_total = cint(self.disable_rounded_total) self.disable_rounded_total = cint(self.disable_rounded_total)
# Make property setters to hide rounded total fields # Make property setters to hide rounded total fields
for doctype in ("Quotation", "Sales Order", "Sales Invoice", "Delivery Note"): for doctype in ("Quotation", "Sales Order", "Sales Invoice", "Delivery Note",
"Supplier Quotation", "Purchase Order"):
make_property_setter(doctype, "base_rounded_total", "hidden", self.disable_rounded_total, "Check") make_property_setter(doctype, "base_rounded_total", "hidden", self.disable_rounded_total, "Check")
make_property_setter(doctype, "base_rounded_total", "print_hide", 1, "Check") make_property_setter(doctype, "base_rounded_total", "print_hide", 1, "Check")
@ -69,6 +70,6 @@ class GlobalDefaults(Document):
# Make property setters to hide in words fields # Make property setters to hide in words fields
for doctype in ("Quotation", "Sales Order", "Sales Invoice", "Delivery Note", for doctype in ("Quotation", "Sales Order", "Sales Invoice", "Delivery Note",
"Supplier Quotation", "Purchase Order", "Purchase Invoice", "Purchase Receipt"): "Supplier Quotation", "Purchase Order", "Purchase Invoice", "Purchase Receipt"):
make_property_setter(doctype, "in_words", "hidden", self.disable_in_words, "Check") make_property_setter(doctype, "in_words", "hidden", self.disable_in_words, "Check")
make_property_setter(doctype, "in_words", "print_hide", self.disable_in_words, "Check") make_property_setter(doctype, "in_words", "print_hide", self.disable_in_words, "Check")