Merge pull request #26397 from GangaManoj/po-payment-terms
feat: Fetch Payment Terms from linked Sales/Purchase Order
This commit is contained in:
commit
f037bae8ea
@ -275,7 +275,7 @@ erpnext.accounts.PurchaseInvoice = class PurchaseInvoice extends erpnext.buying.
|
|||||||
// Do not update if inter company reference is there as the details will already be updated
|
// Do not update if inter company reference is there as the details will already be updated
|
||||||
if(this.frm.updating_party_details || this.frm.doc.inter_company_invoice_reference)
|
if(this.frm.updating_party_details || this.frm.doc.inter_company_invoice_reference)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
erpnext.utils.get_party_details(this.frm, "erpnext.accounts.party.get_party_details",
|
erpnext.utils.get_party_details(this.frm, "erpnext.accounts.party.get_party_details",
|
||||||
{
|
{
|
||||||
posting_date: this.frm.doc.posting_date,
|
posting_date: this.frm.doc.posting_date,
|
||||||
@ -283,7 +283,8 @@ erpnext.accounts.PurchaseInvoice = class PurchaseInvoice extends erpnext.buying.
|
|||||||
party: this.frm.doc.supplier,
|
party: this.frm.doc.supplier,
|
||||||
party_type: "Supplier",
|
party_type: "Supplier",
|
||||||
account: this.frm.doc.credit_to,
|
account: this.frm.doc.credit_to,
|
||||||
price_list: this.frm.doc.buying_price_list
|
price_list: this.frm.doc.buying_price_list,
|
||||||
|
fetch_payment_terms_template: cint(!this.frm.doc.ignore_default_payment_terms_template)
|
||||||
}, function() {
|
}, function() {
|
||||||
me.apply_pricing_rule();
|
me.apply_pricing_rule();
|
||||||
me.frm.doc.apply_tds = me.frm.supplier_tds ? 1 : 0;
|
me.frm.doc.apply_tds = me.frm.supplier_tds ? 1 : 0;
|
||||||
@ -570,4 +571,4 @@ frappe.ui.form.on("Purchase Invoice", {
|
|||||||
company: function(frm) {
|
company: function(frm) {
|
||||||
erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
|
erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
|
||||||
},
|
},
|
||||||
})
|
})
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -8,7 +8,7 @@ from frappe import _, msgprint, scrub
|
|||||||
from frappe.core.doctype.user_permission.user_permission import get_permitted_documents
|
from frappe.core.doctype.user_permission.user_permission import get_permitted_documents
|
||||||
from frappe.model.utils import get_fetch_values
|
from frappe.model.utils import get_fetch_values
|
||||||
from frappe.utils import (add_days, getdate, formatdate, date_diff,
|
from frappe.utils import (add_days, getdate, formatdate, date_diff,
|
||||||
add_years, get_timestamp, nowdate, flt, cstr, add_months, get_last_day)
|
add_years, get_timestamp, nowdate, flt, cstr, add_months, get_last_day, cint)
|
||||||
from frappe.contacts.doctype.address.address import (get_address_display,
|
from frappe.contacts.doctype.address.address import (get_address_display,
|
||||||
get_default_address, get_company_address)
|
get_default_address, get_company_address)
|
||||||
from frappe.contacts.doctype.contact.contact import get_contact_details
|
from frappe.contacts.doctype.contact.contact import get_contact_details
|
||||||
@ -58,7 +58,7 @@ def _get_party_details(party=None, account=None, party_type="Customer", company=
|
|||||||
customer_group=party_details.customer_group, supplier_group=party_details.supplier_group, tax_category=party_details.tax_category,
|
customer_group=party_details.customer_group, supplier_group=party_details.supplier_group, tax_category=party_details.tax_category,
|
||||||
billing_address=party_address, shipping_address=shipping_address)
|
billing_address=party_address, shipping_address=shipping_address)
|
||||||
|
|
||||||
if fetch_payment_terms_template:
|
if cint(fetch_payment_terms_template):
|
||||||
party_details["payment_terms_template"] = get_payment_terms_template(party.name, party_type, company)
|
party_details["payment_terms_template"] = get_payment_terms_template(party.name, party_type, company)
|
||||||
|
|
||||||
if not party_details.get("currency"):
|
if not party_details.get("currency"):
|
||||||
|
@ -447,10 +447,11 @@ def get_mapped_purchase_invoice(source_name, target_doc=None, ignore_permissions
|
|||||||
target.flags.ignore_permissions = ignore_permissions
|
target.flags.ignore_permissions = ignore_permissions
|
||||||
set_missing_values(source, target)
|
set_missing_values(source, target)
|
||||||
#Get the advance paid Journal Entries in Purchase Invoice Advance
|
#Get the advance paid Journal Entries in Purchase Invoice Advance
|
||||||
|
|
||||||
if target.get("allocate_advances_automatically"):
|
if target.get("allocate_advances_automatically"):
|
||||||
target.set_advances()
|
target.set_advances()
|
||||||
|
|
||||||
|
target.set_payment_schedule()
|
||||||
|
|
||||||
def update_item(obj, target, source_parent):
|
def update_item(obj, target, source_parent):
|
||||||
target.amount = flt(obj.amount) - flt(obj.billed_amt)
|
target.amount = flt(obj.amount) - flt(obj.billed_amt)
|
||||||
target.base_amount = target.amount * flt(source_parent.conversion_rate)
|
target.base_amount = target.amount * flt(source_parent.conversion_rate)
|
||||||
@ -470,6 +471,7 @@ def get_mapped_purchase_invoice(source_name, target_doc=None, ignore_permissions
|
|||||||
"party_account_currency": "party_account_currency",
|
"party_account_currency": "party_account_currency",
|
||||||
"supplier_warehouse":"supplier_warehouse"
|
"supplier_warehouse":"supplier_warehouse"
|
||||||
},
|
},
|
||||||
|
"field_no_map" : ["payment_terms_template"],
|
||||||
"validation": {
|
"validation": {
|
||||||
"docstatus": ["=", 1],
|
"docstatus": ["=", 1],
|
||||||
}
|
}
|
||||||
@ -489,12 +491,6 @@ def get_mapped_purchase_invoice(source_name, target_doc=None, ignore_permissions
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if frappe.get_single("Accounts Settings").automatically_fetch_payment_terms == 1:
|
|
||||||
fields["Payment Schedule"] = {
|
|
||||||
"doctype": "Payment Schedule",
|
|
||||||
"add_if_empty": True
|
|
||||||
}
|
|
||||||
|
|
||||||
doc = get_mapped_doc("Purchase Order", source_name, fields,
|
doc = get_mapped_doc("Purchase Order", source_name, fields,
|
||||||
target_doc, postprocess, ignore_permissions=ignore_permissions)
|
target_doc, postprocess, ignore_permissions=ignore_permissions)
|
||||||
|
|
||||||
|
@ -484,6 +484,9 @@ class TestPurchaseOrder(unittest.TestCase):
|
|||||||
|
|
||||||
|
|
||||||
def test_make_purchase_invoice_with_terms(self):
|
def test_make_purchase_invoice_with_terms(self):
|
||||||
|
from erpnext.selling.doctype.sales_order.test_sales_order import automatically_fetch_payment_terms, compare_payment_schedules
|
||||||
|
|
||||||
|
automatically_fetch_payment_terms()
|
||||||
po = create_purchase_order(do_not_save=True)
|
po = create_purchase_order(do_not_save=True)
|
||||||
|
|
||||||
self.assertRaises(frappe.ValidationError, make_pi_from_po, po.name)
|
self.assertRaises(frappe.ValidationError, make_pi_from_po, po.name)
|
||||||
@ -509,6 +512,7 @@ class TestPurchaseOrder(unittest.TestCase):
|
|||||||
self.assertEqual(getdate(pi.payment_schedule[0].due_date), getdate(po.transaction_date))
|
self.assertEqual(getdate(pi.payment_schedule[0].due_date), getdate(po.transaction_date))
|
||||||
self.assertEqual(pi.payment_schedule[1].payment_amount, 2500.0)
|
self.assertEqual(pi.payment_schedule[1].payment_amount, 2500.0)
|
||||||
self.assertEqual(getdate(pi.payment_schedule[1].due_date), add_days(getdate(po.transaction_date), 30))
|
self.assertEqual(getdate(pi.payment_schedule[1].due_date), add_days(getdate(po.transaction_date), 30))
|
||||||
|
automatically_fetch_payment_terms(enable=0)
|
||||||
|
|
||||||
def test_subcontracting(self):
|
def test_subcontracting(self):
|
||||||
po = create_purchase_order(item_code="_Test FG Item", is_subcontracted="Yes")
|
po = create_purchase_order(item_code="_Test FG Item", is_subcontracted="Yes")
|
||||||
@ -632,14 +636,18 @@ class TestPurchaseOrder(unittest.TestCase):
|
|||||||
else:
|
else:
|
||||||
raise Exception
|
raise Exception
|
||||||
|
|
||||||
def test_terms_does_not_copy(self):
|
def test_terms_are_not_copied_if_automatically_fetch_payment_terms_is_unchecked(self):
|
||||||
po = create_purchase_order()
|
po = create_purchase_order(do_not_save=1)
|
||||||
|
po.payment_terms_template = '_Test Payment Term Template'
|
||||||
self.assertTrue(po.get('payment_schedule'))
|
po.save()
|
||||||
|
po.submit()
|
||||||
|
|
||||||
|
frappe.db.set_value('Company', '_Test Company', 'payment_terms', '_Test Payment Term Template 1')
|
||||||
pi = make_pi_from_po(po.name)
|
pi = make_pi_from_po(po.name)
|
||||||
|
pi.save()
|
||||||
|
|
||||||
self.assertFalse(pi.get('payment_schedule'))
|
self.assertEqual(pi.get('payment_terms_template'), '_Test Payment Term Template 1')
|
||||||
|
frappe.db.set_value('Company', '_Test Company', 'payment_terms', '')
|
||||||
|
|
||||||
def test_terms_copied(self):
|
def test_terms_copied(self):
|
||||||
po = create_purchase_order(do_not_save=1)
|
po = create_purchase_order(do_not_save=1)
|
||||||
@ -968,8 +976,27 @@ class TestPurchaseOrder(unittest.TestCase):
|
|||||||
# To test if the PO does NOT have a Blanket Order
|
# To test if the PO does NOT have a Blanket Order
|
||||||
self.assertEqual(po_doc.items[0].blanket_order, None)
|
self.assertEqual(po_doc.items[0].blanket_order, None)
|
||||||
|
|
||||||
|
def test_payment_terms_are_fetched_when_creating_purchase_invoice(self):
|
||||||
|
from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_terms_template
|
||||||
|
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
|
||||||
|
from erpnext.selling.doctype.sales_order.test_sales_order import automatically_fetch_payment_terms, compare_payment_schedules
|
||||||
|
|
||||||
|
automatically_fetch_payment_terms()
|
||||||
|
|
||||||
|
po = create_purchase_order(qty=10, rate=100, do_not_save=1)
|
||||||
|
create_payment_terms_template()
|
||||||
|
po.payment_terms_template = 'Test Receivable Template'
|
||||||
|
po.submit()
|
||||||
|
|
||||||
|
pi = make_purchase_invoice(qty=10, rate=100, do_not_save=1)
|
||||||
|
pi.items[0].purchase_order = po.name
|
||||||
|
pi.items[0].po_detail = po.items[0].name
|
||||||
|
pi.insert()
|
||||||
|
|
||||||
|
# self.assertEqual(po.payment_terms_template, pi.payment_terms_template)
|
||||||
|
compare_payment_schedules(self, po, pi)
|
||||||
|
|
||||||
|
automatically_fetch_payment_terms(enable=0)
|
||||||
|
|
||||||
def make_pr_against_po(po, received_qty=0):
|
def make_pr_against_po(po, received_qty=0):
|
||||||
pr = make_purchase_receipt(po)
|
pr = make_purchase_receipt(po)
|
||||||
|
@ -1096,6 +1096,8 @@ class AccountsController(TransactionBase):
|
|||||||
if self.doctype in ("Sales Invoice", "Purchase Invoice"):
|
if self.doctype in ("Sales Invoice", "Purchase Invoice"):
|
||||||
base_grand_total = base_grand_total - flt(self.base_write_off_amount)
|
base_grand_total = base_grand_total - flt(self.base_write_off_amount)
|
||||||
grand_total = grand_total - flt(self.write_off_amount)
|
grand_total = grand_total - flt(self.write_off_amount)
|
||||||
|
po_or_so, doctype, fieldname = self.get_order_details()
|
||||||
|
automatically_fetch_payment_terms = cint(frappe.db.get_single_value('Accounts Settings', 'automatically_fetch_payment_terms'))
|
||||||
|
|
||||||
if self.get("total_advance"):
|
if self.get("total_advance"):
|
||||||
if party_account_currency == self.company_currency:
|
if party_account_currency == self.company_currency:
|
||||||
@ -1106,22 +1108,86 @@ class AccountsController(TransactionBase):
|
|||||||
base_grand_total = flt(grand_total * self.get("conversion_rate"), self.precision("base_grand_total"))
|
base_grand_total = flt(grand_total * self.get("conversion_rate"), self.precision("base_grand_total"))
|
||||||
|
|
||||||
if not self.get("payment_schedule"):
|
if not self.get("payment_schedule"):
|
||||||
if self.get("payment_terms_template"):
|
if self.doctype in ["Sales Invoice", "Purchase Invoice"] and automatically_fetch_payment_terms \
|
||||||
|
and self.linked_order_has_payment_terms(po_or_so, fieldname, doctype):
|
||||||
|
self.fetch_payment_terms_from_order(po_or_so, doctype)
|
||||||
|
if self.get('payment_terms_template'):
|
||||||
|
self.ignore_default_payment_terms_template = 1
|
||||||
|
elif self.get("payment_terms_template"):
|
||||||
data = get_payment_terms(self.payment_terms_template, posting_date, grand_total, base_grand_total)
|
data = get_payment_terms(self.payment_terms_template, posting_date, grand_total, base_grand_total)
|
||||||
for item in data:
|
for item in data:
|
||||||
self.append("payment_schedule", item)
|
self.append("payment_schedule", item)
|
||||||
else:
|
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)
|
data = dict(due_date=due_date, invoice_portion=100, payment_amount=grand_total, base_payment_amount=base_grand_total)
|
||||||
self.append("payment_schedule", data)
|
self.append("payment_schedule", data)
|
||||||
else:
|
|
||||||
for d in self.get("payment_schedule"):
|
|
||||||
if d.invoice_portion:
|
|
||||||
d.payment_amount = flt(grand_total * flt(d.invoice_portion / 100), d.precision('payment_amount'))
|
|
||||||
d.base_payment_amount = flt(base_grand_total * flt(d.invoice_portion / 100), d.precision('base_payment_amount'))
|
|
||||||
d.outstanding = d.payment_amount
|
|
||||||
elif not d.invoice_portion:
|
|
||||||
d.base_payment_amount = flt(base_grand_total * self.get("conversion_rate"), d.precision('base_payment_amount'))
|
|
||||||
|
|
||||||
|
for d in self.get("payment_schedule"):
|
||||||
|
if d.invoice_portion:
|
||||||
|
d.payment_amount = flt(grand_total * flt(d.invoice_portion / 100), d.precision('payment_amount'))
|
||||||
|
d.base_payment_amount = flt(base_grand_total * flt(d.invoice_portion / 100), d.precision('base_payment_amount'))
|
||||||
|
d.outstanding = d.payment_amount
|
||||||
|
elif not d.invoice_portion:
|
||||||
|
d.base_payment_amount = flt(base_grand_total * self.get("conversion_rate"), d.precision('base_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, doctype):
|
||||||
|
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, doctype):
|
||||||
|
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, doctype):
|
||||||
|
return frappe.get_value(doctype, 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,
|
||||||
|
'mode_of_payment': schedule.mode_of_payment,
|
||||||
|
'description': schedule.description
|
||||||
|
}
|
||||||
|
|
||||||
|
if schedule.discount_type == 'Percentage':
|
||||||
|
payment_schedule['discount_type'] = schedule.discount_type
|
||||||
|
payment_schedule['discount'] = schedule.discount
|
||||||
|
|
||||||
|
self.append("payment_schedule", payment_schedule)
|
||||||
|
|
||||||
def set_due_date(self):
|
def set_due_date(self):
|
||||||
due_dates = [d.due_date for d in self.get("payment_schedule") if d.due_date]
|
due_dates = [d.due_date for d in self.get("payment_schedule") if d.due_date]
|
||||||
@ -1829,4 +1895,4 @@ def validate_regional(doc):
|
|||||||
|
|
||||||
@erpnext.allow_regional
|
@erpnext.allow_regional
|
||||||
def validate_einvoice_fields(doc):
|
def validate_einvoice_fields(doc):
|
||||||
pass
|
pass
|
@ -72,7 +72,8 @@ class BuyingController(StockController, Subcontracting):
|
|||||||
# set contact and address details for supplier, if they are not mentioned
|
# set contact and address details for supplier, if they are not mentioned
|
||||||
if getattr(self, "supplier", None):
|
if getattr(self, "supplier", None):
|
||||||
self.update_if_missing(get_party_details(self.supplier, party_type="Supplier", ignore_permissions=self.flags.ignore_permissions,
|
self.update_if_missing(get_party_details(self.supplier, party_type="Supplier", ignore_permissions=self.flags.ignore_permissions,
|
||||||
doctype=self.doctype, company=self.company, party_address=self.supplier_address, shipping_address=self.get('shipping_address')))
|
doctype=self.doctype, company=self.company, party_address=self.supplier_address, shipping_address=self.get('shipping_address'),
|
||||||
|
fetch_payment_terms_template= not self.get('ignore_default_payment_terms_template')))
|
||||||
|
|
||||||
self.set_missing_item_details(for_validate)
|
self.set_missing_item_details(for_validate)
|
||||||
|
|
||||||
|
@ -76,6 +76,7 @@ erpnext.utils.get_party_details = function(frm, method, args, callback) {
|
|||||||
|
|
||||||
if (args) {
|
if (args) {
|
||||||
args.posting_date = frm.doc.posting_date || frm.doc.transaction_date;
|
args.posting_date = frm.doc.posting_date || frm.doc.transaction_date;
|
||||||
|
args.fetch_payment_terms_template = cint(!frm.doc.ignore_default_payment_terms_template);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!args || !args.party) return;
|
if (!args || !args.party) return;
|
||||||
|
@ -670,6 +670,7 @@ def make_sales_invoice(source_name, target_doc=None, ignore_permissions=False):
|
|||||||
"party_account_currency": "party_account_currency",
|
"party_account_currency": "party_account_currency",
|
||||||
"payment_terms_template": "payment_terms_template"
|
"payment_terms_template": "payment_terms_template"
|
||||||
},
|
},
|
||||||
|
"field_no_map": ["payment_terms_template"],
|
||||||
"validation": {
|
"validation": {
|
||||||
"docstatus": ["=", 1]
|
"docstatus": ["=", 1]
|
||||||
}
|
}
|
||||||
@ -693,6 +694,10 @@ def make_sales_invoice(source_name, target_doc=None, ignore_permissions=False):
|
|||||||
}
|
}
|
||||||
}, target_doc, postprocess, ignore_permissions=ignore_permissions)
|
}, target_doc, postprocess, ignore_permissions=ignore_permissions)
|
||||||
|
|
||||||
|
automatically_fetch_payment_terms = cint(frappe.db.get_single_value('Accounts Settings', 'automatically_fetch_payment_terms'))
|
||||||
|
if automatically_fetch_payment_terms:
|
||||||
|
doclist.set_payment_schedule()
|
||||||
|
|
||||||
return doclist
|
return doclist
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
|
@ -5,7 +5,7 @@ import json
|
|||||||
import unittest
|
import unittest
|
||||||
import frappe
|
import frappe
|
||||||
import frappe.permissions
|
import frappe.permissions
|
||||||
from frappe.utils import flt, add_days, nowdate
|
from frappe.utils import flt, add_days, nowdate, getdate
|
||||||
from frappe.core.doctype.user_permission.test_user_permission import create_user
|
from frappe.core.doctype.user_permission.test_user_permission import create_user
|
||||||
from erpnext.selling.doctype.sales_order.sales_order \
|
from erpnext.selling.doctype.sales_order.sales_order \
|
||||||
import make_material_request, make_delivery_note, make_sales_invoice, WarehouseRequired
|
import make_material_request, make_delivery_note, make_sales_invoice, WarehouseRequired
|
||||||
@ -1231,7 +1231,38 @@ class TestSalesOrder(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertRaises(frappe.ValidationError, so.cancel)
|
self.assertRaises(frappe.ValidationError, so.cancel)
|
||||||
|
|
||||||
|
def test_payment_terms_are_fetched_when_creating_sales_invoice(self):
|
||||||
|
from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_terms_template
|
||||||
|
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
||||||
|
|
||||||
|
automatically_fetch_payment_terms()
|
||||||
|
|
||||||
|
so = make_sales_order(uom="Nos", do_not_save=1)
|
||||||
|
create_payment_terms_template()
|
||||||
|
so.payment_terms_template = 'Test Receivable Template'
|
||||||
|
so.submit()
|
||||||
|
|
||||||
|
si = create_sales_invoice(qty=10, do_not_save=1)
|
||||||
|
si.items[0].sales_order = so.name
|
||||||
|
si.items[0].so_detail = so.items[0].name
|
||||||
|
si.insert()
|
||||||
|
|
||||||
|
self.assertEqual(so.payment_terms_template, si.payment_terms_template)
|
||||||
|
compare_payment_schedules(self, so, si)
|
||||||
|
|
||||||
|
automatically_fetch_payment_terms(enable=0)
|
||||||
|
|
||||||
|
def automatically_fetch_payment_terms(enable=1):
|
||||||
|
accounts_settings = frappe.get_doc("Accounts Settings")
|
||||||
|
accounts_settings.automatically_fetch_payment_terms = enable
|
||||||
|
accounts_settings.save()
|
||||||
|
|
||||||
|
def compare_payment_schedules(doc, doc1, doc2):
|
||||||
|
for index, schedule in enumerate(doc1.get('payment_schedule')):
|
||||||
|
doc.assertEqual(schedule.payment_term, doc2.payment_schedule[index].payment_term)
|
||||||
|
doc.assertEqual(getdate(schedule.due_date), doc2.payment_schedule[index].due_date)
|
||||||
|
doc.assertEqual(schedule.invoice_portion, doc2.payment_schedule[index].invoice_portion)
|
||||||
|
doc.assertEqual(schedule.payment_amount, doc2.payment_schedule[index].payment_amount)
|
||||||
|
|
||||||
def make_sales_order(**args):
|
def make_sales_order(**args):
|
||||||
so = frappe.new_doc("Sales Order")
|
so = frappe.new_doc("Sales Order")
|
||||||
|
@ -503,6 +503,10 @@ def make_sales_invoice(source_name, target_doc=None):
|
|||||||
}
|
}
|
||||||
}, target_doc, set_missing_values)
|
}, target_doc, set_missing_values)
|
||||||
|
|
||||||
|
automatically_fetch_payment_terms = cint(frappe.db.get_single_value('Accounts Settings', 'automatically_fetch_payment_terms'))
|
||||||
|
if automatically_fetch_payment_terms:
|
||||||
|
doc.set_payment_schedule()
|
||||||
|
|
||||||
return doc
|
return doc
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
|
@ -17,7 +17,8 @@ from erpnext.stock.doctype.stock_entry.test_stock_entry \
|
|||||||
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos, SerialNoWarehouseError
|
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos, SerialNoWarehouseError
|
||||||
from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation \
|
from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation \
|
||||||
import create_stock_reconciliation, set_valuation_method
|
import create_stock_reconciliation, set_valuation_method
|
||||||
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order, create_dn_against_so
|
from erpnext.selling.doctype.sales_order.test_sales_order \
|
||||||
|
import make_sales_order, create_dn_against_so, automatically_fetch_payment_terms, compare_payment_schedules
|
||||||
from erpnext.accounts.doctype.account.test_account import get_inventory_account
|
from erpnext.accounts.doctype.account.test_account import get_inventory_account
|
||||||
from erpnext.stock.doctype.warehouse.test_warehouse import get_warehouse
|
from erpnext.stock.doctype.warehouse.test_warehouse import get_warehouse
|
||||||
from erpnext.stock.doctype.item.test_item import make_item
|
from erpnext.stock.doctype.item.test_item import make_item
|
||||||
@ -759,6 +760,32 @@ class TestDeliveryNote(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertTrue("TESTBATCH" in dn.packed_items[0].batch_no, "Batch number not added in packed item")
|
self.assertTrue("TESTBATCH" in dn.packed_items[0].batch_no, "Batch number not added in packed item")
|
||||||
|
|
||||||
|
def test_payment_terms_are_fetched_when_creating_sales_invoice(self):
|
||||||
|
from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_terms_template
|
||||||
|
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
||||||
|
|
||||||
|
automatically_fetch_payment_terms()
|
||||||
|
|
||||||
|
so = make_sales_order(uom="Nos", do_not_save=1)
|
||||||
|
create_payment_terms_template()
|
||||||
|
so.payment_terms_template = 'Test Receivable Template'
|
||||||
|
so.submit()
|
||||||
|
|
||||||
|
dn = create_dn_against_so(so.name, delivered_qty=10)
|
||||||
|
|
||||||
|
si = create_sales_invoice(qty=10, do_not_save=1)
|
||||||
|
si.items[0].delivery_note= dn.name
|
||||||
|
si.items[0].dn_detail = dn.items[0].name
|
||||||
|
si.items[0].sales_order = so.name
|
||||||
|
si.items[0].so_detail = so.items[0].name
|
||||||
|
|
||||||
|
si.insert()
|
||||||
|
si.submit()
|
||||||
|
|
||||||
|
self.assertEqual(so.payment_terms_template, si.payment_terms_template)
|
||||||
|
compare_payment_schedules(self, so, si)
|
||||||
|
|
||||||
|
automatically_fetch_payment_terms(enable=0)
|
||||||
|
|
||||||
def create_delivery_note(**args):
|
def create_delivery_note(**args):
|
||||||
dn = frappe.new_doc("Delivery Note")
|
dn = frappe.new_doc("Delivery Note")
|
||||||
|
@ -734,6 +734,7 @@ def make_purchase_invoice(source_name, target_doc=None):
|
|||||||
doc.run_method("onload")
|
doc.run_method("onload")
|
||||||
doc.run_method("set_missing_values")
|
doc.run_method("set_missing_values")
|
||||||
doc.run_method("calculate_taxes_and_totals")
|
doc.run_method("calculate_taxes_and_totals")
|
||||||
|
doc.set_payment_schedule()
|
||||||
|
|
||||||
def update_item(source_doc, target_doc, source_parent):
|
def update_item(source_doc, target_doc, source_parent):
|
||||||
target_doc.qty, returned_qty = get_pending_qty(source_doc)
|
target_doc.qty, returned_qty = get_pending_qty(source_doc)
|
||||||
|
@ -1065,6 +1065,33 @@ class TestPurchaseReceipt(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertEqual(discrepancy_caused_by_exchange_rate_diff, amount)
|
self.assertEqual(discrepancy_caused_by_exchange_rate_diff, amount)
|
||||||
|
|
||||||
|
def test_payment_terms_are_fetched_when_creating_purchase_invoice(self):
|
||||||
|
from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_terms_template
|
||||||
|
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
|
||||||
|
from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order, make_pr_against_po
|
||||||
|
from erpnext.selling.doctype.sales_order.test_sales_order import automatically_fetch_payment_terms, compare_payment_schedules
|
||||||
|
|
||||||
|
automatically_fetch_payment_terms()
|
||||||
|
|
||||||
|
po = create_purchase_order(qty=10, rate=100, do_not_save=1)
|
||||||
|
create_payment_terms_template()
|
||||||
|
po.payment_terms_template = 'Test Receivable Template'
|
||||||
|
po.submit()
|
||||||
|
|
||||||
|
pr = make_pr_against_po(po.name, received_qty=10)
|
||||||
|
|
||||||
|
pi = make_purchase_invoice(qty=10, rate=100, do_not_save=1)
|
||||||
|
pi.items[0].purchase_receipt = pr.name
|
||||||
|
pi.items[0].pr_detail = pr.items[0].name
|
||||||
|
pi.items[0].purchase_order = po.name
|
||||||
|
pi.items[0].po_detail = po.items[0].name
|
||||||
|
pi.insert()
|
||||||
|
|
||||||
|
# self.assertEqual(po.payment_terms_template, pi.payment_terms_template)
|
||||||
|
compare_payment_schedules(self, po, pi)
|
||||||
|
|
||||||
|
automatically_fetch_payment_terms(enable=0)
|
||||||
|
|
||||||
def get_sl_entries(voucher_type, voucher_no):
|
def get_sl_entries(voucher_type, voucher_no):
|
||||||
return frappe.db.sql(""" select actual_qty, warehouse, stock_value_difference
|
return frappe.db.sql(""" select actual_qty, warehouse, stock_value_difference
|
||||||
from `tabStock Ledger Entry` where voucher_type=%s and voucher_no=%s
|
from `tabStock Ledger Entry` where voucher_type=%s and voucher_no=%s
|
||||||
|
Loading…
x
Reference in New Issue
Block a user