diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index a0bac51046..f68d81909a 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -443,8 +443,6 @@ def make_purchase_invoice_from_portal(purchase_order_name): frappe.response.location = '/purchase-invoices/' + doc.name def get_mapped_purchase_invoice(source_name, target_doc=None, ignore_permissions=False): - from erpnext.controllers.accounts_controller import fetch_payment_terms_from_order - def postprocess(source, target): target.flags.ignore_permissions = ignore_permissions set_missing_values(source, target) @@ -496,7 +494,7 @@ def get_mapped_purchase_invoice(source_name, target_doc=None, ignore_permissions automatically_fetch_payment_terms = cint(frappe.db.get_single_value('Accounts Settings', 'automatically_fetch_payment_terms')) if automatically_fetch_payment_terms: - fetch_payment_terms_from_order(doc) + doc.set_payment_schedule() return doc diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index d38c2cbdb5..77234aa999 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -1038,7 +1038,14 @@ class AccountsController(TransactionBase): data = get_payment_terms(self.payment_terms_template, posting_date, grand_total, base_grand_total) for item in data: self.append("payment_schedule", item) - else: + + elif self.doctype in ["Sales Invoice", "Purchase Invoice"]: + po_or_so, doctype, fieldname = self.get_order_details() + + if self.linked_order_has_payment_terms(po_or_so, fieldname): + self.fetch_payment_terms_from_order(po_or_so, doctype) + + elif self.doctype not in ["Purchase Receipt"]: data = dict(due_date=due_date, invoice_portion=100, payment_amount=grand_total, base_payment_amount=base_grand_total) self.append("payment_schedule", data) else: @@ -1048,6 +1055,63 @@ class AccountsController(TransactionBase): d.base_payment_amount = flt(base_grand_total * flt(d.invoice_portion / 100), d.precision('payment_amount')) d.outstanding = d.payment_amount + def get_order_details(self): + if self.doctype == "Sales Invoice": + po_or_so = self.get('items')[0].get('sales_order') + po_or_so_doctype = "Sales Order" + po_or_so_doctype_name = "sales_order" + + else: + po_or_so = self.get('items')[0].get('purchase_order') + po_or_so_doctype = "Purchase Order" + po_or_so_doctype_name = "purchase_order" + + return po_or_so, po_or_so_doctype, po_or_so_doctype_name + + def linked_order_has_payment_terms(self, po_or_so, fieldname): + if po_or_so and self.all_items_have_same_po_or_so(po_or_so, fieldname): + if self.linked_order_has_payment_terms_template(po_or_so): + return True + elif self.linked_order_has_payment_schedule(po_or_so): + return True + + return False + + def all_items_have_same_po_or_so(self, po_or_so, fieldname): + for item in self.get('items'): + if item.get(fieldname) != po_or_so: + return False + + return True + + def linked_order_has_payment_terms_template(self, po_or_so): + return frappe.get_value('Sales Order', po_or_so, 'payment_terms_template') + + def linked_order_has_payment_schedule(self, po_or_so): + return frappe.get_all('Payment Schedule', filters={'parent': po_or_so}) + + def fetch_payment_terms_from_order(self, po_or_so, po_or_so_doctype): + """ + Fetch Payment Terms from Purchase/Sales Order on creating a new Purchase/Sales Invoice. + """ + po_or_so = frappe.get_cached_doc(po_or_so_doctype, po_or_so) + + self.payment_schedule = [] + self.payment_terms_template = po_or_so.payment_terms_template + + for schedule in po_or_so.payment_schedule: + payment_schedule = { + 'payment_term': schedule.payment_term, + 'due_date': schedule.due_date, + 'invoice_portion': schedule.invoice_portion, + 'discount_type': schedule.discount_type, + 'discount': schedule.discount, + 'base_payment_amount': schedule.base_payment_amount, + 'payment_amount': schedule.payment_amount, + 'outstanding': schedule.outstanding + } + self.append("payment_schedule", payment_schedule) + def set_due_date(self): due_dates = [d.due_date for d in self.get("payment_schedule") if d.due_date] if due_dates: @@ -1729,47 +1793,4 @@ def validate_regional(doc): @erpnext.allow_regional def validate_einvoice_fields(doc): - pass - -def fetch_payment_terms_from_order(doc): - """ - Fetch Payment Terms from Purchase/Sales Order on creating a new Purchase/Sales Invoice. - """ - - if doc.doctype == "Sales Invoice": - po_or_so = doc.get('items')[0].get('sales_order') - po_or_so_doctype = "Sales Order" - po_or_so_doctype_name = "sales_order" - else: - po_or_so = doc.get('items')[0].get('purchase_order') - po_or_so_doctype = "Purchase Order" - po_or_so_doctype_name = "purchase_order" - - if po_or_so and all_items_have_same_po_or_so(doc, po_or_so, po_or_so_doctype_name): - po_or_so = frappe.get_cached_doc(po_or_so_doctype, po_or_so) - else: - doc.set_payment_schedule() - return - - doc.payment_schedule = [] - doc.payment_terms_template = po_or_so.payment_terms_template - - for schedule in po_or_so.payment_schedule: - payment_schedule = { - 'payment_term': schedule.payment_term, - 'due_date': schedule.due_date, - 'invoice_portion': schedule.invoice_portion, - 'discount_type': schedule.discount_type, - 'discount': schedule.discount, - 'base_payment_amount': schedule.base_payment_amount, - 'payment_amount': schedule.payment_amount, - 'outstanding': schedule.outstanding - } - doc.append("payment_schedule", payment_schedule) - -def all_items_have_same_po_or_so(doc, po_or_so, po_or_so_fieldname): - for item in doc.get('items'): - if item.get(po_or_so_fieldname) != po_or_so: - return False - - return True \ No newline at end of file + pass \ 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 a58c381df3..2b9d516e21 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -621,8 +621,6 @@ def make_delivery_note(source_name, target_doc=None, skip_item_mapping=False): @frappe.whitelist() def make_sales_invoice(source_name, target_doc=None, ignore_permissions=False): - from erpnext.controllers.accounts_controller import fetch_payment_terms_from_order - def postprocess(source, target): set_missing_values(source, target) #Get the advance paid Journal Entries in Sales Invoice Advance @@ -697,7 +695,7 @@ def make_sales_invoice(source_name, target_doc=None, ignore_permissions=False): automatically_fetch_payment_terms = cint(frappe.db.get_single_value('Accounts Settings', 'automatically_fetch_payment_terms')) if automatically_fetch_payment_terms: - fetch_payment_terms_from_order(doclist) + doclist.set_payment_schedule() return doclist diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py index 1628f93019..f99a01b820 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/delivery_note.py @@ -414,8 +414,6 @@ def get_returned_qty_map(delivery_note): @frappe.whitelist() def make_sales_invoice(source_name, target_doc=None): - from erpnext.controllers.accounts_controller import fetch_payment_terms_from_order - doc = frappe.get_doc('Delivery Note', source_name) to_make_invoice_qty_map = {} @@ -507,7 +505,7 @@ def make_sales_invoice(source_name, target_doc=None): automatically_fetch_payment_terms = cint(frappe.db.get_single_value('Accounts Settings', 'automatically_fetch_payment_terms')) if automatically_fetch_payment_terms: - fetch_payment_terms_from_order(doc) + doc.set_payment_schedule() return doc diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index 6d72a5fa0b..36f21465b5 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -604,7 +604,6 @@ def update_billing_percentage(pr_doc, update_modified=True): @frappe.whitelist() def make_purchase_invoice(source_name, target_doc=None): from erpnext.accounts.party import get_payment_terms_template - from erpnext.controllers.accounts_controller import fetch_payment_terms_from_order doc = frappe.get_doc('Purchase Receipt', source_name) returned_qty_map = get_returned_qty_map(source_name) @@ -678,7 +677,7 @@ def make_purchase_invoice(source_name, target_doc=None): automatically_fetch_payment_terms = cint(frappe.db.get_single_value('Accounts Settings', 'automatically_fetch_payment_terms')) if automatically_fetch_payment_terms: - fetch_payment_terms_from_order(doclist) + doc.set_payment_schedule() return doclist