def test_purchase_invoice_with_advance(self):
        from erpnext.accounts.doctype.journal_entry.test_journal_entry \
         import test_records as jv_test_records
        from erpnext.accounts.utils import get_balance_on_voucher

        jv = frappe.copy_doc(jv_test_records[1])
        jv.insert()
        jv.submit()

        pi = frappe.copy_doc(test_records[0])
        pi.disable_rounded_total = 1
        pi.allocate_advances_automatically = 0
        pi.append(
            "advances", {
                "reference_type": "Journal Entry",
                "reference_name": jv.name,
                "advance_amount": 400,
                "allocated_amount": 300,
                "remarks": jv.remark
            })
        pi.insert()

        self.assertEqual(pi.outstanding_amount, 1212.30)

        pi.disable_rounded_total = 0
        pi.get("payment_schedule")[0].payment_amount = 1512.0
        pi.save()
        pi.submit()
        pi.load_from_db()

        self.assertEqual(pi.outstanding_amount, 1212.0)
        self.assertEqual(
            get_balance_on_voucher(pi.doctype, pi.name, "Supplier",
                                   pi.supplier, pi.credit_to), 1212.0)
        self.assertEqual(
            get_balance_on_voucher(jv.doctype, jv.name, "Supplier",
                                   pi.supplier, pi.credit_to), -100.0)

        self.assertTrue(
            frappe.db.sql(
                """select name from `tabJournal Entry Account`
			where reference_type='Purchase Invoice'
			and reference_name=%s and debit_in_account_currency=300""", pi.name))

        pi.cancel()

        self.assertFalse(
            frappe.db.sql(
                """select name from `tabJournal Entry Account`
			where reference_type='Purchase Invoice' and reference_name=%s""", pi.name))

        self.assertEqual(
            get_balance_on_voucher(jv.doctype, jv.name, "Supplier",
                                   pi.supplier, pi.credit_to), -400.0)
    def test_debit_note(self):
        from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
        from erpnext.accounts.utils import get_balance_on_voucher

        pi = make_purchase_invoice(item_code="_Test Item",
                                   qty=(5 * -1),
                                   rate=500,
                                   is_return=1)

        outstanding_amount = get_balance_on_voucher(pi.doctype, pi.name,
                                                    "Supplier", pi.supplier,
                                                    "Creditors - _TC")

        self.assertEqual(pi.outstanding_amount, outstanding_amount)

        pe = get_payment_entry("Purchase Invoice",
                               pi.name,
                               bank_account="_Test Bank - _TC")
        pe.reference_no = "1"
        pe.reference_date = nowdate()
        pe.paid_from_account_currency = pi.currency
        pe.paid_to_account_currency = pi.currency
        pe.source_exchange_rate = 1
        pe.target_exchange_rate = 1
        pe.paid_amount = pi.grand_total * -1
        pe.insert()
        pe.submit()

        pi_doc = frappe.get_doc('Purchase Invoice', pi.name)
        self.assertEqual(pi_doc.outstanding_amount, 0)
Esempio n. 3
0
def update_outstanding_amt(voucher_type,
                           voucher_no,
                           account,
                           party_type,
                           party,
                           on_cancel=False):
    # Update outstanding amt on against voucher

    dr_or_cr = None
    if voucher_type in [
            "Sales Invoice", "Purchase Invoice", "Landed Cost Voucher", "Fees",
            "Expense Claim"
    ]:
        fieldname = "outstanding_amount"
    elif voucher_type == "Employee Advance":
        fieldname = "balance_amount"
        dr_or_cr = "debit_in_account_currency - credit_in_account_currency"
    else:
        return

    bal = get_balance_on_voucher(voucher_type,
                                 voucher_no,
                                 party_type,
                                 party,
                                 account,
                                 dr_or_cr=dr_or_cr)
    ref_doc = frappe.get_doc(voucher_type, voucher_no)
    ref_doc.db_set(fieldname, bal)
    ref_doc.set_status(update=True)
Esempio n. 4
0
def update_outstanding_amt(voucher_type,
                           voucher_no,
                           account,
                           party_type,
                           party,
                           on_cancel=False):
    # Update outstanding amt on against voucher
    if voucher_type in [
            "Sales Invoice", "Purchase Invoice", "Landed Cost Voucher", "Fees"
    ]:
        bal = get_balance_on_voucher(voucher_type, voucher_no, party_type,
                                     party, account)
        ref_doc = frappe.get_doc(voucher_type, voucher_no)
        ref_doc.db_set('outstanding_amount', bal)
        ref_doc.set_status(update=True)
def get_outstanding(args):
	if not frappe.has_permission("Account"):
		frappe.msgprint(_("No Permission"), raise_exception=1)

	if isinstance(args, string_types):
		args = json.loads(args)

	company_currency = erpnext.get_company_currency(args.get("company"))

	if args.get("doctype") == "Journal Entry":
		against_jv_amount = get_balance_on_voucher("Journal Entry", args.get("docname"), args.get("party_type"),
			args.get("party"), args.get("account"), dr_or_cr="debit_in_account_currency - credit_in_account_currency")

		amount_field = "credit_in_account_currency" if against_jv_amount >= 0 else "debit_in_account_currency"
		return {
			amount_field: abs(against_jv_amount)
		}
	elif args.get("doctype") in ("Sales Invoice", "Purchase Invoice"):
		party_type = "Customer" if args.get("doctype") == "Sales Invoice" else "Supplier"
		invoice = frappe.db.get_value(args["doctype"], args["docname"],
			["outstanding_amount", "conversion_rate", scrub(party_type)]
				+ (["letter_of_credit"] if args.get("doctype") == "Purchase Invoice" else []), as_dict=1)

		if invoice.get("letter_of_credit"):
			party_type = "Letter of Credit"

		exchange_rate = invoice.conversion_rate if (args.get("account_currency") != company_currency) else 1

		if args["doctype"] == "Sales Invoice":
			amount_field = "credit_in_account_currency" \
				if flt(invoice.outstanding_amount) > 0 else "debit_in_account_currency"
		else:
			amount_field = "debit_in_account_currency" \
				if flt(invoice.outstanding_amount) > 0 else "credit_in_account_currency"

		return {
			amount_field: abs(flt(invoice.outstanding_amount)),
			"exchange_rate": exchange_rate,
			"party_type": party_type,
			"party": invoice.get(scrub(party_type))
		}
	def validate_jv_party_references(self):
		for reference_name, acc_amounts in iteritems(self.jv_party_references):
			for (account, party_type, party), amount in iteritems(acc_amounts):
				if amount == 0:
					continue

				if amount > 0:
					bal_dr_or_cr = "credit_in_account_currency - debit_in_account_currency"
					dr_or_cr = "credit"
				else:
					bal_dr_or_cr = "debit_in_account_currency - credit_in_account_currency"
					dr_or_cr = "debit"

				jv_balance = get_balance_on_voucher("Journal Entry", reference_name, party_type, party, account, bal_dr_or_cr)
				if jv_balance <= 0:
					frappe.throw(_("Journal Entry {0} does not have any {1} outstanding balance for party {2}")
						.format(reference_name, dr_or_cr, party))
				else:
					amount = abs(amount)
					if amount > jv_balance:
						frappe.throw(_("Referenced amount {0} to Journal Entry {1} for party {2} is greater than the outstanding balance {3}")
							.format(amount, reference_name, party, jv_balance))
Esempio n. 7
0
    def test_jv_payable_advance_payment_voucher_balance(self):
        # Advance payment
        payment_jv = make_journal_entry("_Test Payable - _TC",
                                        "_Test Account Shipping Charges - _TC",
                                        500,
                                        save=False)
        payment_jv.get("accounts")[0].update({
            "party_type": "Supplier",
            "party": "_Test Supplier"
        })
        payment_jv.insert()
        payment_jv.submit()
        payment_balance = get_balance_on_voucher(payment_jv.doctype,
                                                 payment_jv.name, "Supplier",
                                                 "_Test Supplier",
                                                 "_Test Payable - _TC")
        self.assertEqual(payment_balance, -500)

        # Attempt to allocate an advance payment against another advance payment
        payment_jv2 = make_journal_entry(
            "_Test Payable - _TC",
            "_Test Account Shipping Charges - _TC",
            100,
            save=False)
        payment_jv2.get("accounts")[0].update({
            "party_type": "Supplier",
            "party": "_Test Supplier",
            "reference_type": payment_jv.doctype,
            "reference_name": payment_jv.name
        })
        self.assertRaises(frappe.ValidationError, payment_jv2.insert)

        # Partial return of advance payment
        return_jv1 = make_journal_entry("_Test Bank - _TC",
                                        "_Test Payable - _TC",
                                        150,
                                        save=False)
        return_jv1.get("accounts")[1].update({
            "party_type": "Supplier",
            "party": "_Test Supplier",
            "reference_type": payment_jv.doctype,
            "reference_name": payment_jv.name
        })
        return_jv1.insert()
        return_jv1.submit()
        return_balance = get_balance_on_voucher(return_jv1.doctype,
                                                return_jv1.name, "Supplier",
                                                "_Test Supplier",
                                                "_Test Payable - _TC")
        self.assertEqual(return_balance, 0)

        payment_balance = get_balance_on_voucher(payment_jv.doctype,
                                                 payment_jv.name, "Supplier",
                                                 "_Test Supplier",
                                                 "_Test Payable - _TC")
        self.assertEqual(payment_balance, -350)

        # Attempt to return more than advance payment balance
        return_jv2 = make_journal_entry("_Test Bank - _TC",
                                        "_Test Payable - _TC",
                                        1000,
                                        save=False)
        return_jv2.get("accounts")[1].update({
            "party_type": "Supplier",
            "party": "_Test Supplier",
            "reference_type": payment_jv.doctype,
            "reference_name": payment_jv.name
        })
        self.assertRaises(frappe.ValidationError, return_jv2.insert)

        # Return for the remaining balance of advance payment
        return_jv3 = make_journal_entry("_Test Bank - _TC",
                                        "_Test Payable - _TC",
                                        350,
                                        save=False)
        return_jv3.get("accounts")[1].update({
            "party_type": "Supplier",
            "party": "_Test Supplier",
            "reference_type": payment_jv.doctype,
            "reference_name": payment_jv.name
        })
        return_jv3.insert()
        return_jv3.submit()
        payment_balance = get_balance_on_voucher(payment_jv.doctype,
                                                 payment_jv.name, "Supplier",
                                                 "_Test Supplier",
                                                 "_Test Payable - _TC")
        self.assertEqual(payment_balance, 0)

        # Cancel a payment
        return_jv1.cancel()
        payment_balance = get_balance_on_voucher(payment_jv.doctype,
                                                 payment_jv.name, "Supplier",
                                                 "_Test Supplier",
                                                 "_Test Payable - _TC")
        self.assertEqual(payment_balance, -150)
Esempio n. 8
0
    def test_jv_receivable_voucher_balance(self):
        # Receivable entry
        receivable_jv = make_journal_entry("_Test Receivable - _TC",
                                           "Sales - _TC",
                                           500,
                                           save=False)
        receivable_jv.get("accounts")[0].update({
            "party_type": "Customer",
            "party": "_Test Customer"
        })
        receivable_jv.insert()
        receivable_jv.submit()
        receivable_balance = get_balance_on_voucher(receivable_jv.doctype,
                                                    receivable_jv.name,
                                                    "Customer",
                                                    "_Test Customer",
                                                    "_Test Receivable - _TC")
        self.assertEqual(receivable_balance, 500)

        # Attempt to allocate a receivable entry against another receivable entry
        receivable_jv2 = make_journal_entry("_Test Receivable - _TC",
                                            "Sales - _TC",
                                            100,
                                            save=False)
        receivable_jv2.get("accounts")[0].update({
            "party_type":
            "Customer",
            "party":
            "_Test Customer",
            "reference_type":
            receivable_jv.doctype,
            "reference_name":
            receivable_jv.name
        })
        self.assertRaises(frappe.ValidationError, receivable_jv2.insert)

        # Partial payment against receivable entry
        payment_jv1 = make_journal_entry("_Test Bank - _TC",
                                         "_Test Receivable - _TC",
                                         150,
                                         save=False)
        payment_jv1.get("accounts")[1].update({
            "party_type":
            "Customer",
            "party":
            "_Test Customer",
            "reference_type":
            receivable_jv.doctype,
            "reference_name":
            receivable_jv.name
        })
        payment_jv1.insert()
        payment_jv1.submit()
        payment_balance = get_balance_on_voucher(payment_jv1.doctype,
                                                 payment_jv1.name, "Customer",
                                                 "_Test Customer",
                                                 "_Test Receivable - _TC")
        self.assertEqual(payment_balance, 0)

        receivable_balance = get_balance_on_voucher(receivable_jv.doctype,
                                                    receivable_jv.name,
                                                    "Customer",
                                                    "_Test Customer",
                                                    "_Test Receivable - _TC")
        self.assertEqual(receivable_balance, 350)

        # Attempt to over allocate payment against receivable entry
        payment_jv2 = make_journal_entry("_Test Bank - _TC",
                                         "_Test Receivable - _TC",
                                         1000,
                                         save=False)
        payment_jv2.get("accounts")[1].update({
            "party_type":
            "Customer",
            "party":
            "_Test Customer",
            "reference_type":
            receivable_jv.doctype,
            "reference_name":
            receivable_jv.name
        })
        self.assertRaises(frappe.ValidationError, payment_jv2.insert)

        # Payment for the remaining balance of receivable entry
        payment_jv3 = make_journal_entry("_Test Bank - _TC",
                                         "_Test Receivable - _TC",
                                         350,
                                         save=False)
        payment_jv3.get("accounts")[1].update({
            "party_type":
            "Customer",
            "party":
            "_Test Customer",
            "reference_type":
            receivable_jv.doctype,
            "reference_name":
            receivable_jv.name
        })
        payment_jv3.insert()
        payment_jv3.submit()
        receivable_balance = get_balance_on_voucher(receivable_jv.doctype,
                                                    receivable_jv.name,
                                                    "Customer",
                                                    "_Test Customer",
                                                    "_Test Receivable - _TC")
        self.assertEqual(receivable_balance, 0)

        # Cancel a payment
        payment_jv1.cancel()
        receivable_balance = get_balance_on_voucher(receivable_jv.doctype,
                                                    receivable_jv.name,
                                                    "Customer",
                                                    "_Test Customer",
                                                    "_Test Receivable - _TC")
        self.assertEqual(receivable_balance, 150)
    def test_reconcile_advance_journal_entries(self):
        self.assertFalse(
            get_advance_journal_entries(self.customer.doctype,
                                        self.customer.name,
                                        "_Test Receivable - _TC",
                                        "Sales Order",
                                        against_all_orders=True))

        # Test records
        jv_simple = make_payment_jv(self.customer, 100)
        jv_multiple_rows = make_payment_jv(self.customer,
                                           300,
                                           unallocated_rows=3)

        jv_half_returned = make_payment_jv(self.customer, 200)
        _jv_return = make_payment_jv(self.customer, 0,
                                     jv_half_returned.doctype,
                                     jv_half_returned.name, -100)

        _jv_receivable = make_payment_jv(self.customer, -100)
        jv_half_allocated = make_payment_jv(self.customer, 100,
                                            _jv_receivable.doctype,
                                            _jv_receivable.name, 100)

        so = make_sales_order(self.customer)
        jv_against_so = make_payment_jv(self.customer, 100, so.doctype,
                                        so.name, 100)

        # Test get_advance_journal_entries
        advances = get_advance_journal_entries(self.customer.doctype,
                                               self.customer.name,
                                               "_Test Receivable - _TC",
                                               "Sales Order",
                                               against_all_orders=True)
        advance_vouchers = {}
        for d in advances:
            advance_vouchers.setdefault(d.reference_name, [])
            advance_vouchers[d.reference_name].append(d)

        self.assertEqual(len(advance_vouchers[jv_simple.name]), 1)
        self.assertEqual(advance_vouchers[jv_simple.name][0].amount, 100)

        self.assertEqual(len(advance_vouchers[jv_multiple_rows.name]), 1)
        self.assertEqual(advance_vouchers[jv_multiple_rows.name][0].amount,
                         300)

        self.assertEqual(len(advance_vouchers[jv_half_returned.name]), 1)
        self.assertEqual(advance_vouchers[jv_half_returned.name][0].amount,
                         100)

        self.assertEqual(len(advance_vouchers[jv_half_allocated.name]), 1)
        self.assertEqual(advance_vouchers[jv_half_allocated.name][0].amount,
                         100)

        self.assertEqual(len(advance_vouchers[jv_against_so.name]), 2)
        self.assertEqual(advance_vouchers[jv_against_so.name][0].amount, 100)
        self.assertEqual(advance_vouchers[jv_against_so.name][0].reference_row,
                         jv_against_so.accounts[2].name)
        self.assertEqual(advance_vouchers[jv_against_so.name][1].amount, 100)

        # Test reconcile_against_document
        jv_receivable = make_payment_jv(self.customer, -5000)

        # Full allocation
        lst = [
            frappe._dict({
                'voucher_type': jv_simple.doctype,
                'voucher_no': jv_simple.name,
                'voucher_detail_no': None,
                'against_voucher_type': jv_receivable.doctype,
                'against_voucher': jv_receivable.name,
                'account': "_Test Receivable - _TC",
                'party_type': "Customer",
                'party': self.customer.name,
                'dr_or_cr': "credit_in_account_currency",
                'unadjusted_amount': 100,
                'allocated_amount': 100
            })
        ]
        reconcile_against_document(lst)
        self.assertEqual(
            get_balance_on_voucher(jv_receivable.doctype, jv_receivable.name,
                                   "Customer", self.customer.name,
                                   "_Test Receivable - _TC"), 4900)
        self.assertTrue(
            frappe.db.sql(
                """select name from `tabJournal Entry Account`
			where name=%s and reference_name=%s and credit_in_account_currency=%s and docstatus=1
		""", [jv_simple.accounts[1].name, jv_receivable.name, 100]))

        # Multiple row partial allocation
        lst = [
            frappe._dict({
                'voucher_type': jv_multiple_rows.doctype,
                'voucher_no': jv_multiple_rows.name,
                'voucher_detail_no': None,
                'against_voucher_type': jv_receivable.doctype,
                'against_voucher': jv_receivable.name,
                'account': "_Test Receivable - _TC",
                'party_type': "Customer",
                'party': self.customer.name,
                'dr_or_cr': "credit_in_account_currency",
                'unadjusted_amount': 300,
                'allocated_amount': 230
            })
        ]
        reconcile_against_document(lst)
        self.assertEqual(
            get_balance_on_voucher(jv_receivable.doctype, jv_receivable.name,
                                   "Customer", self.customer.name,
                                   "_Test Receivable - _TC"), 4670)
        self.assertTrue(
            frappe.db.sql(
                """select count(*) from `tabJournal Entry Account`
			where parent=%s and reference_name=%s and party_type='Customer' and party=%s and account='_Test Receivable - _TC'
			and credit_in_account_currency=%s and docstatus=1
			having count(*) = 2
		""", [jv_multiple_rows.name, jv_receivable.name, self.customer.name, 100]))
        self.assertTrue(
            frappe.db.sql(
                """select name from `tabJournal Entry Account`
			where parent=%s and reference_name=%s and party_type='Customer' and party=%s and account='_Test Receivable - _TC'
			and credit_in_account_currency=%s and docstatus=1
		""", [jv_multiple_rows.name, jv_receivable.name, self.customer.name, 30]))
        self.assertTrue(
            frappe.db.sql(
                """select name from `tabJournal Entry Account`
			where parent=%s and party_type='Customer' and party=%s and ifnull(reference_name, '') = ''
			and account='_Test Receivable - _TC' and credit_in_account_currency=%s and docstatus=1
		""", [jv_multiple_rows.name, self.customer.name, 70]))

        # Attempt to over allocate a partially returned/knocked-off jv
        lst = [
            frappe._dict({
                'voucher_type': jv_half_returned.doctype,
                'voucher_no': jv_half_returned.name,
                'voucher_detail_no': None,
                'against_voucher_type': jv_receivable.doctype,
                'against_voucher': jv_receivable.name,
                'account': "_Test Receivable - _TC",
                'party_type': "Customer",
                'party': self.customer.name,
                'dr_or_cr': "credit_in_account_currency",
                'unadjusted_amount': 200,
                'allocated_amount': 200
            })
        ]
        self.assertRaises(frappe.ValidationError, reconcile_against_document,
                          lst)

        # Attempt to over allocate a partially allocated jv
        lst = [
            frappe._dict({
                'voucher_type': jv_half_allocated.doctype,
                'voucher_no': jv_half_allocated.name,
                'voucher_detail_no': None,
                'against_voucher_type': jv_receivable.doctype,
                'against_voucher': jv_receivable.name,
                'account': "_Test Receivable - _TC",
                'party_type': "Customer",
                'party': self.customer.name,
                'dr_or_cr': "credit_in_account_currency",
                'unadjusted_amount': 200,
                'allocated_amount': 200
            })
        ]
        self.assertRaises(frappe.ValidationError, reconcile_against_document,
                          lst)

        # Sales Order advance reallocation
        lst = [
            frappe._dict({
                'voucher_type': jv_against_so.doctype,
                'voucher_no': jv_against_so.name,
                'voucher_detail_no': jv_against_so.accounts[2].name,
                'against_voucher_type': jv_receivable.doctype,
                'against_voucher': jv_receivable.name,
                'account': "_Test Receivable - _TC",
                'party_type': "Customer",
                'party': self.customer.name,
                'dr_or_cr': "credit_in_account_currency",
                'unadjusted_amount': 100,
                'allocated_amount': 100
            })
        ]
        reconcile_against_document(lst)
        self.assertEqual(
            get_balance_on_voucher(jv_receivable.doctype, jv_receivable.name,
                                   "Customer", self.customer.name,
                                   "_Test Receivable - _TC"), 4570)
        self.assertEqual(
            get_balance_on_voucher(so.doctype, so.name, "Customer",
                                   self.customer.name,
                                   "_Test Receivable - _TC"), 0)
        self.assertEqual(
            frappe.db.get_value("Sales Order", so.name, "advance_paid"), 0)
        self.assertTrue(
            frappe.db.sql(
                """select name from `tabJournal Entry Account`
			where name=%s and reference_name=%s and credit_in_account_currency=%s and docstatus=1
		""", [jv_against_so.accounts[2].name, jv_receivable.name, 100]))

        # Test get_advance_payment_entries after reconciliation
        advances = get_advance_journal_entries(self.customer.doctype,
                                               self.customer.name,
                                               "_Test Receivable - _TC",
                                               "Sales Order",
                                               against_all_orders=True)
        advance_vouchers = {}
        for d in advances:
            advance_vouchers.setdefault(d.reference_name, [])
            advance_vouchers[d.reference_name].append(d)

        self.assertFalse(advance_vouchers.get(jv_simple.name))

        self.assertEqual(len(advance_vouchers[jv_multiple_rows.name]), 1)
        self.assertEqual(advance_vouchers[jv_multiple_rows.name][0].amount, 70)

        self.assertEqual(len(advance_vouchers[jv_against_so.name]), 1)
        self.assertEqual(advance_vouchers[jv_against_so.name][0].amount, 100)
    def test_reconcile_advance_payment_entries(self):
        self.assertFalse(
            get_advance_payment_entries(self.customer.doctype,
                                        self.customer.name,
                                        "_Test Receivable - _TC",
                                        "Sales Order",
                                        against_all_orders=True))

        # Test records
        _jv_receivable = make_payment_jv(self.customer, -100)

        so = make_sales_order(self.customer)
        pe_against_so = make_payment_entry(self.customer, 100, so.doctype,
                                           so.name, 100)
        pe_unallocated = make_payment_entry(self.customer, 100)
        pe_half_allocated = make_payment_entry(self.customer, 100,
                                               _jv_receivable.doctype,
                                               _jv_receivable.name, 100)

        # Test get_advance_payment_entries
        advances = get_advance_payment_entries(self.customer.doctype,
                                               self.customer.name,
                                               "_Test Receivable - _TC",
                                               "Sales Order",
                                               against_all_orders=True)
        advance_vouchers = {}
        for d in advances:
            advance_vouchers.setdefault(d.reference_name, [])
            advance_vouchers[d.reference_name].append(d)

        self.assertEqual(len(advance_vouchers[pe_against_so.name]), 2)
        self.assertEqual(advance_vouchers[pe_against_so.name][0].reference_row,
                         pe_against_so.references[0].name)
        self.assertEqual(advance_vouchers[pe_against_so.name][0].amount, 100)
        self.assertEqual(advance_vouchers[pe_against_so.name][1].amount, 100)

        self.assertEqual(len(advance_vouchers[pe_unallocated.name]), 1)
        self.assertEqual(advance_vouchers[pe_unallocated.name][0].amount, 100)

        self.assertEqual(len(advance_vouchers[pe_half_allocated.name]), 1)
        self.assertEqual(advance_vouchers[pe_half_allocated.name][0].amount,
                         100)

        # Test reconcile_against_document
        jv_receivable = make_payment_jv(self.customer, -5000)

        # Full allocation
        lst = [
            frappe._dict({
                'voucher_type': pe_unallocated.doctype,
                'voucher_no': pe_unallocated.name,
                'voucher_detail_no': None,
                'against_voucher_type': jv_receivable.doctype,
                'against_voucher': jv_receivable.name,
                'account': "_Test Receivable - _TC",
                'party_type': "Customer",
                'party': self.customer.name,
                'dr_or_cr': "credit_in_account_currency",
                'unadjusted_amount': 100,
                'allocated_amount': 100
            })
        ]
        reconcile_against_document(lst)
        self.assertEqual(
            get_balance_on_voucher(jv_receivable.doctype, jv_receivable.name,
                                   "Customer", self.customer.name,
                                   "_Test Receivable - _TC"), 4900)
        self.assertTrue(
            frappe.db.sql(
                """select name from `tabPayment Entry Reference`
			where parent=%s and reference_name=%s and allocated_amount=%s and docstatus=1
		""", [pe_unallocated.name, jv_receivable.name, 100]))
        self.assertEqual(
            frappe.get_value("Payment Entry", pe_unallocated.name,
                             "unallocated_amount"), 0)

        # Attempt to over allocate a partially allocated pe
        lst = [
            frappe._dict({
                'voucher_type': pe_half_allocated.doctype,
                'voucher_no': pe_half_allocated.name,
                'voucher_detail_no': None,
                'against_voucher_type': jv_receivable.doctype,
                'against_voucher': jv_receivable.name,
                'account': "_Test Receivable - _TC",
                'party_type': "Customer",
                'party': self.customer.name,
                'dr_or_cr': "credit_in_account_currency",
                'unadjusted_amount': 200,
                'allocated_amount': 200
            })
        ]
        self.assertRaises(frappe.ValidationError, reconcile_against_document,
                          lst)

        # Sales Order advance reallocation
        lst = [
            frappe._dict({
                'voucher_type': pe_against_so.doctype,
                'voucher_no': pe_against_so.name,
                'voucher_detail_no': pe_against_so.references[0].name,
                'against_voucher_type': jv_receivable.doctype,
                'against_voucher': jv_receivable.name,
                'account': "_Test Receivable - _TC",
                'party_type': "Customer",
                'party': self.customer.name,
                'dr_or_cr': "credit_in_account_currency",
                'unadjusted_amount': 100,
                'allocated_amount': 100
            })
        ]
        reconcile_against_document(lst)
        self.assertEqual(
            get_balance_on_voucher(jv_receivable.doctype, jv_receivable.name,
                                   "Customer", self.customer.name,
                                   "_Test Receivable - _TC"), 4800)
        self.assertEqual(
            get_balance_on_voucher(so.doctype, so.name, "Customer",
                                   self.customer.name,
                                   "_Test Receivable - _TC"), 0)
        self.assertEqual(
            frappe.db.get_value("Sales Order", so.name, "advance_paid"), 0)
        self.assertTrue(
            frappe.db.sql(
                """select name from `tabPayment Entry Reference`
			where parent=%s and reference_name=%s and allocated_amount=%s and docstatus=1
		""", [pe_unallocated.name, jv_receivable.name, 100]))
        self.assertEqual(
            frappe.get_value("Payment Entry", pe_against_so.name,
                             "unallocated_amount"), 100)

        # Test get_advance_payment_entries after reconciliation
        advances = get_advance_payment_entries(self.customer.doctype,
                                               self.customer.name,
                                               "_Test Receivable - _TC",
                                               "Sales Order",
                                               against_all_orders=True)
        advance_vouchers = {}
        for d in advances:
            advance_vouchers.setdefault(d.reference_name, [])
            advance_vouchers[d.reference_name].append(d)

        self.assertFalse(advance_vouchers.get(pe_unallocated.name))
        self.assertEqual(len(advance_vouchers[pe_against_so.name]), 1)
        self.assertEqual(advance_vouchers[pe_against_so.name][0].amount, 100)
Esempio n. 11
0
def get_outstanding(args):
	if not frappe.has_permission("Account"):
		frappe.msgprint(_("No Permission"), raise_exception=1)

	if isinstance(args, string_types):
		args = json.loads(args)

	company_currency = erpnext.get_company_currency(args.get("company"))

	if args.get("doctype") == "Journal Entry":
		against_jv_amount = get_balance_on_voucher("Journal Entry", args.get("docname"), args.get("party_type"),
			args.get("party"), args.get("account"), dr_or_cr="debit_in_account_currency - credit_in_account_currency")

		amount_field = "credit_in_account_currency" if against_jv_amount >= 0 else "debit_in_account_currency"
		return {
			amount_field: abs(against_jv_amount)
		}

	elif args.get("doctype") in ("Sales Invoice", "Purchase Invoice", "Landed Cost Voucher"):
		fields = ["outstanding_amount", "conversion_rate"]
		if args.get("doctype") == "Landed Cost Voucher":
			party_type = "Supplier"
			party_field = 'party'
			fields.append('party_type')
		else:
			party_type = "Customer" if args.get("doctype") == "Sales Invoice" else "Supplier"
			party_field = scrub(party_type)

		account_field = "debit_to" if args.get("doctype") == "Sales Invoice" else "credit_to"
		fields.append(account_field)
		fields.append(party_field)
		if args.get("doctype") == "Purchase Invoice":
			fields.append('letter_of_credit')

		invoice = frappe.db.get_value(args["doctype"], args["docname"], fields, as_dict=1)
		if invoice.get("party_type"):
			party_type = invoice.get("party_type")
		if invoice.get("letter_of_credit"):
			party_type = "Letter of Credit"

		exchange_rate = invoice.conversion_rate if (args.get("account_currency") != company_currency) else 1

		if args["doctype"] == "Sales Invoice":
			amount_field = "credit_in_account_currency" \
				if flt(invoice.outstanding_amount) > 0 else "debit_in_account_currency"
		else:
			amount_field = "debit_in_account_currency" \
				if flt(invoice.outstanding_amount) > 0 else "credit_in_account_currency"

		return {
			amount_field: abs(flt(invoice.outstanding_amount)),
			"exchange_rate": exchange_rate,
			"party_type": party_type,
			"party": invoice.get(party_field),
			"account": invoice.get(account_field)
		}

	elif args.get("doctype") in ("Employee Advance", "Expense Claim"):
		account_field = 'advance_account' if args.get("doctype") == "Employee Advance" else "payable_account"
		balance_field = 'balance_amount' if args.get("doctype") == "Employee Advance" else "outstanding_amount"
		details = frappe.db.get_value(args["doctype"], args["docname"], ['employee', account_field, balance_field], as_dict=1)

		balance_amount = details.get(balance_field) if args.get("doctype") == "Expense Claim" \
			else -1 * flt(details.get(balance_field))
		amount_field = "debit_in_account_currency" \
			if flt(balance_amount) > 0 else "credit_in_account_currency"

		return {
			amount_field: abs(balance_amount),
			"party_type": "Employee",
			"party": details.get("employee"),
			"account": details.get(account_field),
		}
def get_reference_details(reference_doctype, reference_name, party_account_currency, party_type, party, account):
	total_amount = outstanding_amount = bill_no = None
	exchange_rate = 1

	ref_doc = frappe.get_doc(reference_doctype, reference_name)
	company_currency = ref_doc.get("company_currency") or erpnext.get_company_currency(ref_doc.company)

	if reference_doctype == "Fees":
		total_amount = ref_doc.get("grand_total")
		exchange_rate = 1
		outstanding_amount = ref_doc.get("outstanding_amount")
	elif reference_doctype == "Landed Cost Voucher":
		total_amount = ref_doc.get("total_taxes_and_charges")
		exchange_rate = ref_doc.get("conversion_rate")
		outstanding_amount = ref_doc.get("outstanding_amount")
	elif reference_doctype == "Journal Entry" and ref_doc.docstatus == 1:
		total_amount = ref_doc.get("total_amount")
		if ref_doc.multi_currency:
			exchange_rate = get_average_party_exchange_rate_on_journal_entry(reference_name, party_type, party, account)
		else:
			exchange_rate = 1
		outstanding_amount = get_balance_on_voucher("Journal Entry", reference_name, party_type, party, account)
	elif reference_doctype != "Journal Entry":
		if party_account_currency == company_currency:
			if ref_doc.doctype == "Expense Claim":
				total_amount = ref_doc.total_sanctioned_amount
			elif ref_doc.doctype == "Employee Advance":
				total_amount = ref_doc.advance_amount
			else:
				total_amount = ref_doc.base_grand_total
			exchange_rate = 1
		else:
			total_amount = ref_doc.grand_total

			# Get the exchange rate from the original ref doc
			# or get it based on the posting date of the ref doc
			exchange_rate = ref_doc.get("conversion_rate") or \
				get_exchange_rate(party_account_currency, company_currency, ref_doc.posting_date)

		if reference_doctype in ("Sales Invoice", "Purchase Invoice"):
			outstanding_amount = ref_doc.get("outstanding_amount")
			bill_no = ref_doc.get("bill_no")
		elif reference_doctype == "Expense Claim":
			outstanding_amount = flt(ref_doc.get("total_sanctioned_amount")) \
				- flt(ref_doc.get("total_amount+reimbursed")) - flt(ref_doc.get("total_advance_amount"))
		elif reference_doctype == "Employee Advance":
			outstanding_amount = ref_doc.advance_amount - flt(ref_doc.paid_amount)
		else:
			outstanding_amount = flt(total_amount) - flt(ref_doc.advance_paid)
	else:
		# Get the exchange rate based on the posting date of the ref doc
		exchange_rate = get_exchange_rate(party_account_currency,
			company_currency, ref_doc.posting_date)

	return frappe._dict({
		"due_date": ref_doc.get("due_date"),
		"total_amount": total_amount,
		"outstanding_amount": outstanding_amount,
		"exchange_rate": exchange_rate,
		"bill_no": bill_no
	})