Skip to content

Commit

Permalink
Merge pull request #33404 from frappe/version-14-hotfix
Browse files Browse the repository at this point in the history
chore: release v14
  • Loading branch information
deepeshgarg007 authored Dec 20, 2022
2 parents ac1af3b + 6ef7eaf commit c915663
Show file tree
Hide file tree
Showing 44 changed files with 511 additions and 186 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,10 @@ def set_default_accounts(company):
"default_payable_account": frappe.db.get_value(
"Account", {"company": company.name, "account_type": "Payable", "is_group": 0}
),
"default_provisional_account": frappe.db.get_value(
"Account",
{"company": company.name, "account_type": "Service Received But Not Billed", "is_group": 0},
),
}
)

Expand Down
4 changes: 3 additions & 1 deletion erpnext/accounts/doctype/payment_entry/payment_entry.json
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@
"fieldname": "source_exchange_rate",
"fieldtype": "Float",
"label": "Exchange Rate",
"precision": "9",
"print_hide": 1,
"reqd": 1
},
Expand Down Expand Up @@ -334,6 +335,7 @@
"fieldname": "target_exchange_rate",
"fieldtype": "Float",
"label": "Exchange Rate",
"precision": "9",
"print_hide": 1,
"reqd": 1
},
Expand Down Expand Up @@ -731,7 +733,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2022-02-23 20:08:39.559814",
"modified": "2022-12-08 16:25:43.824051",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Entry",
Expand Down
51 changes: 26 additions & 25 deletions erpnext/accounts/doctype/payment_entry/payment_entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -684,34 +684,33 @@ def clear_unallocated_reference_document_rows(self):
)

def validate_payment_against_negative_invoice(self):
if (self.payment_type == "Pay" and self.party_type == "Customer") or (
self.payment_type == "Receive" and self.party_type == "Supplier"
if (self.payment_type != "Pay" or self.party_type != "Customer") and (
self.payment_type != "Receive" or self.party_type != "Supplier"
):
return

total_negative_outstanding = sum(
abs(flt(d.outstanding_amount)) for d in self.get("references") if flt(d.outstanding_amount) < 0
)
total_negative_outstanding = sum(
abs(flt(d.outstanding_amount)) for d in self.get("references") if flt(d.outstanding_amount) < 0
)

paid_amount = self.paid_amount if self.payment_type == "Receive" else self.received_amount
additional_charges = sum([flt(d.amount) for d in self.deductions])
paid_amount = self.paid_amount if self.payment_type == "Receive" else self.received_amount
additional_charges = sum(flt(d.amount) for d in self.deductions)

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")),
self.party_type,
),
InvalidPaymentEntry,
)
if not total_negative_outstanding:
if self.party_type == "Customer":
msg = _("Cannot pay to Customer without any negative outstanding invoice")
else:
msg = _("Cannot receive from Supplier without any negative outstanding invoice")

elif paid_amount - additional_charges > total_negative_outstanding:
frappe.throw(
_("Paid Amount cannot be greater than total negative outstanding amount {0}").format(
total_negative_outstanding
),
InvalidPaymentEntry,
)
frappe.throw(msg, InvalidPaymentEntry)

elif paid_amount - additional_charges > 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 frappe.flags.in_import and self.title:
Expand Down Expand Up @@ -1188,6 +1187,7 @@ def get_outstanding_reference_documents(args):

ple = qb.DocType("Payment Ledger Entry")
common_filter = []
accounting_dimensions_filter = []
posting_and_due_date = []

# confirm that Supplier is not blocked
Expand Down Expand Up @@ -1217,7 +1217,7 @@ def get_outstanding_reference_documents(args):
# Add cost center condition
if args.get("cost_center"):
condition += " and cost_center='%s'" % args.get("cost_center")
common_filter.append(ple.cost_center == args.get("cost_center"))
accounting_dimensions_filter.append(ple.cost_center == args.get("cost_center"))

date_fields_dict = {
"posting_date": ["from_posting_date", "to_posting_date"],
Expand All @@ -1243,6 +1243,7 @@ def get_outstanding_reference_documents(args):
posting_date=posting_and_due_date,
min_outstanding=args.get("outstanding_amt_greater_than"),
max_outstanding=args.get("outstanding_amt_less_than"),
accounting_dimensions=accounting_dimensions_filter,
)

outstanding_invoices = split_invoices_based_on_payment_terms(outstanding_invoices)
Expand Down Expand Up @@ -1639,7 +1640,7 @@ def get_payment_entry(
):
reference_doc = None
doc = frappe.get_doc(dt, dn)
if dt in ("Sales Order", "Purchase Order") and flt(doc.per_billed, 2) > 0:
if dt in ("Sales Order", "Purchase Order") and flt(doc.per_billed, 2) >= 99.99:
frappe.throw(_("Can only make payment against unbilled {0}").format(dt))

if not party_type:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class PaymentReconciliation(Document):
def __init__(self, *args, **kwargs):
super(PaymentReconciliation, self).__init__(*args, **kwargs)
self.common_filter_conditions = []
self.accounting_dimension_filter_conditions = []
self.ple_posting_date_filter = []

@frappe.whitelist()
Expand Down Expand Up @@ -193,6 +194,7 @@ def get_invoice_entries(self):
posting_date=self.ple_posting_date_filter,
min_outstanding=self.minimum_invoice_amount if self.minimum_invoice_amount else None,
max_outstanding=self.maximum_invoice_amount if self.maximum_invoice_amount else None,
accounting_dimensions=self.accounting_dimension_filter_conditions,
)

if self.invoice_limit:
Expand Down Expand Up @@ -381,7 +383,7 @@ def build_qb_filter_conditions(self, get_invoices=False, get_return_invoices=Fal
self.common_filter_conditions.append(ple.company == self.company)

if self.get("cost_center") and (get_invoices or get_return_invoices):
self.common_filter_conditions.append(ple.cost_center == self.cost_center)
self.accounting_dimension_filter_conditions.append(ple.cost_center == self.cost_center)

if get_invoices:
if self.from_invoice_date:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
from frappe.tests.utils import FrappeTestCase
from frappe.utils import add_days, nowdate

from erpnext import get_default_cost_center
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_entry
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.accounts.party import get_party_account
Expand All @@ -20,6 +22,7 @@ def setUp(self):
self.create_item()
self.create_customer()
self.create_account()
self.create_cost_center()
self.clear_old_entries()

def tearDown(self):
Expand Down Expand Up @@ -216,6 +219,22 @@ def create_journal_entry(
)
return je

def create_cost_center(self):
# Setup cost center
cc_name = "Sub"

self.main_cc = frappe.get_doc("Cost Center", get_default_cost_center(self.company))

cc_exists = frappe.db.get_list("Cost Center", filters={"cost_center_name": cc_name})
if cc_exists:
self.sub_cc = frappe.get_doc("Cost Center", cc_exists[0].name)
else:
sub_cc = frappe.new_doc("Cost Center")
sub_cc.cost_center_name = "Sub"
sub_cc.parent_cost_center = self.main_cc.parent_cost_center
sub_cc.company = self.main_cc.company
self.sub_cc = sub_cc.save()

def test_filter_min_max(self):
# check filter condition minimum and maximum amount
self.create_sales_invoice(qty=1, rate=300)
Expand Down Expand Up @@ -578,3 +597,24 @@ def test_pr_output_foreign_currency_and_amount(self):
self.assertEqual(len(pr.payments), 1)
self.assertEqual(pr.payments[0].amount, amount)
self.assertEqual(pr.payments[0].currency, "EUR")

def test_differing_cost_center_on_invoice_and_payment(self):
"""
Cost Center filter should not affect outstanding amount calculation
"""

si = self.create_sales_invoice(qty=1, rate=100, do_not_submit=True)
si.cost_center = self.main_cc.name
si.submit()
pr = get_payment_entry(si.doctype, si.name)
pr.cost_center = self.sub_cc.name
pr = pr.save().submit()

pr = self.create_payment_reconciliation()
pr.cost_center = self.main_cc.name

pr.get_unreconciled_entries()

# check PR tool output
self.assertEqual(len(pr.get("invoices")), 0)
self.assertEqual(len(pr.get("payments")), 0)
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ frappe.ui.form.on("Payment Request", "refresh", function(frm) {
});
}

if(!frm.doc.payment_gateway_account && frm.doc.status == "Initiated") {
if((!frm.doc.payment_gateway_account || frm.doc.payment_request_type == "Outward") && frm.doc.status == "Initiated") {
frm.add_custom_button(__('Create Payment Entry'), function(){
frappe.call({
method: "erpnext.accounts.doctype.payment_request.payment_request.make_payment_entry",
Expand Down
28 changes: 13 additions & 15 deletions erpnext/accounts/doctype/payment_request/payment_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ def create_payment_entry(self, submit=True):

payment_entry.update(
{
"mode_of_payment": self.mode_of_payment,
"reference_no": self.name,
"reference_date": nowdate(),
"remarks": "Payment Entry against {0} {1} via Payment Request {2}".format(
Expand Down Expand Up @@ -403,25 +404,22 @@ def make_payment_request(**args):
else ""
)

existing_payment_request = None
if args.order_type == "Shopping Cart":
existing_payment_request = frappe.db.get_value(
"Payment Request",
{"reference_doctype": args.dt, "reference_name": args.dn, "docstatus": ("!=", 2)},
)
draft_payment_request = frappe.db.get_value(
"Payment Request",
{"reference_doctype": args.dt, "reference_name": args.dn, "docstatus": 0},
)

if existing_payment_request:
existing_payment_request_amount = get_existing_payment_request_amount(args.dt, args.dn)

if existing_payment_request_amount:
grand_total -= existing_payment_request_amount

if draft_payment_request:
frappe.db.set_value(
"Payment Request", existing_payment_request, "grand_total", grand_total, update_modified=False
"Payment Request", draft_payment_request, "grand_total", grand_total, update_modified=False
)
pr = frappe.get_doc("Payment Request", existing_payment_request)
pr = frappe.get_doc("Payment Request", draft_payment_request)
else:
if args.order_type != "Shopping Cart":
existing_payment_request_amount = get_existing_payment_request_amount(args.dt, args.dn)

if existing_payment_request_amount:
grand_total -= existing_payment_request_amount

pr = frappe.new_doc("Payment Request")
pr.update(
{
Expand Down
15 changes: 11 additions & 4 deletions erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,13 @@
"tax_withholding_net_total",
"base_tax_withholding_net_total",
"taxes_section",
"tax_category",
"taxes_and_charges",
"column_break_58",
"tax_category",
"column_break_49",
"shipping_rule",
"column_break_49",
"incoterm",
"named_place",
"section_break_51",
"taxes",
"totals",
Expand Down Expand Up @@ -1541,13 +1542,19 @@
"fieldtype": "Link",
"label": "Incoterm",
"options": "Incoterm"
},
{
"depends_on": "incoterm",
"fieldname": "named_place",
"fieldtype": "Data",
"label": "Named Place"
}
],
"icon": "fa fa-file-text",
"idx": 204,
"is_submittable": 1,
"links": [],
"modified": "2022-11-27 16:28:45.559785",
"modified": "2022-12-14 18:37:38.142688",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",
Expand Down Expand Up @@ -1611,4 +1618,4 @@
"timeline_field": "supplier",
"title_field": "title",
"track_changes": 1
}
}
13 changes: 10 additions & 3 deletions erpnext/accounts/doctype/sales_invoice/sales_invoice.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,13 @@
"total",
"net_total",
"taxes_section",
"tax_category",
"taxes_and_charges",
"column_break_38",
"shipping_rule",
"incoterm",
"column_break_55",
"tax_category",
"incoterm",
"named_place",
"section_break_40",
"taxes",
"section_break_43",
Expand Down Expand Up @@ -2105,6 +2106,12 @@
"fieldtype": "Link",
"label": "Incoterm",
"options": "Incoterm"
},
{
"depends_on": "incoterm",
"fieldname": "named_place",
"fieldtype": "Data",
"label": "Named Place"
}
],
"icon": "fa fa-file-text",
Expand All @@ -2117,7 +2124,7 @@
"link_fieldname": "consolidated_invoice"
}
],
"modified": "2022-12-05 16:18:14.532114",
"modified": "2022-12-12 18:34:33.409895",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,24 @@ def get_party_tax_withholding_details(inv, tax_withholding_category=None):
else:
tax_row = get_tax_row_for_tcs(inv, tax_details, tax_amount, tax_deducted)

cost_center = get_cost_center(inv)
tax_row.update({"cost_center": cost_center})

if inv.doctype == "Purchase Invoice":
return tax_row, tax_deducted_on_advances, voucher_wise_amount
else:
return tax_row


def get_cost_center(inv):
cost_center = frappe.get_cached_value("Company", inv.company, "cost_center")

if len(inv.get("taxes", [])) > 0:
cost_center = inv.get("taxes")[0].cost_center

return cost_center


def get_tax_withholding_details(tax_withholding_category, posting_date, company):
tax_withholding = frappe.get_doc("Tax Withholding Category", tax_withholding_category)

Expand Down
Loading

0 comments on commit c915663

Please sign in to comment.