Update manuals. Fix codacy issues
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index 59a899b..7bb9a52 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -18,21 +18,21 @@
class InvalidPaymentEntry(ValidationError): pass
class PaymentEntry(AccountsController):
- def setup_party_account_field(self):
+ def setup_party_account_field(self):
self.party_account_field = None
self.party_account = None
self.party_account_currency = None
-
+
if self.payment_type == "Receive":
self.party_account_field = "paid_from"
self.party_account = self.paid_from
self.party_account_currency = self.paid_from_account_currency
-
+
elif self.payment_type == "Pay":
self.party_account_field = "paid_to"
self.party_account = self.paid_to
self.party_account_currency = self.paid_to_account_currency
-
+
def validate(self):
self.setup_party_account_field()
self.set_missing_values()
@@ -50,7 +50,7 @@
self.set_remarks()
self.validate_duplicate_entry()
self.validate_allocated_amount()
-
+
def on_submit(self):
self.setup_party_account_field()
if self.difference_amount:
@@ -58,7 +58,7 @@
self.make_gl_entries()
self.update_advance_paid()
self.update_expense_claim()
-
+
def on_cancel(self):
self.setup_party_account_field()
self.make_gl_entries(cancel=1)
@@ -72,8 +72,8 @@
if (d.reference_doctype, d.reference_name) in reference_names:
frappe.throw(_("Row #{0}: Duplicate entry in References {1} {2}").format(d.idx, d.reference_doctype, d.reference_name))
reference_names.append((d.reference_doctype, d.reference_name))
-
-
+
+
def validate_allocated_amount(self):
for d in self.get("references"):
if (flt(d.allocated_amount))> 0:
@@ -89,98 +89,98 @@
def set_missing_values(self):
if self.payment_type == "Internal Transfer":
- for field in ("party", "party_balance", "total_allocated_amount",
+ for field in ("party", "party_balance", "total_allocated_amount",
"base_total_allocated_amount", "unallocated_amount"):
self.set(field, None)
self.references = []
else:
if not self.party_type:
frappe.throw(_("Party Type is mandatory"))
-
+
if not self.party:
frappe.throw(_("Party is mandatory"))
-
- self.party_name = frappe.db.get_value(self.party_type, self.party,
+
+ self.party_name = frappe.db.get_value(self.party_type, self.party,
self.party_type.lower() + "_name")
-
+
if self.party:
if not self.party_balance:
self.party_balance = get_balance_on(party_type=self.party_type,
party=self.party, date=self.posting_date, company=self.company)
-
+
if not self.party_account:
party_account = get_party_account(self.party_type, self.party, self.company)
self.set(self.party_account_field, party_account)
self.party_account = party_account
-
+
if self.paid_from and not (self.paid_from_account_currency or self.paid_from_account_balance):
acc = get_account_details(self.paid_from, self.posting_date)
self.paid_from_account_currency = acc.account_currency
self.paid_from_account_balance = acc.account_balance
-
+
if self.paid_to and not (self.paid_to_account_currency or self.paid_to_account_balance):
acc = get_account_details(self.paid_to, self.posting_date)
self.paid_to_account_currency = acc.account_currency
self.paid_to_account_balance = acc.account_balance
-
+
self.party_account_currency = self.paid_from_account_currency \
if self.payment_type=="Receive" else self.paid_to_account_currency
-
+
self.set_missing_ref_details()
-
-
+
+
def set_missing_ref_details(self):
for d in self.get("references"):
if d.allocated_amount:
- ref_details = get_reference_details(d.reference_doctype,
+ ref_details = get_reference_details(d.reference_doctype,
d.reference_name, self.party_account_currency)
-
+
for field, value in ref_details.items():
if not d.get(field):
d.set(field, value)
-
+
def validate_payment_type(self):
if self.payment_type not in ("Receive", "Pay", "Internal Transfer"):
frappe.throw(_("Payment Type must be one of Receive, Pay and Internal Transfer"))
-
+
def validate_party_details(self):
if self.party:
if not frappe.db.exists(self.party_type, self.party):
frappe.throw(_("Invalid {0}: {1}").format(self.party_type, self.party))
-
+
if self.party_account:
party_account_type = "Receivable" if self.party_type=="Customer" else "Payable"
self.validate_account_type(self.party_account, [party_account_type])
-
+
def validate_bank_accounts(self):
if self.payment_type in ("Pay", "Internal Transfer"):
self.validate_account_type(self.paid_from, ["Bank", "Cash"])
-
+
if self.payment_type in ("Receive", "Internal Transfer"):
self.validate_account_type(self.paid_to, ["Bank", "Cash"])
-
+
def validate_account_type(self, account, account_types):
account_type = frappe.db.get_value("Account", account, "account_type")
if account_type not in account_types:
frappe.throw(_("Account Type for {0} must be {1}").format(account, comma_or(account_types)))
-
+
def set_exchange_rate(self):
if self.paid_from and not self.source_exchange_rate:
if self.paid_from_account_currency == self.company_currency:
self.source_exchange_rate = 1
else:
- self.source_exchange_rate = get_exchange_rate(self.paid_from_account_currency,
+ self.source_exchange_rate = get_exchange_rate(self.paid_from_account_currency,
self.company_currency, self.posting_date)
-
+
if self.paid_to and not self.target_exchange_rate:
- self.target_exchange_rate = get_exchange_rate(self.paid_to_account_currency,
+ self.target_exchange_rate = get_exchange_rate(self.paid_to_account_currency,
self.company_currency, self.posting_date)
-
+
def validate_mandatory(self):
for field in ("paid_amount", "received_amount", "source_exchange_rate", "target_exchange_rate"):
if not self.get(field):
frappe.throw(_("{0} is mandatory").format(self.meta.get_label(field)))
-
+
def validate_reference_documents(self):
if self.party_type == "Customer":
valid_reference_doctypes = ("Sales Order", "Sales Invoice", "Journal Entry")
@@ -195,7 +195,7 @@
if d.reference_doctype not in valid_reference_doctypes:
frappe.throw(_("Reference Doctype must be one of {0}")
.format(comma_or(valid_reference_doctypes)))
-
+
elif d.reference_name:
if not frappe.db.exists(d.reference_doctype, d.reference_name):
frappe.throw(_("{0} {1} does not exist").format(d.reference_doctype, d.reference_name))
@@ -208,7 +208,7 @@
.format(d.reference_doctype, d.reference_name, self.party_type, self.party))
else:
self.validate_journal_entry()
-
+
if d.reference_doctype in ("Sales Invoice", "Purchase Invoice", "Expense Claim"):
if self.party_type=="Customer":
ref_party_account = ref_doc.debit_to
@@ -216,18 +216,18 @@
ref_party_account = ref_doc.credit_to
elif self.party_type=="Employee":
ref_party_account = ref_doc.payable_account
-
+
if ref_party_account != self.party_account:
frappe.throw(_("{0} {1} is associated with {2}, but Party Account is {3}")
.format(d.reference_doctype, d.reference_name, ref_party_account, self.party_account))
-
+
if ref_doc.docstatus != 1:
frappe.throw(_("{0} {1} must be submitted")
.format(d.reference_doctype, d.reference_name))
-
+
def validate_journal_entry(self):
for d in self.get("references"):
- if d.allocated_amount and d.reference_doctype == "Journal Entry":
+ if d.allocated_amount and d.reference_doctype == "Journal Entry":
je_accounts = frappe.db.sql("""select debit, credit from `tabJournal Entry Account`
where account = %s and party=%s and docstatus = 1 and parent = %s
and (reference_type is null or reference_type in ("", "Sales Order", "Purchase Order"))
@@ -245,7 +245,7 @@
if not valid:
frappe.throw(_("Against Journal Entry {0} does not have any unmatched {1} entry")
.format(d.reference_name, dr_or_cr))
-
+
def set_amounts(self):
self.set_amounts_in_company_currency()
self.set_total_allocated_amount()
@@ -255,111 +255,111 @@
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.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.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":
return
-
+
total_allocated_amount, base_total_allocated_amount = 0, 0
for d in self.get("references"):
- if d.allocated_amount:
+ if d.allocated_amount:
total_allocated_amount += flt(d.allocated_amount)
- base_total_allocated_amount += flt(flt(d.allocated_amount) * flt(d.exchange_rate),
+ base_total_allocated_amount += flt(flt(d.allocated_amount) * flt(d.exchange_rate),
self.precision("base_paid_amount"))
-
+
self.total_allocated_amount = abs(total_allocated_amount)
self.base_total_allocated_amount = abs(base_total_allocated_amount)
-
+
def set_unallocated_amount(self):
self.unallocated_amount = 0;
if self.party:
party_amount = self.paid_amount if self.payment_type=="Receive" else self.received_amount
-
+
total_deductions = sum([flt(d.amount) for d in self.get("deductions")])
-
+
if self.total_allocated_amount < party_amount:
if self.payment_type == "Receive":
self.unallocated_amount = party_amount - (self.total_allocated_amount - total_deductions)
else:
self.unallocated_amount = party_amount - (self.total_allocated_amount + total_deductions)
-
+
def set_difference_amount(self):
- base_unallocated_amount = flt(self.unallocated_amount) * (flt(self.source_exchange_rate)
+ base_unallocated_amount = flt(self.unallocated_amount) * (flt(self.source_exchange_rate)
if self.payment_type=="Receive" else flt(self.target_exchange_rate))
-
+
base_party_amount = flt(self.base_total_allocated_amount) + flt(base_unallocated_amount)
-
+
if self.payment_type == "Receive":
self.difference_amount = base_party_amount - self.base_received_amount
elif self.payment_type == "Pay":
self.difference_amount = self.base_paid_amount - base_party_amount
else:
self.difference_amount = self.base_paid_amount - flt(self.base_received_amount)
-
+
for d in self.get("deductions"):
if d.amount:
self.difference_amount -= flt(d.amount)
-
+
self.difference_amount = flt(self.difference_amount, self.precision("difference_amount"))
-
+
def clear_unallocated_reference_document_rows(self):
self.set("references", self.get("references", {"allocated_amount": ["not in", [0, None, ""]]}))
- frappe.db.sql("""delete from `tabPayment Entry Reference`
+ frappe.db.sql("""delete from `tabPayment Entry Reference`
where parent = %s and allocated_amount = 0""", self.name)
-
+
def validate_payment_against_negative_invoice(self):
- if ((self.payment_type=="Pay" and self.party_type=="Customer")
+ if ((self.payment_type=="Pay" and self.party_type=="Customer")
or (self.payment_type=="Receive" and self.party_type=="Supplier")):
-
- total_negative_outstanding = sum([abs(flt(d.outstanding_amount))
+
+ total_negative_outstanding = sum([abs(flt(d.outstanding_amount))
for d in self.get("references") if flt(d.outstanding_amount) < 0])
-
+
party_amount = self.paid_amount if self.payment_type=="Receive" else self.received_amount
if not total_negative_outstanding:
frappe.throw(_("Cannot {0} {1} {2} without any negative outstanding invoice")
- .format(self.payment_type, ("to" if self.party_type=="Customer" else "from"),
+ .format(self.payment_type, ("to" if self.party_type=="Customer" else "from"),
self.party_type), InvalidPaymentEntry)
-
+
elif party_amount > total_negative_outstanding:
frappe.throw(_("Paid Amount cannot be greater than total negative outstanding amount {0}")
.format(total_negative_outstanding), InvalidPaymentEntry)
-
+
def set_title(self):
if self.payment_type in ("Receive", "Pay"):
self.title = self.party
else:
self.title = self.paid_from + " - " + self.paid_to
-
+
def validate_transaction_reference(self):
bank_account = self.paid_to if self.payment_type == "Receive" else self.paid_from
bank_account_type = frappe.db.get_value("Account", bank_account, "account_type")
-
+
if bank_account_type == "Bank":
if not self.reference_no or not self.reference_date:
frappe.throw(_("Reference No and Reference Date is mandatory for Bank transaction"))
-
+
def set_remarks(self):
if self.remarks: return
-
+
if self.payment_type=="Internal Transfer":
remarks = [_("Amount {0} {1} transferred from {2} to {3}")
.format(self.paid_from_account_currency, self.paid_amount, self.paid_from, self.paid_to)]
else:
-
+
remarks = [_("Amount {0} {1} {2} {3}").format(
self.party_account_currency,
self.paid_amount if self.payment_type=="Receive" else self.received_amount,
_("received from") if self.payment_type=="Receive" else _("to"), self.party
)]
-
+
if self.reference_no:
remarks.append(_("Transaction reference no {0} dated {1}")
.format(self.reference_no, self.reference_date))
@@ -367,35 +367,35 @@
if self.payment_type in ["Receive", "Pay"]:
for d in self.get("references"):
if d.allocated_amount:
- remarks.append(_("Amount {0} {1} against {2} {3}").format(self.party_account_currency,
+ remarks.append(_("Amount {0} {1} against {2} {3}").format(self.party_account_currency,
d.allocated_amount, d.reference_doctype, d.reference_name))
-
+
for d in self.get("deductions"):
if d.amount:
remarks.append(_("Amount {0} {1} deducted against {2}")
.format(self.company_currency, d.amount, d.account))
self.set("remarks", "\n".join(remarks))
-
+
def make_gl_entries(self, cancel=0, adv_adj=0):
if self.payment_type in ("Receive", "Pay") and not self.get("party_account_field"):
self.setup_party_account_field()
-
+
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=cancel, adv_adj=adv_adj)
-
+
def add_party_gl_entries(self, gl_entries):
if self.party_account:
if self.payment_type=="Receive":
against_account = self.paid_to
else:
against_account = self.paid_from
-
-
+
+
party_gl_dict = self.get_gl_dict({
"account": self.party_account,
"party_type": self.party_type,
@@ -403,39 +403,39 @@
"against": against_account,
"account_currency": self.party_account_currency
})
-
+
dr_or_cr = "credit" if self.party_type == "Customer" else "debit"
-
+
for d in self.get("references"):
gle = party_gl_dict.copy()
gle.update({
"against_voucher_type": d.reference_doctype,
"against_voucher": d.reference_name
})
-
- allocated_amount_in_company_currency = flt(flt(d.allocated_amount) * flt(d.exchange_rate),
- self.precision("paid_amount"))
-
+
+ allocated_amount_in_company_currency = flt(flt(d.allocated_amount) * flt(d.exchange_rate),
+ self.precision("paid_amount"))
+
gle.update({
dr_or_cr + "_in_account_currency": d.allocated_amount,
dr_or_cr: allocated_amount_in_company_currency
})
-
+
gl_entries.append(gle)
-
+
if self.unallocated_amount:
base_unallocated_amount = base_unallocated_amount = self.unallocated_amount * \
(self.source_exchange_rate if self.payment_type=="Receive" else self.target_exchange_rate)
-
+
gle = party_gl_dict.copy()
-
+
gle.update({
dr_or_cr + "_in_account_currency": self.unallocated_amount,
dr_or_cr: base_unallocated_amount
})
gl_entries.append(gle)
-
+
def add_bank_gl_entries(self, gl_entries):
if self.payment_type in ("Pay", "Internal Transfer"):
gl_entries.append(
@@ -457,14 +457,14 @@
"debit": self.base_received_amount
})
)
-
+
def add_deductions_gl_entries(self, gl_entries):
for d in self.get("deductions"):
if d.amount:
account_currency = get_account_currency(d.account)
if account_currency != self.company_currency:
frappe.throw(_("Currency for {0} must be {1}").format(d.account, self.company_currency))
-
+
gl_entries.append(
self.get_gl_dict({
"account": d.account,
@@ -475,7 +475,7 @@
"cost_center": d.cost_center
})
)
-
+
def update_advance_paid(self):
if self.payment_type in ("Receive", "Pay") and self.party:
for d in self.get("references"):
@@ -495,17 +495,17 @@
party_account_currency = get_account_currency(args.get("party_account"))
company_currency = frappe.db.get_value("Company", args.get("company"), "default_currency")
-
+
# Get negative outstanding sales /purchase invoices
total_field = "base_grand_total" if party_account_currency == company_currency else "grand_total"
-
- negative_outstanding_invoices = get_negative_outstanding_invoices(args.get("party_type"),
+
+ negative_outstanding_invoices = get_negative_outstanding_invoices(args.get("party_type"),
args.get("party"), args.get("party_account"), total_field)
# Get positive outstanding sales /purchase invoices
- outstanding_invoices = get_outstanding_invoices(args.get("party_type"), args.get("party"),
+ 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:
@@ -517,11 +517,11 @@
)
# 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("posting_date"),args.get("party_type"), args.get("party"),
+ orders_to_be_billed = get_orders_to_be_billed(args.get("posting_date"),args.get("party_type"), args.get("party"),
party_account_currency, company_currency)
-
+
return negative_outstanding_invoices + outstanding_invoices + orders_to_be_billed
-
+
def get_orders_to_be_billed(posting_date, party_type, party, party_account_currency, company_currency):
if party_type == "Customer":
voucher_type = 'Sales Order'
@@ -529,7 +529,7 @@
voucher_type = 'Purchase Order'
elif party_type == "Employee":
voucher_type = None
-
+
orders = []
if voucher_type:
ref_field = "base_grand_total" if party_account_currency == company_currency else "grand_total"
@@ -560,19 +560,19 @@
for d in orders:
d["voucher_type"] = voucher_type
# This assumes that the exchange rate required is the one in the SO
- d["exchange_rate"] = get_exchange_rate(party_account_currency,
+ d["exchange_rate"] = get_exchange_rate(party_account_currency,
company_currency, posting_date)
order_list.append(d)
return order_list
-
+
def get_negative_outstanding_invoices(party_type, party, party_account, total_field):
if party_type != "Employee":
voucher_type = "Sales Invoice" if party_type == "Customer" else "Purchase Invoice"
return frappe.db.sql("""
select
- "{voucher_type}" as voucher_type, name as voucher_no,
- {total_field} as invoice_amount, outstanding_amount, posting_date,
+ "{voucher_type}" as voucher_type, name as voucher_no,
+ {total_field} as invoice_amount, outstanding_amount, posting_date,
due_date, conversion_rate as exchange_rate
from
`tab{voucher_type}`
@@ -588,18 +588,18 @@
}), (party, party_account), as_dict = True)
else:
return []
-
+
@frappe.whitelist()
def get_party_details(company, party_type, party, date):
if not frappe.db.exists(party_type, party):
frappe.throw(_("Invalid {0}: {1}").format(party_type, party))
-
+
party_account = get_party_account(party_type, party, company)
-
+
account_currency = get_account_currency(party_account)
account_balance = get_balance_on(party_account, date)
party_balance = get_balance_on(party_type=party_type, party=party)
-
+
return {
"party_account": party_account,
"party_account_currency": account_currency,
@@ -607,7 +607,7 @@
"account_balance": account_balance
}
-@frappe.whitelist()
+@frappe.whitelist()
def get_account_details(account, date):
frappe.has_permission('Payment Entry', throw=True)
return frappe._dict({
@@ -615,61 +615,61 @@
"account_balance": get_balance_on(account, date),
"account_type": frappe.db.get_value("Account", account, "account_type")
})
-
+
@frappe.whitelist()
def get_company_defaults(company):
fields = ["write_off_account", "exchange_gain_loss_account", "cost_center"]
ret = frappe.db.get_value("Company", company, fields, as_dict=1)
-
+
for fieldname in fields:
if not ret[fieldname]:
frappe.throw(_("Please set default {0} in Company {1}")
.format(frappe.get_meta("Company").get_label(fieldname), company))
-
+
return ret
@frappe.whitelist()
def get_reference_details(reference_doctype, reference_name, party_account_currency):
total_amount = outstanding_amount = exchange_rate = None
ref_doc = frappe.get_doc(reference_doctype, reference_name)
-
+
if reference_doctype != "Journal Entry":
if party_account_currency == ref_doc.company_currency:
if ref_doc.doctype == "Expense Claim":
total_amount = ref_doc.total_sanctioned_amount
- else:
+ 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
+
+ # 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, ref_doc.company_currency, ref_doc.posting_date)
-
+
outstanding_amount = ref_doc.get("outstanding_amount") \
if reference_doctype in ("Sales Invoice", "Purchase Invoice", "Expense Claim") \
- else flt(total_amount) - flt(ref_doc.advance_paid)
+ else 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,
+ exchange_rate = get_exchange_rate(party_account_currency,
ref_doc.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
})
-
+
@frappe.whitelist()
def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=None):
doc = frappe.get_doc(dt, dn)
-
+
if dt in ("Sales Order", "Purchase Order") and flt(doc.per_billed, 2) > 0:
frappe.throw(_("Can only make payment against unbilled {0}").format(dt))
-
+
if dt in ("Sales Invoice", "Sales Order"):
party_type = "Customer"
elif dt in ("Purchase Invoice", "Purchase Order"):
@@ -684,16 +684,16 @@
party_account = doc.credit_to
else:
party_account = get_party_account(party_type, doc.get(party_type.lower()), doc.company)
-
+
party_account_currency = doc.get("party_account_currency") or get_account_currency(party_account)
-
+
# payment type
if (dt == "Sales Order" or (dt=="Sales Invoice" and doc.outstanding_amount > 0)) \
or (dt=="Purchase Invoice" and doc.outstanding_amount < 0):
payment_type = "Receive"
else:
payment_type = "Pay"
-
+
# amounts
grand_total = outstanding_amount = 0
if party_amount:
@@ -710,9 +710,9 @@
outstanding_amount = grand_total - flt(doc.advance_paid)
# bank or cash
- bank = get_default_bank_cash_account(doc.company, "Bank", mode_of_payment=doc.get("mode_of_payment"),
+ bank = get_default_bank_cash_account(doc.company, "Bank", mode_of_payment=doc.get("mode_of_payment"),
account=bank_account)
-
+
paid_amount = received_amount = 0
if party_account_currency == bank.account_currency:
paid_amount = received_amount = abs(outstanding_amount)
@@ -724,7 +724,7 @@
received_amount = abs(outstanding_amount)
if bank_amount:
paid_amount = bank_amount
-
+
pe = frappe.new_doc("Payment Entry")
pe.payment_type = payment_type
pe.company = doc.company
@@ -741,7 +741,7 @@
pe.received_amount = received_amount
pe.allocate_payment_amount = 1
pe.letter_head = doc.get("letter_head")
-
+
pe.append("references", {
"reference_doctype": dt,
"reference_name": dn,
diff --git a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
index 9d6b75b..0316cca 100644
--- a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
@@ -21,102 +21,102 @@
pe.paid_from = "Debtors - _TC"
pe.insert()
pe.submit()
-
+
expected_gle = dict((d[0], d) for d in [
["Debtors - _TC", 0, 1000, so.name],
["_Test Cash - _TC", 1000.0, 0, None]
])
-
+
self.validate_gl_entries(pe.name, expected_gle)
-
+
so_advance_paid = frappe.db.get_value("Sales Order", so.name, "advance_paid")
self.assertEqual(so_advance_paid, 1000)
-
+
pe.cancel()
-
+
self.assertFalse(self.get_gle(pe.name))
-
+
so_advance_paid = frappe.db.get_value("Sales Order", so.name, "advance_paid")
self.assertEqual(so_advance_paid, 0)
-
+
def test_payment_entry_against_si_usd_to_usd(self):
si = create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable USD - _TC",
currency="USD", conversion_rate=50)
pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank USD - _TC")
pe.reference_no = "1"
pe.reference_date = "2016-01-01"
- pe.target_exchange_rate = 50
+ pe.target_exchange_rate = 50
pe.insert()
pe.submit()
-
+
expected_gle = dict((d[0], d) for d in [
["_Test Receivable USD - _TC", 0, 5000, si.name],
["_Test Bank USD - _TC", 5000.0, 0, None]
])
-
+
self.validate_gl_entries(pe.name, expected_gle)
-
+
outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"))
self.assertEqual(outstanding_amount, 0)
-
+
pe.cancel()
self.assertFalse(self.get_gle(pe.name))
-
+
outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"))
self.assertEqual(outstanding_amount, 100)
-
+
def test_payment_entry_against_pi(self):
pi = make_purchase_invoice(supplier="_Test Supplier USD", debit_to="_Test Payable USD - _TC",
currency="USD", conversion_rate=50)
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank USD - _TC")
pe.reference_no = "1"
pe.reference_date = "2016-01-01"
- pe.source_exchange_rate = 50
+ pe.source_exchange_rate = 50
pe.insert()
pe.submit()
-
+
expected_gle = dict((d[0], d) for d in [
["_Test Payable USD - _TC", 12500, 0, pi.name],
["_Test Bank USD - _TC", 0, 12500, None]
])
-
+
self.validate_gl_entries(pe.name, expected_gle)
-
+
outstanding_amount = flt(frappe.db.get_value("Sales Invoice", pi.name, "outstanding_amount"))
self.assertEqual(outstanding_amount, 0)
def test_payment_entry_against_ec(self):
-
+
payable = frappe.db.get_value('Company', "_Test Company", 'default_payable_account')
ec = make_expense_claim(payable, 300, 300, "_Test Company","Travel Expenses - _TC")
pe = get_payment_entry("Expense Claim", ec.name, bank_account="_Test Bank USD - _TC", bank_amount=300)
pe.reference_no = "1"
pe.reference_date = "2016-01-01"
- pe.source_exchange_rate = 1
+ pe.source_exchange_rate = 1
pe.insert()
pe.submit()
-
+
expected_gle = dict((d[0], d) for d in [
[payable, 300, 0, ec.name],
["_Test Bank USD - _TC", 0, 300, None]
])
-
+
self.validate_gl_entries(pe.name, expected_gle)
-
+
outstanding_amount = flt(frappe.db.get_value("Expense Claim", ec.name, "total_sanctioned_amount")) - \
flt(frappe.db.get_value("Expense Claim", ec.name, "total_amount_reimbursed"))
self.assertEqual(outstanding_amount, 0)
-
+
def test_payment_entry_against_si_usd_to_inr(self):
si = create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable USD - _TC",
currency="USD", conversion_rate=50)
- pe = get_payment_entry("Sales Invoice", si.name, party_amount=20,
+ pe = get_payment_entry("Sales Invoice", si.name, party_amount=20,
bank_account="_Test Bank - _TC", bank_amount=900)
pe.reference_no = "1"
pe.reference_date = "2016-01-01"
-
+
self.assertEqual(pe.difference_amount, 100)
-
+
pe.append("deductions", {
"account": "_Test Exchange Gain/Loss - _TC",
"cost_center": "_Test Cost Center - _TC",
@@ -124,15 +124,15 @@
})
pe.insert()
pe.submit()
-
+
expected_gle = dict((d[0], d) for d in [
["_Test Receivable USD - _TC", 0, 1000, si.name],
["_Test Bank - _TC", 900, 0, None],
["_Test Exchange Gain/Loss - _TC", 100.0, 0, None],
])
-
+
self.validate_gl_entries(pe.name, expected_gle)
-
+
outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"))
self.assertEqual(outstanding_amount, 80)
@@ -163,7 +163,7 @@
pe.source_exchange_rate, 65.1,
"{0} is not equal to {1}".format(pe.source_exchange_rate, 65.1)
)
-
+
def test_internal_transfer_usd_to_inr(self):
pe = frappe.new_doc("Payment Entry")
pe.payment_type = "Internal Transfer"
@@ -175,31 +175,31 @@
pe.received_amount = 4500
pe.reference_no = "2"
pe.reference_date = nowdate()
-
+
pe.setup_party_account_field()
pe.set_missing_values()
pe.set_exchange_rate()
pe.set_amounts()
-
+
self.assertEquals(pe.difference_amount, 500)
-
+
pe.append("deductions", {
"account": "_Test Exchange Gain/Loss - _TC",
"cost_center": "_Test Cost Center - _TC",
"amount": 500
})
-
+
pe.insert()
pe.submit()
-
+
expected_gle = dict((d[0], d) for d in [
["_Test Bank USD - _TC", 0, 5000, None],
["_Test Bank - _TC", 4500, 0, None],
["_Test Exchange Gain/Loss - _TC", 500.0, 0, None],
])
-
+
self.validate_gl_entries(pe.name, expected_gle)
-
+
def test_payment_against_negative_sales_invoice(self):
pe1 = frappe.new_doc("Payment Entry")
pe1.payment_type = "Pay"
@@ -209,33 +209,33 @@
pe1.paid_from = "_Test Cash - _TC"
pe1.paid_amount = 100
pe1.received_amount = 100
-
+
self.assertRaises(InvalidPaymentEntry, pe1.validate)
-
+
si1 = create_sales_invoice()
-
+
# create full payment entry against si1
pe2 = get_payment_entry("Sales Invoice", si1.name, bank_account="_Test Cash - _TC")
pe2.insert()
pe2.submit()
-
+
# create return entry against si1
create_sales_invoice(is_return=1, return_against=si1.name, qty=-1)
si1_outstanding = frappe.db.get_value("Sales Invoice", si1.name, "outstanding_amount")
self.assertEqual(si1_outstanding, -100)
-
+
# pay more than outstanding against si1
pe3 = get_payment_entry("Sales Invoice", si1.name, bank_account="_Test Cash - _TC")
pe3.paid_amount = pe3.received_amount = 300
self.assertRaises(InvalidPaymentEntry, pe3.validate)
-
+
# pay negative outstanding against si1
pe3.paid_to = "Debtors - _TC"
pe3.paid_amount = pe3.received_amount = 100
-
+
pe3.insert()
pe3.submit()
-
+
expected_gle = dict((d[0], d) for d in [
["Debtors - _TC", 100, 0, si1.name],
["_Test Cash - _TC", 0, 100, None]
@@ -251,10 +251,10 @@
outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si1.name, "outstanding_amount"))
self.assertEqual(outstanding_amount, -100)
-
+
def validate_gl_entries(self, voucher_no, expected_gle):
gl_entries = self.get_gle(voucher_no)
-
+
self.assertTrue(gl_entries)
for i, gle in enumerate(gl_entries):
@@ -262,7 +262,7 @@
self.assertEquals(expected_gle[gle.account][1], gle.debit)
self.assertEquals(expected_gle[gle.account][2], gle.credit)
self.assertEquals(expected_gle[gle.account][3], gle.against_voucher)
-
+
def get_gle(self, voucher_no):
return frappe.db.sql("""select account, debit, credit, against_voucher
from `tabGL Entry` where voucher_type='Payment Entry' and voucher_no=%s
diff --git a/erpnext/docs/user/manual/en/accounts/payment-entry.md b/erpnext/docs/user/manual/en/accounts/payment-entry.md
index a6dbde0..ae82eb2 100644
--- a/erpnext/docs/user/manual/en/accounts/payment-entry.md
+++ b/erpnext/docs/user/manual/en/accounts/payment-entry.md
@@ -6,6 +6,7 @@
2. Purchase Invoice.
3. Sales Order (Advance Payment)
4. Purchase Order (Advance Payment)
+ 5. Expense Claim
####Step 1: Make Payment
@@ -21,7 +22,7 @@
####Step 3: Payment Amount
-Enter actual payment amount received from the Customer or paid to the Supplier.
+Enter actual payment amount received from the Customer or paid to the Supplier or Employee.
<img class="screenshot" alt="Making Payment" src="/docs/assets/img/accounts/payment-entry-3.png">
@@ -90,7 +91,7 @@
- Updating opening balance in an Accounts.
- Fixed Asset Depreciation entry.
- For adjusting Credit Note against Sales Invoice and Debit Note against Purchase Invoice, incase there is no payment happening at all.
-
+ 4. Payment Entries are used if a cheque is printed.
* * *
## Managing Outstanding Payments
diff --git a/erpnext/docs/user/manual/en/human-resources/expense-claim.md b/erpnext/docs/user/manual/en/human-resources/expense-claim.md
index 718e7fd..2d7432f 100644
--- a/erpnext/docs/user/manual/en/human-resources/expense-claim.md
+++ b/erpnext/docs/user/manual/en/human-resources/expense-claim.md
@@ -39,11 +39,18 @@
<img class="screenshot" alt="Expense Claim" src="/docs/assets/img/human-resources/payment.png">
#### Payment Entry
-<img class="screenshot" alt="Expense Claim" src="/docs/assets/img/human-resources/payment_entry.png">
-
+<img class="screenshot" alt="Expense Claim" src="{{docs_base_url}}/assets/img/human-resources/payment_entry.png">
Note: This amount should not be clubbed with Salary because the amount will then be taxable to the Employee.
+Alternatively, a Payment Entry can be made for an employee and all outstanding Expense Claims will be pulled in.
+
+> Accounts > Payment Entry > New Payment Entry
+
+Set the Payment Type to "Pay", the Party Type to Employee, the Party to the employee being paid and the account being paid
+from. All outstanding expense claims will be pulled in and payments amounts can be allocated to each expense.
+<img class="screenshot" alt="Expense Claim" src="{{docs_base_url}}/assets/img/human-resources/expense_claim_payment_entry.png">
+
### Linking with Task & Project
* To Link Expense Claim with Task or Project specify the Task or the Project while making an Expense Claim
diff --git a/erpnext/hr/doctype/expense_claim/test_expense_claim.py b/erpnext/hr/doctype/expense_claim/test_expense_claim.py
index 016e8fa..bcde2c0 100644
--- a/erpnext/hr/doctype/expense_claim/test_expense_claim.py
+++ b/erpnext/hr/doctype/expense_claim/test_expense_claim.py
@@ -14,7 +14,7 @@
frappe.db.sql("""delete from `tabTask` where project = "_Test Project 1" """)
frappe.db.sql("""delete from `tabProject` where name = "_Test Project 1" """)
-
+
frappe.get_doc({
"project_name": "_Test Project 1",
"doctype": "Project",
@@ -25,7 +25,7 @@
task_name = frappe.db.get_value("Task", {"project": "_Test Project 1"})
payable_account = get_payable_account("Wind Power LLC")
- expense_claim = make_expense_claim(payable_account, 300, 200, "Wind Power LLC","Travel Expenses - WP", "_Test Project 1", task_name)
+ make_expense_claim(payable_account, 300, 200, "Wind Power LLC","Travel Expenses - WP", "_Test Project 1", task_name)
self.assertEqual(frappe.db.get_value("Task", task_name, "total_expense_claim"), 200)
self.assertEqual(frappe.db.get_value("Project", "_Test Project 1", "total_expense_claim"), 200)
@@ -40,7 +40,7 @@
self.assertEqual(frappe.db.get_value("Task", task_name, "total_expense_claim"), 200)
self.assertEqual(frappe.db.get_value("Project", "_Test Project 1", "total_expense_claim"), 200)
-
+
def test_expense_claim_status(self):
payable_account = get_payable_account("Wind Power LLC")
expense_claim = make_expense_claim(payable_account, 300, 200, "Wind Power LLC", "Travel Expenses - WP")
@@ -54,7 +54,7 @@
expense_claim = frappe.get_doc("Expense Claim", expense_claim.name)
self.assertEqual(expense_claim.status, "Paid")
-
+
je.cancel()
expense_claim = frappe.get_doc("Expense Claim", expense_claim.name)
self.assertEqual(expense_claim.status, "Unpaid")
@@ -63,7 +63,7 @@
payable_account = get_payable_account("Wind Power LLC")
expense_claim = make_expense_claim(payable_account, 300, 200, "Wind Power LLC", "Travel Expenses - WP")
expense_claim.submit()
-
+
gl_entries = frappe.db.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type='Expense Claim' and voucher_no=%s
order by account asc""", expense_claim.name, as_dict=1)
@@ -100,7 +100,7 @@
def get_payable_account(company):
return frappe.db.get_value('Company', company, 'default_payable_account')
-
+
def make_expense_claim(payable_account,claim_amount, sanctioned_amount, company, account, project=None, task_name=None):
expense_claim = frappe.get_doc({
"doctype": "Expense Claim",
@@ -118,5 +118,5 @@
expense_claim.submit()
return expense_claim
-
+