diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js index 3fb8fa5fcb..ad01eb35f9 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.js +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js @@ -234,11 +234,12 @@ frappe.ui.form.on('Payment Entry', { frm.set_value(field, null); }) } else { + frm.set_value("party_type", frm.doc.payment_type=="Receive" ? "Customer" : "Supplier"); frm.events.party(frm); } }, - "mode_of_payment": function(frm) { + mode_of_payment: function(frm) { return frappe.call({ method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.get_bank_cash_account", args: { @@ -357,7 +358,8 @@ frappe.ui.form.on('Payment Entry', { paid_amount: function(frm) { frm.set_value("base_paid_amount", flt(frm.doc.paid_amount) * flt(frm.doc.source_exchange_rate)); - if(frm.doc.paid_from_account_currency == frm.doc.paid_to_account_currency) { + if(!frm.set_paid_amount_based_on_received_amount && + (frm.doc.paid_from_account_currency == frm.doc.paid_to_account_currency)) { frm.set_value("received_amount", frm.doc.paid_amount); frm.set_value("target_exchange_rate", frm.doc.source_exchange_rate); frm.set_value("base_received_amount", frm.doc.base_paid_amount); @@ -366,9 +368,19 @@ frappe.ui.form.on('Payment Entry', { frm.events.allocate_party_amount_against_ref_docs(frm, frm.doc.paid_amount); else frm.events.set_difference_amount(frm); + + frm.set_paid_amount_based_on_received_amount = false; }, received_amount: function(frm) { + frm.set_paid_amount_based_on_received_amount = true; + + if(!frm.doc.paid_amount && frm.doc.paid_from_account_currency == frm.doc.paid_to_account_currency) { + frm.set_value("paid_amount", frm.doc.received_amount); + frm.set_value("source_exchange_rate", frm.doc.target_exchange_rate); + frm.set_value("base_paid_amount", frm.doc.base_received_amount); + } + frm.set_value("base_received_amount", flt(frm.doc.received_amount) * flt(frm.doc.target_exchange_rate)); @@ -397,12 +409,15 @@ frappe.ui.form.on('Payment Entry', { }, callback: function(r, rt) { if(r.message) { + var total_invoice_outstanding_amount = 0; $.each(r.message, function(i, d) { var c = frm.add_child("references"); c.reference_doctype = d.voucher_type; c.reference_name = d.voucher_no; c.total_amount = d.invoice_amount; c.outstanding_amount = d.outstanding_amount; + if(!in_list(["Sales Order", "Purchase Order"], d.voucher_type)) + total_outstanding_amount += flt(d.outstanding_amount); var party_account_currency = frm.doc.payment_type=="Receive" ? frm.doc.paid_from_account_currency : frm.doc.paid_to_account_currency; @@ -416,6 +431,9 @@ frappe.ui.form.on('Payment Entry', { c.due_date = d.due_date } }); + + var party_amt_field = frm.doc.payment_type=="Receive" ? "paid_amount" : "received_amount"; + frm.set_value(party_amt_field, total_outstanding_amount); } frm.events.allocate_party_amount_against_ref_docs(frm, @@ -426,12 +444,14 @@ frappe.ui.form.on('Payment Entry', { allocate_party_amount_against_ref_docs: function(frm, amount) { $.each(frm.doc.references || [], function(i, row) { - if (!amount) return false; + row.allocated_amount = 0 - if(row.outstanding_amount >= amount) row.allocated_amount = amount; - else row.allocated_amount = row.outstanding_amount; + if(amount) { + if(row.outstanding_amount >= amount) row.allocated_amount = amount; + else row.allocated_amount = row.outstanding_amount; - amount -= flt(row.allocated_amount); + amount -= flt(row.allocated_amount); + } }) frm.refresh_fields() frm.events.set_total_allocated_amount(frm); diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.json b/erpnext/accounts/doctype/payment_entry/payment_entry.json index f21fe561fa..b827b7c68c 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.json +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.json @@ -27,7 +27,7 @@ "options": "PE-", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, @@ -53,7 +53,7 @@ "options": "Receive\nPay\nInternal Transfer", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, @@ -129,7 +129,7 @@ "options": "Company", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, @@ -208,7 +208,7 @@ "options": "Customer\nSupplier", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, @@ -285,7 +285,7 @@ "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 1, "report_hide": 0, @@ -337,7 +337,7 @@ "options": "Account", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, @@ -364,7 +364,7 @@ "options": "Currency", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 1, "report_hide": 0, @@ -391,7 +391,7 @@ "options": "paid_from_account_currency", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 1, "report_hide": 0, @@ -442,7 +442,7 @@ "options": "Account", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, @@ -469,7 +469,7 @@ "options": "paid_to_account_currency", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 1, "report_hide": 0, @@ -496,7 +496,7 @@ "options": "Currency", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 1, "report_hide": 0, @@ -576,7 +576,7 @@ "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, @@ -603,7 +603,7 @@ "options": "Company:company:default_currency", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 1, "report_hide": 0, @@ -654,7 +654,7 @@ "options": "paid_to_account_currency", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, @@ -680,7 +680,7 @@ "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, @@ -707,7 +707,7 @@ "options": "Company:company:default_currency", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 1, "report_hide": 0, @@ -834,7 +834,7 @@ "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 1, "report_hide": 0, @@ -939,7 +939,7 @@ "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 1, "report_hide": 0, @@ -966,7 +966,7 @@ "options": "Company:company:default_currency", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 1, "report_hide": 0, @@ -1067,7 +1067,7 @@ "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 1, "report_hide": 0, @@ -1094,7 +1094,7 @@ "options": "Company:company:default_currency", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 1, "report_hide": 0, @@ -1201,7 +1201,7 @@ "options": "Project", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, @@ -1276,7 +1276,7 @@ "options": "Letter Head", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, @@ -1302,7 +1302,7 @@ "options": "Print Heading", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, @@ -1352,7 +1352,7 @@ "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, @@ -1372,7 +1372,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2016-06-26 17:36:58.416685", + "modified": "2016-06-27 11:17:47.484139", "modified_by": "Administrator", "module": "Accounts", "name": "Payment Entry", diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index c421d3298c..a1df702ed3 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -16,17 +16,26 @@ from erpnext.controllers.accounts_controller import AccountsController class PaymentEntry(AccountsController): + def __init__(self, arg1, arg2=None): + super(PaymentEntry, self).__init__(arg1, arg2) + + self.party_account_field = None + self.party_account = None + + if self.payment_type == "Receive": + self.party_account_field = "paid_from" + self.party_account = self.paid_from + elif self.payment_type == "Pay": + self.party_account_field = "paid_to" + self.party_account = self.paid_to + def validate(self): - self.define_party_account_field() self.set_missing_values() self.validate_party_details() self.validate_bank_accounts() self.set_exchange_rate() - self.set_amounts_in_company_currency() self.validate_reference_documents() - self.set_total_allocated_amount() - self.set_unallocated_amount() - self.set_difference_amount() + self.set_amounts() self.clear_unallocated_reference_document_rows() self.set_title() @@ -35,17 +44,9 @@ class PaymentEntry(AccountsController): self.update_advance_paid() def on_cancel(self): - self.make_gl_entries() + self.make_gl_entries(cancel=1) self.update_advance_paid() - - def define_party_account_field(self): - self.party_account_field = None - - if self.payment_type == "Receive": - self.party_account_field = "paid_from" - elif self.payment_type == "Pay": - self.party_account_field = "paid_to" - + def set_missing_values(self): if self.payment_type == "Internal Transfer": for field in ("party", "party_balance", "total_allocated_amount", @@ -114,16 +115,6 @@ class PaymentEntry(AccountsController): if self.paid_to: self.target_exchange_rate = get_exchange_rate(self.paid_to_account_currency, self.company_currency) - - def set_amounts_in_company_currency(self): - self.base_paid_amount, self.base_received_amount, self.difference_amount = 0, 0, 0 - if self.paid_amount: - self.base_paid_amount = flt(flt(self.paid_amount) * flt(self.source_exchange_rate), - self.precision("base_paid_amount")) - - if self.received_amount: - self.base_received_amount = flt(flt(self.received_amount) * flt(self.target_exchange_rate), - self.precision("base_received_amount")) def validate_reference_documents(self): if self.party_type == "Customer": @@ -150,6 +141,22 @@ class PaymentEntry(AccountsController): if ref_doc.docstatus != 1: frappe.throw(_("{0} {1} must be submitted") .format(d.reference_doctype, d.reference_name)) + + def set_amounts(self): + self.set_amounts_in_company_currency() + self.set_total_allocated_amount() + self.set_unallocated_amount() + self.set_difference_amount() + + def set_amounts_in_company_currency(self): + self.base_paid_amount, self.base_received_amount, self.difference_amount = 0, 0, 0 + if self.paid_amount: + self.base_paid_amount = flt(flt(self.paid_amount) * flt(self.source_exchange_rate), + self.precision("base_paid_amount")) + + if self.received_amount: + self.base_received_amount = flt(flt(self.received_amount) * flt(self.target_exchange_rate), + self.precision("base_received_amount")) def set_total_allocated_amount(self): if self.payment_type == "Internal Transfer": @@ -203,13 +210,13 @@ class PaymentEntry(AccountsController): else: self.title = self.paid_from + " - " + self.paid_to - def make_gl_entries(self): + def make_gl_entries(self, cancel=0, adv_adj=0): gl_entries = [] self.add_party_gl_entries(gl_entries) self.add_bank_gl_entries(gl_entries) self.add_deductions_gl_entries(gl_entries) - - make_gl_entries(gl_entries, cancel = (self.docstatus==2)) + + make_gl_entries(gl_entries, cancel=cancel, adv_adj=adv_adj) def add_party_gl_entries(self, gl_entries): if self.party_account: @@ -332,6 +339,12 @@ def get_outstanding_reference_documents(args): # Get all outstanding sales /purchase invoices outstanding_invoices = get_outstanding_invoices(args.get("party_type"), args.get("party"), args.get("party_account")) + + for d in outstanding_invoices: + d.exchange_rate = 1 + if party_account_currency != company_currency \ + and d.voucher_type in ("Sales Invoice", "Purchase Invoice"): + d.exchange_rate = frappe.db.get_value(d.voucher_type, d.voucher_no, "conversion_rate") # Get all SO / PO which are not fully billed or aginst which full advance not paid orders_to_be_billed = get_orders_to_be_billed(args.get("party_type"), args.get("party"), diff --git a/erpnext/accounts/doctype/payment_entry_deduction/payment_entry_deduction.json b/erpnext/accounts/doctype/payment_entry_deduction/payment_entry_deduction.json index e800235f1c..e71d973364 100644 --- a/erpnext/accounts/doctype/payment_entry_deduction/payment_entry_deduction.json +++ b/erpnext/accounts/doctype/payment_entry_deduction/payment_entry_deduction.json @@ -52,7 +52,7 @@ "options": "Cost Center", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, @@ -97,7 +97,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2016-06-23 12:45:26.516398", + "modified": "2016-06-27 11:18:35.021945", "modified_by": "Administrator", "module": "Accounts", "name": "Payment Entry Deduction", diff --git a/erpnext/accounts/doctype/payment_entry_reference/payment_entry_reference.json b/erpnext/accounts/doctype/payment_entry_reference/payment_entry_reference.json index 62a0d17f28..5d61996199 100644 --- a/erpnext/accounts/doctype/payment_entry_reference/payment_entry_reference.json +++ b/erpnext/accounts/doctype/payment_entry_reference/payment_entry_reference.json @@ -126,7 +126,7 @@ "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 1, "report_hide": 0, @@ -201,7 +201,7 @@ "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 1, "report_hide": 0, @@ -221,7 +221,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2016-06-26 15:01:17.161402", + "modified": "2016-06-27 11:18:20.442383", "modified_by": "Administrator", "module": "Accounts", "name": "Payment Entry Reference", diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py index 832a346ee0..6868a48e6c 100644 --- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py +++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py @@ -105,8 +105,8 @@ class PaymentReconciliation(Document): 'party': self.party, 'is_advance' : e.is_advance, 'dr_or_cr' : dr_or_cr, - 'unadjusted_amt' : flt(e.amount), - 'allocated_amt' : flt(e.allocated_amount) + 'unadjusted_amount' : flt(e.amount), + 'allocated_amount' : flt(e.allocated_amount) }) if lst: diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json index c6d04c1ccc..b247e3ebfc 100755 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json @@ -2055,7 +2055,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "fieldname": "get_advances_paid", + "fieldname": "get_advances", "fieldtype": "Button", "hidden": 0, "ignore_user_permissions": 0, @@ -2066,7 +2066,7 @@ "length": 0, "no_copy": 0, "oldfieldtype": "Button", - "options": "get_advances", + "options": "", "permlevel": 0, "print_hide": 1, "print_hide_if_no_value": 0, @@ -3031,7 +3031,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2016-06-30 13:40:39.440646", + "modified": "2016-06-30 13:40:39.440648", "modified_by": "Administrator", "module": "Accounts", "name": "Purchase Invoice", diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index de654858a4..3bb402de98 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -65,7 +65,7 @@ class PurchaseInvoice(BuyingController): self.po_required() self.pr_required() self.validate_supplier_invoice() - self.validate_advance_jv("Purchase Order") + # validate cash purchase if (self.is_paid == 1): @@ -109,11 +109,6 @@ class PurchaseInvoice(BuyingController): super(PurchaseInvoice, self).set_missing_values(for_validate) - def get_advances(self): - if not self.is_return: - super(PurchaseInvoice, self).get_advances(self.credit_to, "Supplier", self.supplier, - "Purchase Invoice Advance", "advances", "debit_in_account_currency", "purchase_order") - def check_conversion_rate(self): default_currency = get_company_currency(self.company) if not default_currency: @@ -234,37 +229,6 @@ class PurchaseInvoice(BuyingController): if not submitted: frappe.throw(_("Purchase Receipt {0} is not submitted").format(d.purchase_receipt)) - - def update_against_document_in_jv(self): - """ - Links invoice and advance voucher: - 1. cancel advance voucher - 2. split into multiple rows if partially adjusted, assign against voucher - 3. submit advance voucher - """ - - lst = [] - for d in self.get('advances'): - if flt(d.allocated_amount) > 0: - args = { - 'voucher_no' : d.journal_entry, - 'voucher_detail_no' : d.jv_detail_no, - 'against_voucher_type' : 'Purchase Invoice', - 'against_voucher' : self.name, - 'account' : self.credit_to, - 'party_type': 'Supplier', - 'party': self.supplier, - 'is_advance' : 'Yes', - 'dr_or_cr' : 'debit_in_account_currency', - 'unadjusted_amt' : flt(d.advance_amount), - 'allocated_amt' : flt(d.allocated_amount) - } - lst.append(args) - - if lst: - from erpnext.accounts.utils import reconcile_against_document - reconcile_against_document(lst) - def update_status_updater_args(self): if cint(self.update_stock): self.status_updater.extend([{ diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index 5dacb9babe..bb489e71bc 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -196,8 +196,9 @@ class TestPurchaseInvoice(unittest.TestCase): pi = frappe.copy_doc(test_records[0]) pi.append("advances", { - "journal_entry": jv.name, - "jv_detail_no": jv.get("accounts")[0].name, + "reference_type": "Journal Entry", + "reference_name": jv.name, + "reference_row": jv.get("accounts")[0].name, "advance_amount": 400, "allocated_amount": 300, "remarks": jv.remark diff --git a/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.json b/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.json index 34156f5b1e..462773d4b8 100644 --- a/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.json +++ b/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.json @@ -2,29 +2,33 @@ "allow_copy": 0, "allow_import": 0, "allow_rename": 0, + "beta": 0, "creation": "2013-03-08 15:36:46", "custom": 0, "docstatus": 0, "doctype": "DocType", + "document_type": "Document", "fields": [ { "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "fieldname": "journal_entry", + "fieldname": "reference_type", "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, - "in_list_view": 1, - "label": "Journal Entry", + "in_list_view": 0, + "label": "Reference Type", "length": 0, "no_copy": 1, "oldfieldname": "journal_voucher", "oldfieldtype": "Link", - "options": "Journal Entry", + "options": "DocType", "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "print_width": "180px", "read_only": 1, "report_hide": 0, @@ -38,19 +42,75 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "fieldname": "jv_detail_no", + "fieldname": "reference_name", + "fieldtype": "Dynamic Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 1, + "label": "Reference Name", + "length": 0, + "no_copy": 1, + "options": "reference_type", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "remarks", + "fieldtype": "Read Only", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 1, + "label": "Remarks", + "length": 0, + "no_copy": 1, + "oldfieldname": "remarks", + "oldfieldtype": "Small Text", + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": "150px", + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0, + "width": "150px" + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "reference_row", "fieldtype": "Data", "hidden": 1, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, - "label": "Journal Entry Detail No", + "label": "Reference Row", "length": 0, "no_copy": 1, "oldfieldname": "jv_detail_no", "oldfieldtype": "Date", "permlevel": 0, "print_hide": 1, + "print_hide_if_no_value": 0, "print_width": "80px", "read_only": 1, "report_hide": 0, @@ -60,32 +120,6 @@ "unique": 0, "width": "80px" }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "fieldname": "remarks", - "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 1, - "label": "Remarks", - "length": 0, - "no_copy": 1, - "oldfieldname": "remarks", - "oldfieldtype": "Small Text", - "permlevel": 0, - "print_hide": 0, - "print_width": "150px", - "read_only": 1, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0, - "width": "150px" - }, { "allow_on_submit": 0, "bold": 0, @@ -94,12 +128,14 @@ "fieldtype": "Column Break", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "length": 0, "no_copy": 0, "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -115,6 +151,7 @@ "fieldtype": "Currency", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, "label": "Advance Amount", @@ -125,6 +162,7 @@ "options": "party_account_currency", "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "print_width": "100px", "read_only": 1, "report_hide": 0, @@ -142,6 +180,7 @@ "fieldtype": "Currency", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, "label": "Allocated Amount", @@ -152,6 +191,7 @@ "options": "party_account_currency", "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "print_width": "100px", "read_only": 0, "report_hide": 0, @@ -165,18 +205,23 @@ "hide_heading": 0, "hide_toolbar": 0, "idx": 1, + "image_view": 0, "in_create": 0, "in_dialog": 0, "is_submittable": 0, "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2015-11-16 06:29:53.288895", + "menu_index": 0, + "modified": "2016-06-27 12:37:42.845967", "modified_by": "Administrator", "module": "Accounts", "name": "Purchase Invoice Advance", "owner": "Administrator", "permissions": [], + "quick_entry": 1, "read_only": 0, - "read_only_onload": 0 + "read_only_onload": 0, + "track_seen": 0, + "version": 0 } \ No newline at end of file diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index d64a024222..09ff5b23a2 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -244,7 +244,7 @@ $.extend(cur_frm.cscript, new erpnext.accounts.SalesInvoiceController({frm: cur_ // Hide Fields // ------------ cur_frm.cscript.hide_fields = function(doc) { - parent_fields = ['project', 'due_date', 'is_opening', 'source', 'total_advance', 'get_advances_received', + parent_fields = ['project', 'due_date', 'is_opening', 'source', 'total_advance', 'get_advances', 'advances', 'sales_partner', 'commission_rate', 'total_commission', 'advances', 'from_date', 'to_date']; if(cint(doc.is_pos) == 1) { diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json index 308db38d61..746209f20f 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json @@ -2019,7 +2019,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "fieldname": "get_advances_received", + "fieldname": "get_advances", "fieldtype": "Button", "hidden": 0, "ignore_user_permissions": 0, @@ -2030,7 +2030,7 @@ "length": 0, "no_copy": 0, "oldfieldtype": "Button", - "options": "get_advances", + "options": "", "permlevel": 0, "print_hide": 1, "print_hide_if_no_value": 0, @@ -3676,7 +3676,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2016-07-02 20:10:14.146763", + "modified": "2016-07-02 20:10:14.146963", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice", diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 470ea913dd..a6fbff739b 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -77,7 +77,6 @@ class SalesInvoice(SellingController): self.check_close_sales_order("sales_order") self.validate_debit_to_acc() self.clear_unallocated_advances("Sales Invoice Advance", "advances") - self.validate_advance_jv("Sales Order") self.add_remarks() self.validate_write_off_account() self.validate_fixed_asset() @@ -294,44 +293,9 @@ class SalesInvoice(SellingController): return pos - def get_advances(self): - if not self.is_return: - super(SalesInvoice, self).get_advances(self.debit_to, "Customer", self.customer, - "Sales Invoice Advance", "advances", "credit_in_account_currency", "sales_order") - def get_company_abbr(self): return frappe.db.sql("select abbr from tabCompany where name=%s", self.company)[0][0] - def update_against_document_in_jv(self): - """ - Links invoice and advance voucher: - 1. cancel advance voucher - 2. split into multiple rows if partially adjusted, assign against voucher - 3. submit advance voucher - """ - - lst = [] - for d in self.get('advances'): - if flt(d.allocated_amount) > 0: - args = { - 'voucher_no' : d.journal_entry, - 'voucher_detail_no' : d.jv_detail_no, - 'against_voucher_type' : 'Sales Invoice', - 'against_voucher' : self.name, - 'account' : self.debit_to, - 'party_type': 'Customer', - 'party': self.customer, - 'is_advance' : 'Yes', - 'dr_or_cr' : 'credit_in_account_currency', - 'unadjusted_amt' : flt(d.advance_amount), - 'allocated_amt' : flt(d.allocated_amount) - } - lst.append(args) - - if lst: - from erpnext.accounts.utils import reconcile_against_document - reconcile_against_document(lst) - def validate_debit_to_acc(self): account = frappe.db.get_value("Account", self.debit_to, ["account_type", "report_type", "account_currency"], as_dict=True) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index cc3d95227c..ec63b1f1d2 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -676,8 +676,9 @@ class TestSalesInvoice(unittest.TestCase): si = frappe.copy_doc(test_records[0]) si.append("advances", { "doctype": "Sales Invoice Advance", - "journal_entry": jv.name, - "jv_detail_no": jv.get("accounts")[0].name, + "reference_type": "Journal Entry", + "reference_name": jv.name, + "reference_row": jv.get("accounts")[0].name, "advance_amount": 400, "allocated_amount": 300, "remarks": jv.remark diff --git a/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.json b/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.json index b1fae8e47d..06c67358b2 100644 --- a/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.json +++ b/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.json @@ -2,29 +2,33 @@ "allow_copy": 0, "allow_import": 0, "allow_rename": 0, + "beta": 0, "creation": "2013-02-22 01:27:41", "custom": 0, "docstatus": 0, "doctype": "DocType", + "document_type": "Document", "fields": [ { "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "fieldname": "journal_entry", + "fieldname": "reference_type", "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, - "in_list_view": 1, - "label": "Journal Entry", + "in_list_view": 0, + "label": "Reference Type", "length": 0, "no_copy": 1, "oldfieldname": "journal_voucher", "oldfieldtype": "Link", - "options": "Journal Entry", + "options": "DocType", "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "print_width": "250px", "read_only": 1, "report_hide": 0, @@ -38,10 +42,37 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "fieldname": "remarks", - "fieldtype": "Small Text", + "fieldname": "reference_name", + "fieldtype": "Dynamic Link", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 1, + "label": "Reference Name", + "length": 0, + "no_copy": 1, + "options": "reference_type", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "remarks", + "fieldtype": "Read Only", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, "label": "Remarks", @@ -51,8 +82,9 @@ "oldfieldtype": "Small Text", "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "print_width": "150px", - "read_only": 1, + "read_only": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -64,19 +96,21 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "fieldname": "jv_detail_no", + "fieldname": "reference_row", "fieldtype": "Data", "hidden": 1, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, - "label": "Journal Entry Detail No", + "label": "Reference Row", "length": 0, "no_copy": 1, "oldfieldname": "jv_detail_no", "oldfieldtype": "Data", "permlevel": 0, "print_hide": 1, + "print_hide_if_no_value": 0, "print_width": "120px", "read_only": 1, "report_hide": 0, @@ -94,12 +128,14 @@ "fieldtype": "Column Break", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "length": 0, "no_copy": 0, "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -115,6 +151,7 @@ "fieldtype": "Currency", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, "label": "Advance amount", @@ -125,6 +162,7 @@ "options": "party_account_currency", "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "print_width": "120px", "read_only": 1, "report_hide": 0, @@ -142,6 +180,7 @@ "fieldtype": "Currency", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, "label": "Allocated amount", @@ -152,6 +191,7 @@ "options": "party_account_currency", "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "print_width": "120px", "read_only": 0, "report_hide": 0, @@ -165,18 +205,24 @@ "hide_heading": 0, "hide_toolbar": 0, "idx": 1, + "image_view": 0, "in_create": 0, "in_dialog": 0, "is_submittable": 0, "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2015-11-16 06:29:56.263776", + "menu_index": 0, + "modified": "2016-06-27 12:38:58.845134", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice Advance", "owner": "Administrator", "permissions": [], + "quick_entry": 1, "read_only": 0, - "read_only_onload": 0 + "read_only_onload": 0, + "sort_order": "DESC", + "track_seen": 0, + "version": 0 } \ No newline at end of file diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index 20416e5381..957460324f 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -172,53 +172,77 @@ def reconcile_against_document(args): Cancel JV, Update aginst document, split if required and resubmit jv """ for d in args: - check_if_jv_modified(d) + + check_if_advance_entry_modified(d) validate_allocated_amount(d) + + # cancel advance entry + doc = frappe.get_doc(d.voucher_type, d.voucher_no) - # cancel JV - jv_obj = frappe.get_doc('Journal Entry', d['voucher_no']) + doc.make_gl_entries(cancel=1, adv_adj=1) - jv_obj.make_gl_entries(cancel=1, adv_adj=1) + # update ref in advance entry + if d.voucher_type == "Journal Entry": + update_reference_in_journal_entry(d, doc) + else: + update_reference_in_payment_entry(d, doc) - # update ref in JV Detail - update_against_doc(d, jv_obj) + # re-submit advance entry + doc = frappe.get_doc(d.voucher_type, d.voucher_no) + doc.make_gl_entries(cancel = 0, adv_adj =1) - # re-submit JV - jv_obj = frappe.get_doc('Journal Entry', d['voucher_no']) - jv_obj.make_gl_entries(cancel = 0, adv_adj =1) - - -def check_if_jv_modified(args): +def check_if_advance_entry_modified(args): """ check if there is already a voucher reference check if amount is same check if jv is submitted """ - ret = frappe.db.sql(""" - select t2.{dr_or_cr} from `tabJournal Entry` t1, `tabJournal Entry Account` t2 - where t1.name = t2.parent and t2.account = %(account)s - and t2.party_type = %(party_type)s and t2.party = %(party)s - and (t2.reference_type is null or t2.reference_type in ("", "Sales Order", "Purchase Order")) - and t1.name = %(voucher_no)s and t2.name = %(voucher_detail_no)s - and t1.docstatus=1 """.format(dr_or_cr = args.get("dr_or_cr")), args) + ret = None + if args.voucher_type == "Journal Entry": + ret = frappe.db.sql(""" + select t2.{dr_or_cr} from `tabJournal Entry` t1, `tabJournal Entry Account` t2 + where t1.name = t2.parent and t2.account = %(account)s + and t2.party_type = %(party_type)s and t2.party = %(party)s + and (t2.reference_type is null or t2.reference_type in ("", "Sales Order", "Purchase Order")) + and t1.name = %(voucher_no)s and t2.name = %(voucher_detail_no)s + and t1.docstatus=1 """.format(dr_or_cr = args.get("dr_or_cr")), args) + else: + party_account_field = "paid_from" if args.party_type == "Customer" else "paid_to" + if args.voucher_detail_no: + ret = frappe.db.sql("""select t1.name + from `tabPayment Entry` t1, `tabPayment Entry Reference` t2 + where + t1.name = t2.parent and t1.docstatus = 1 + and t1.name = %(voucher_no)s and t2.name = %(voucher_detail_no)s + and t1.party_type = %(party_type)s and t1.party = %(party)s and t1.{0} = %(account)s + and t2.reference_doctype in ("", "Sales Order", "Purchase Order") + and t2.allocated_amount = %(unadjusted_amount)s + """.format(party_account_field), args) + else: + ret = frappe.db.sql("""select name from `tabPayment Entry` + where + name = %(voucher_no)s and docstatus = 1 + and party_type = %(party_type)s and party = %(party)s and {0} = %(account)s + and unallocated_amount = %(unadjusted_amount)s + """.format(party_account_field), args) if not ret: throw(_("""Payment Entry has been modified after you pulled it. Please pull it again.""")) def validate_allocated_amount(args): - if args.get("allocated_amt") < 0: + if args.get("allocated_amount") < 0: throw(_("Allocated amount can not be negative")) - elif args.get("allocated_amt") > args.get("unadjusted_amt"): - throw(_("Allocated amount can not greater than unadusted amount")) + elif args.get("allocated_amount") > args.get("unadjusted_amount"): + throw(_("Allocated amount can not greater than unadjusted amount")) -def update_against_doc(d, jv_obj): +def update_reference_in_journal_entry(d, jv_obj): """ Updates against document, if partial amount splits into rows """ jv_detail = jv_obj.get("accounts", {"name": d["voucher_detail_no"]})[0] - jv_detail.set(d["dr_or_cr"], d["allocated_amt"]) + jv_detail.set(d["dr_or_cr"], d["allocated_amount"]) jv_detail.set('debit' if d['dr_or_cr']=='debit_in_account_currency' else 'credit', - d["allocated_amt"]*flt(jv_detail.exchange_rate)) + d["allocated_amount"]*flt(jv_detail.exchange_rate)) original_reference_type = jv_detail.reference_type original_reference_name = jv_detail.reference_name @@ -226,14 +250,14 @@ def update_against_doc(d, jv_obj): jv_detail.set("reference_type", d["against_voucher_type"]) jv_detail.set("reference_name", d["against_voucher"]) - if d['allocated_amt'] < d['unadjusted_amt']: + if d['allocated_amount'] < d['unadjusted_amount']: jvd = frappe.db.sql(""" select cost_center, balance, against_account, is_advance, account_type, exchange_rate, account_currency from `tabJournal Entry Account` where name = %s """, d['voucher_detail_no'], as_dict=True) - amount_in_account_currency = flt(d['unadjusted_amt']) - flt(d['allocated_amt']) + amount_in_account_currency = flt(d['unadjusted_amount']) - flt(d['allocated_amount']) amount_in_company_currency = amount_in_account_currency * flt(jvd[0]['exchange_rate']) # new entry with balance amount @@ -263,6 +287,37 @@ def update_against_doc(d, jv_obj): # will work as update after submit jv_obj.flags.ignore_validate_update_after_submit = True jv_obj.save(ignore_permissions=True) + +def update_reference_in_payment_entry(d, payment_entry): + reference_details = { + "reference_doctype": d.against_voucher_type, + "reference_name": d.against_voucher, + "total_amount": d.grand_total, + "outstanding_amount": d.outstanding_amount, + "allocated_amount": d.allocated_amount, + "exchange_rate": d.exchange_rate + } + + if d.voucher_detail_no: + existing_row = payment_entry.get("references", {"name": d["voucher_detail_no"]})[0] + original_row = existing_row.as_dict().copy() + existing_row.update(reference_details) + + if d.allocated_amount < original_row.allocated_amount: + new_row = payment_entry.append("references") + new_row.docstatus = 1 + for field in reference_details.keys(): + new_row.set(field, original_row[field]) + + new_row.allocated_amount = original_row.allocated_amount - d.allocated_amount + else: + new_row = payment_entry.append("references") + new_row.docstatus = 1 + new_row.update(reference_details) + + payment_entry.flags.ignore_validate_update_after_submit = True + payment_entry.set_amounts() + payment_entry.save(ignore_permissions=True) def remove_against_link_from_jv(ref_type, ref_no): linked_jv = frappe.db.sql_list("""select parent from `tabJournal Entry Account` @@ -425,10 +480,9 @@ def get_outstanding_invoices(party_type, party, account, condition=None): 'payment_amount': flt(d.payment_amount), 'outstanding_amount': flt(d.invoice_amount - d.payment_amount, precision), 'due_date': frappe.db.get_value(d.voucher_type, d.voucher_no, "due_date"), - 'exchange_rate': frappe.db.get_value(d.voucher_type, d.voucher_no, "conversion_rate") }) - outstanding_invoices = sorted(outstanding_invoices, key=lambda k: k['due_date']) + outstanding_invoices = sorted(outstanding_invoices, key=lambda k: k['due_date'] or getdate(nowdate())) return outstanding_invoices diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index d4b2221095..ec1bf46ec5 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -308,7 +308,7 @@ def make_purchase_invoice(source_name, target_doc=None): def postprocess(source, target): set_missing_values(source, target) #Get the advance paid Journal Entries in Purchase Invoice Advance - target.get_advances() + target.set_advances() def update_item(obj, target, source_parent): target.amount = flt(obj.amount) - flt(obj.billed_amt) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 36abae87d0..58c6bb12d8 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -42,6 +42,7 @@ class AccountsController(TransactionBase): if self.doctype in ("Sales Invoice", "Purchase Invoice") and not self.is_return: self.validate_due_date() + self.validate_advance_entries() if self.meta.get_field("taxes_and_charges"): self.validate_enabled_taxes_and_charges() @@ -276,22 +277,69 @@ class AccountsController(TransactionBase): frappe.db.sql("""delete from `tab%s` where parentfield=%s and parent = %s and allocated_amount = 0""" % (childtype, '%s', '%s'), (parentfield, self.name)) - def get_advances(self, account_head, party_type, party, child_doctype, parentfield, dr_or_cr, against_order_field): + def set_advances(self): """Returns list of advances against Account, Party, Reference""" - order_list = list(set([d.get(against_order_field) for d in self.get("items") if d.get(against_order_field)])) + + res = self.get_advance_entries() - # conver sales_order to "Sales Order" - reference_type = against_order_field.replace("_", " ").title() + self.set("advances", []) + for d in res: + self.append("advances", { + "doctype": self.doctype + " Advance", + "reference_type": d.reference_type, + "reference_name": d.reference_name, + "reference_row": d.reference_row, + "remarks": d.remarks, + "advance_amount": flt(d.amount), + "allocated_amount": flt(d.amount) if d.against_order else 0 + }) + + def get_advance_entries(self, include_unallocated=True): + if self.doctype == "Sales Invoice": + party_account = self.debit_to + party_type = "Customer" + party = self.customer + amount_field = "credit_in_account_currency" + order_field = "sales_order" + order_doctype = "Sales Order" + else: + party_account = self.credit_to + party_type = "Supplier" + party = self.supplier + amount_field = "debit_in_account_currency" + order_field = "purchase_order" + order_doctype = "Purchase Order" + + order_list = list(set([d.get(order_field) + for d in self.get("items") if d.get(order_field)])) + + journal_entries = self.get_advance_journal_entries(party_type, party, party_account, + amount_field, order_doctype, order_list, include_unallocated) + + payment_entries = self.get_advance_payment_entries(party_type, party, party_account, + order_doctype, order_list, include_unallocated) + + res = journal_entries + payment_entries + + return res + + def get_advance_journal_entries(self, party_type, party, party_account, amount_field, + order_doctype, order_list, include_unallocated=True): + conditions = [] + if include_unallocated: + conditions.append("ifnull(t2.reference_name, '')=''") - condition = "" if order_list: - in_placeholder = ', '.join(['%s'] * len(order_list)) - condition = "or (t2.reference_type = '{0}' and ifnull(t2.reference_name, '') in ({1}))"\ - .format(reference_type, in_placeholder) - - res = frappe.db.sql(""" + order_condition = ', '.join(['%s'] * len(order_list)) + conditions.append(" (t2.reference_type = '{0}' and ifnull(t2.reference_name, '') in ({1}))"\ + .format(order_doctype, order_condition)) + + reference_condition = " and (" + " or ".join(conditions) + ")" if conditions else "" + + journal_entries = frappe.db.sql(""" select - t1.name as jv_no, t1.remark, t2.{0} as amount, t2.name as jv_detail_no, + "Journal Entry" as reference_type, t1.name as reference_name, + t1.remark as remarks, t2.{0} as amount, t2.name as reference_row, t2.reference_name as against_order from `tabJournal Entry` t1, `tabJournal Entry Account` t2 @@ -299,48 +347,98 @@ class AccountsController(TransactionBase): t1.name = t2.parent and t2.account = %s and t2.party_type = %s and t2.party = %s and t2.is_advance = 'Yes' and t1.docstatus = 1 - and (ifnull(t2.reference_type, '')='' {1}) - order by t1.posting_date""".format(dr_or_cr, condition), - [account_head, party_type, party] + order_list, as_dict=1) - - self.set(parentfield, []) - for d in res: - self.append(parentfield, { - "doctype": child_doctype, - "journal_entry": d.jv_no, - "jv_detail_no": d.jv_detail_no, - "remarks": d.remark, - "advance_amount": flt(d.amount), - "allocated_amount": flt(d.amount) if d.against_order else 0 - }) - - def validate_advance_jv(self, reference_type): - against_order_field = frappe.scrub(reference_type) - order_list = list(set([d.get(against_order_field) for d in self.get("items") if d.get(against_order_field)])) + and (ifnull(t2.reference_name, '')='' {1}) + order by t1.posting_date""".format(amount_field, reference_condition), + [party_account, party_type, party] + order_list, as_dict=1) + + return list(journal_entries) + + def get_advance_payment_entries(self, party_type, party, party_account, + order_doctype, order_list, include_unallocated=True): + party_account_field = "paid_from" if party_type == "Customer" else "paid_to" + payment_type = "Receive" if party_type == "Customer" else "Pay" + payment_entries_against_order, unallocated_payment_entries = [], [] + if order_list: - account = self.get("debit_to" if self.doctype=="Sales Invoice" else "credit_to") + payment_entries_against_order = frappe.db.sql(""" + select + "Payment Entry" as reference_type, t1.name as reference_name, + t1.remarks, t2.allocated_amount as amount, t2.name as reference_row, + t2.reference_name as against_order + from `tabPayment Entry` t1, `tabPayment Entry Reference` t2 + where + t1.name = t2.parent and t1.{0} = %s and t1.payment_type = %s + and t1.party_type = %s and t1.party = %s and t1.docstatus = 1 + and t2.reference_doctype = %s and t2.reference_name in ({1}) + """.format(party_account_field, ', '.join(['%s'] * len(order_list))), + [party_account, payment_type, party_type, party, order_doctype] + order_list, as_dict=1) + + if include_unallocated: + unallocated_payment_entries = frappe.db.sql(""" + select "Payment Entry" as reference_type, name as reference_name, + remarks, unallocated_amount as amount + from `tabPayment Entry` + where + {0} = %s and party_type = %s and party = %s and payment_type = %s + and docstatus = 1 and unallocated_amount > 0 + """.format(party_account_field), (party_account, party_type, party, payment_type), as_dict=1) + + return list(payment_entries_against_order) + list(unallocated_payment_entries) - jv_against_order = frappe.db.sql("""select parent, reference_name as against_order - from `tabJournal Entry Account` - where docstatus=1 and account=%s and ifnull(is_advance, 'No') = 'Yes' - and reference_type=%s - and ifnull(reference_name, '') in ({0}) - group by parent, reference_name""".format(', '.join(['%s']*len(order_list))), - tuple([account, reference_type] + order_list), as_dict=1) - - if jv_against_order: - order_jv_map = {} - for d in jv_against_order: - order_jv_map.setdefault(d.against_order, []).append(d.parent) - - advance_jv_against_si = [d.journal_entry for d in self.get("advances")] - - for order, jv_list in order_jv_map.items(): - for jv in jv_list: - if not advance_jv_against_si or jv not in advance_jv_against_si: - frappe.msgprint(_("Journal Entry {0} is linked against Order {1}, check if it should be pulled as advance in this invoice.") - .format(jv, order)) + def validate_advance_entries(self): + advance_entries = self.get_advance_entries(include_unallocated=False) + + if advance_entries: + advance_entries_against_si = [d.reference_name for d in self.get("advances")] + for d in advance_entries: + if not advance_entries_against_si or d.reference_name not in advance_entries_against_si: + frappe.msgprint(_("Payment Entry {0} is linked against Order {1}, check if it should be pulled as advance in this invoice.") + .format(d.reference_name, d.against_order)) + + def update_against_document_in_jv(self): + """ + Links invoice and advance voucher: + 1. cancel advance voucher + 2. split into multiple rows if partially adjusted, assign against voucher + 3. submit advance voucher + """ + + if self.doctype == "Sales Invoice": + party = self.customer + party_account = self.debit_to + dr_or_cr = "credit_in_account_currency" + else: + party = self.supplier + party_account = self.credit_to + dr_or_cr = "debit_in_account_currency" + lst = [] + for d in self.get('advances'): + if flt(d.allocated_amount) > 0: + args = frappe._dict({ + 'voucher_type': d.reference_type, + 'voucher_no' : d.reference_name, + 'voucher_detail_no' : d.reference_row, + 'against_voucher_type' : self.doctype, + 'against_voucher' : self.name, + 'account' : party_account, + 'party_type': 'Customer', + 'party': party, + 'is_advance' : 'Yes', + 'dr_or_cr' : dr_or_cr, + 'unadjusted_amount' : flt(d.advance_amount), + 'allocated_amount' : flt(d.allocated_amount), + 'exchange_rate': (self.conversion_rate + if self.party_account_currency != self.company_currency else 1), + 'grand_total': (self.base_grand_total + if self.party_account_currency==self.company_currency else self.grand_total), + 'outstanding_amount': self.outstanding_amount + }) + lst.append(args) + + if lst: + from erpnext.accounts.utils import reconcile_against_document + reconcile_against_document(lst) def validate_multiple_billing(self, ref_dt, item_ref_dn, based_on, parentfield): from erpnext.controllers.status_updater import get_tolerance_for diff --git a/erpnext/patches/v6_4/fix_journal_entries_due_to_reconciliation.py b/erpnext/patches/v6_4/fix_journal_entries_due_to_reconciliation.py index 37b6c63af2..b1464d5e2a 100644 --- a/erpnext/patches/v6_4/fix_journal_entries_due_to_reconciliation.py +++ b/erpnext/patches/v6_4/fix_journal_entries_due_to_reconciliation.py @@ -5,6 +5,9 @@ from __future__ import unicode_literals import frappe def execute(): + frappe.reload_doctype("Sales Invoice Advance") + frappe.reload_doctype("Purchase Invoice Advance") + je_rows = frappe.db.sql(""" select name, parent, reference_type, reference_name, debit, credit from `tabJournal Entry Account` @@ -23,7 +26,7 @@ def execute(): is_advance_entry=None if d.reference_type in ("Sales Invoice", "Purchase Invoice") and d.reference_name: is_advance_entry = frappe.db.sql("""select name from `tab{0}` - where journal_entry=%s and jv_detail_no=%s + where reference_name=%s and reference_row=%s and ifnull(allocated_amount, 0) > 0 and docstatus=1""" .format(d.reference_type + " Advance"), (d.parent, d.name)) diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index ce11c8a80b..ad6901c8c3 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -4,6 +4,16 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ setup: function() { this._super(); + + if(in_list(["Sales Invoice", "Purchase Invoice"], this.frm.doc.doctype)) { + this.frm.get_field('advances').grid.editable_fields = [ + {fieldname: 'reference_name', columns: 2}, + {fieldname: 'remarks', columns: 3}, + {fieldname: 'advance_amount', columns: 3}, + {fieldname: 'allocated_amount', columns: 3} + ]; + } + frappe.ui.form.on(this.frm.doctype + " Item", "rate", function(frm, cdt, cdn) { var item = frappe.get_doc(cdt, cdn); frappe.model.round_floats_in(item, ["rate", "price_list_rate"]); @@ -978,5 +988,17 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ if(!this.item_selector) { this.item_selector = new erpnext.ItemSelector({frm: this.frm}); } + }, + + get_advances: function() { + if(!this.frm.is_return) { + return this.frm.call({ + method: "set_advances", + doc: this.frm.doc, + callback: function(r, rt) { + refresh_field("advances"); + } + }) + } } }); \ No newline at end of file diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 8103756cfd..8fcd89de6e 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -441,7 +441,7 @@ def make_sales_invoice(source_name, target_doc=None, ignore_permissions=False): def postprocess(source, target): set_missing_values(source, target) #Get the advance paid Journal Entries in Sales Invoice Advance - target.get_advances() + target.set_advances() def set_missing_values(source, target): target.is_pos = 0