diff --git a/erpnext/accounts/doctype/payment_request/payment_request.js b/erpnext/accounts/doctype/payment_request/payment_request.js index e73da4c507..afc3804ff7 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.js +++ b/erpnext/accounts/doctype/payment_request/payment_request.js @@ -31,5 +31,21 @@ frappe.ui.form.on("Payment Request", "refresh", function(frm) { }); }); } + + if(!frm.doc.payment_gateway_account && frm.doc.status == "Initiated") { + frm.add_custom_button(__('Make Payment Entry'), function(){ + frappe.call({ + method: "erpnext.accounts.doctype.payment_request.payment_request.make_payment_entry", + args: {"docname": frm.doc.name}, + freeze: true, + callback: function(r){ + if(!r.exc) { + var doc = frappe.model.sync(r.message); + frappe.set_route("Form", r.message.doctype, r.message.name); + } + } + }); + }).addClass("btn-primary"); + } }); diff --git a/erpnext/accounts/doctype/payment_request/payment_request.json b/erpnext/accounts/doctype/payment_request/payment_request.json index eca0ad092d..3a3802ffbf 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.json +++ b/erpnext/accounts/doctype/payment_request/payment_request.json @@ -3,11 +3,13 @@ "allow_import": 0, "allow_rename": 0, "autoname": "PR.######", + "beta": 0, "creation": "2015-12-15 22:23:24.745065", "custom": 0, "docstatus": 0, "doctype": "DocType", "document_type": "", + "editable_grid": 0, "fields": [ { "allow_on_submit": 0, @@ -156,7 +158,7 @@ "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, - "reqd": 1, + "reqd": 0, "search_index": 0, "set_only_once": 0, "unique": 0 @@ -404,30 +406,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "fieldname": "column_break_16", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, + "label": "Payment Gateway Details", "length": 0, "no_copy": 0, "permlevel": 0, @@ -599,13 +578,14 @@ "hide_heading": 0, "hide_toolbar": 0, "idx": 0, + "image_view": 0, "in_create": 1, "in_dialog": 0, "is_submittable": 1, "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2016-05-03 10:31:45.692016", + "modified": "2016-07-21 19:11:57.517964", "modified_by": "Administrator", "module": "Accounts", "name": "Payment Request", diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py index 0c8df0220f..30d043f729 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.py +++ b/erpnext/accounts/doctype/payment_request/payment_request.py @@ -13,7 +13,6 @@ from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_ent class PaymentRequest(Document): def validate(self): - self.validate_payment_gateway_account() self.validate_payment_request() self.validate_currency() @@ -24,19 +23,9 @@ class PaymentRequest(Document): def validate_currency(self): ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name) - if ref_doc.currency != frappe.db.get_value("Account", self.payment_account, "account_currency"): + if self.payment_account and ref_doc.currency != frappe.db.get_value("Account", self.payment_account, "account_currency"): frappe.throw(_("Transaction currency must be same as Payment Gateway currency")) - def validate_payment_gateway_account(self): - if not self.payment_gateway: - frappe.throw(_("Payment Gateway Account is not configured")) - - def validate_payment_gateway(self): - if self.payment_gateway == "PayPal": - if not frappe.db.get_value("PayPal Settings", None, "api_username"): - if not frappe.conf.paypal_username: - frappe.throw(_("PayPal Settings missing")) - def on_submit(self): send_mail = True self.make_communication_entry() @@ -45,7 +34,7 @@ class PaymentRequest(Document): if hasattr(ref_doc, "order_type") and getattr(ref_doc, "order_type") == "Shopping Cart": send_mail = False - if send_mail: + if send_mail and not self.flags.mute_email: self.send_payment_request() self.send_email() @@ -66,9 +55,13 @@ class PaymentRequest(Document): si.submit() def send_payment_request(self): - self.payment_url = get_url("/api/method/erpnext.accounts.doctype.payment_request.payment_request.generate_payment_request?name={0}".format(self.name)) + if self.payment_account: + self.payment_url = get_url("/api/method/erpnext.accounts.doctype.payment_request.payment_request.generate_payment_request?name={0}".format(self.name)) + if self.payment_url: self.db_set('payment_url', self.payment_url) + + if self.payment_url or not self.payment_gateway_account: self.db_set('status', 'Initiated') def set_as_paid(self): @@ -80,7 +73,7 @@ class PaymentRequest(Document): return payment_entry - def create_payment_entry(self): + def create_payment_entry(self, submit=True): """create entry""" frappe.flags.ignore_account_permission = True @@ -111,18 +104,18 @@ class PaymentRequest(Document): self.reference_name, self.name) }) - company_details = get_company_defaults(ref_doc.company) if payment_entry.difference_amount: + company_details = get_company_defaults(ref_doc.company) + payment_entry.append("deductions", { "account": company_details.exchange_gain_loss_account, "cost_center": company_details.cost_center, "amount": payment_entry.difference_amount }) - payment_entry.insert(ignore_permissions=True) - payment_entry.submit() - #set status as paid for Payment Request - self.db_set('status', 'Paid') + if submit: + payment_entry.insert(ignore_permissions=True) + payment_entry.submit() return payment_entry @@ -140,7 +133,8 @@ class PaymentRequest(Document): "payment_url": self.payment_url } - return frappe.render_template(self.message, context) + if self.message: + return frappe.render_template(self.message, context) def set_failed(self): pass @@ -171,7 +165,7 @@ def make_payment_request(**args): ref_doc = frappe.get_doc(args.dt, args.dn) - gateway_account = get_gateway_details(args) + gateway_account = get_gateway_details(args) or frappe._dict() grand_total = get_amount(ref_doc, args.dt) @@ -184,20 +178,24 @@ def make_payment_request(**args): else: pr = frappe.new_doc("Payment Request") pr.update({ - "payment_gateway_account": gateway_account.name, - "payment_gateway": gateway_account.payment_gateway, - "payment_account": gateway_account.payment_account, + "payment_gateway_account": gateway_account.get("name"), + "payment_gateway": gateway_account.get("payment_gateway"), + "payment_account": gateway_account.get("payment_account"), "currency": ref_doc.currency, "grand_total": grand_total, "email_to": args.recipient_id or "", "subject": "Payment Request for %s"%args.dn, - "message": gateway_account.message, + "message": gateway_account.get("message") or get_dummy_message(args.use_dummy_message), "reference_doctype": args.dt, "reference_name": args.dn }) if args.return_doc: return pr + + if args.mute_email: + pr.flags.mute_email = True + if args.submit_doc: pr.insert(ignore_permissions=True) pr.submit() @@ -239,9 +237,6 @@ def get_gateway_details(args): gateway_account = get_payment_gateway_account({"is_default": 1}) - if not gateway_account: - frappe.throw(_("Payment Gateway Account is not configured")) - return gateway_account def get_payment_gateway_account(args): @@ -267,3 +262,29 @@ def generate_payment_request(name): @frappe.whitelist(allow_guest=True) def resend_payment_email(docname): return frappe.get_doc("Payment Request", docname).send_email() + +@frappe.whitelist() +def make_payment_entry(docname): + doc = frappe.get_doc("Payment Request", docname) + return doc.create_payment_entry(submit=False).as_dict() + +def make_status_as_paid(doc, method): + for ref in doc.references: + payment_request_name = frappe.db.get_value("Payment Request", + {"reference_doctype": ref.reference_doctype, "reference_name": ref.reference_name, + "docstatus": 1}) + + if payment_request_name: + doc = frappe.get_doc("Payment Request", payment_request_name) + if doc.status != "Paid": + doc.db_set('status', 'Paid') + +def get_dummy_message(use_dummy_message=True): + return """ +

Hope you are enjoying a service. Please consider bank details for payment

+

Bank Details


+

Bank Name : National Bank

+

Account Number : 123456789000872

+

IFSC code : NB000001

+

Account Name : Wind Power LLC

+ """ diff --git a/erpnext/demo/user/accounts.py b/erpnext/demo/user/accounts.py index e7dceb3887..052d4560ef 100644 --- a/erpnext/demo/user/accounts.py +++ b/erpnext/demo/user/accounts.py @@ -10,6 +10,8 @@ from frappe.utils import random_string from frappe.desk import query_report from erpnext.accounts.doctype.journal_entry.journal_entry import get_payment_entry_against_invoice from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry +from frappe.utils.make_random import get_random +from erpnext.accounts.doctype.payment_request.payment_request import make_payment_request, make_payment_entry def work(): frappe.set_user(frappe.db.get_global('demo_accounts_user')) @@ -46,10 +48,23 @@ def work(): if random.random() < 0.5: make_payment_entries("Purchase Invoice", "Accounts Payable") + if random.random() < 0.1: + #make payment request against sales invoice + sales_invoice_name = get_random("Sales Invoice", filters={"docstatus": 1}) + if sales_invoice_name: + si = frappe.get_doc("Sales Invoice", sales_invoice_name) + if si.outstanding_amount > 0: + payment_request = make_payment_request(dt="Sales Invoice", dn=si.name, recipient_id=si.contact_email, + submit_doc=True, mute_email=True, use_dummy_message=True) + + payment_entry = frappe.get_doc(make_payment_entry(payment_request.name)) + payment_entry.posting_date = frappe.flags.current_date + payment_entry.submit() + def make_payment_entries(ref_doctype, report): - outstanding_invoices = list(set([r[3] for r in query_report.run(report, + outstanding_invoices = list(set([r[3] for r in query_report.run(report, {"report_date": frappe.flags.current_date })["result"] if r[2]==ref_doctype])) - + # make Payment Entry for inv in outstanding_invoices[:random.randint(1, 2)]: pe = get_payment_entry(ref_doctype, inv) @@ -69,4 +84,4 @@ def make_payment_entries(ref_doctype, report): jv.cheque_date = frappe.flags.current_date jv.insert() jv.submit() - frappe.db.commit() \ No newline at end of file + frappe.db.commit() diff --git a/erpnext/demo/user/sales.py b/erpnext/demo/user/sales.py index 6b36b46f78..10df14334f 100644 --- a/erpnext/demo/user/sales.py +++ b/erpnext/demo/user/sales.py @@ -4,9 +4,11 @@ from __future__ import unicode_literals import frappe, random +from frappe.utils import flt from frappe.utils.make_random import add_random_children, get_random from erpnext.setup.utils import get_exchange_rate from erpnext.accounts.party import get_party_account_currency +from erpnext.accounts.doctype.payment_request.payment_request import make_payment_request, make_payment_entry def work(): frappe.set_user(frappe.db.get_global('demo_sales_user_2')) @@ -34,6 +36,19 @@ def work(): for i in xrange(random.randint(1,3)): make_sales_order() + if random.random() < 0.1: + #make payment request against Sales Order + sales_order_name = get_random("Sales Order", filters={"docstatus": 1}) + if sales_order_name: + so = frappe.get_doc("Sales Order", sales_order_name) + if flt(so.per_billed) != 100: + payment_request = make_payment_request(dt="Sales Order", dn=so.name, recipient_id=so.contact_email, + submit_doc=True, mute_email=True, use_dummy_message=True) + + payment_entry = frappe.get_doc(make_payment_entry(payment_request.name)) + payment_entry.posting_date = frappe.flags.current_date + payment_entry.submit() + def make_opportunity(): b = frappe.get_doc({ "doctype": "Opportunity", diff --git a/erpnext/hooks.py b/erpnext/hooks.py index fd188bc83e..82d23de2ac 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -158,6 +158,9 @@ doc_events = { "Website Settings": { "validate": "erpnext.portal.doctype.products_settings.products_settings.home_page_is_products" + }, + "Payment Entry": { + "on_submit": "erpnext.accounts.doctype.payment_request.payment_request.make_status_as_paid" } }