Skip to content

Commit

Permalink
Merge pull request #43467 from frappe/version-15-hotfix
Browse files Browse the repository at this point in the history
chore: release v15
  • Loading branch information
ruthra-kumar authored Oct 4, 2024
2 parents 01f9139 + 4fa5131 commit 5a9522e
Show file tree
Hide file tree
Showing 33 changed files with 658 additions and 211 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def get_api_endpoint(service_provider: str | None = None, use_http: bool = False
if service_provider == "exchangerate.host":
api = "api.exchangerate.host/convert"
elif service_provider == "frankfurter.app":
api = "frankfurter.app/{transaction_date}"
api = "api.frankfurter.app/{transaction_date}"

protocol = "https://"
if use_http:
Expand Down
38 changes: 25 additions & 13 deletions erpnext/accounts/doctype/dunning/dunning.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,19 +210,31 @@ def get_linked_dunnings_as_per_state(sales_invoice, state):


@frappe.whitelist()
def get_dunning_letter_text(dunning_type, doc, language=None):
def get_dunning_letter_text(dunning_type: str, doc: str | dict, language: str | None = None) -> dict:
DOCTYPE = "Dunning Letter Text"
FIELDS = ["body_text", "closing_text", "language"]

if isinstance(doc, str):
doc = json.loads(doc)

if not language:
language = doc.get("language")

if language:
filters = {"parent": dunning_type, "language": language}
else:
filters = {"parent": dunning_type, "is_default_language": 1}
letter_text = frappe.db.get_value(
"Dunning Letter Text", filters, ["body_text", "closing_text", "language"], as_dict=1
)
if letter_text:
return {
"body_text": frappe.render_template(letter_text.body_text, doc),
"closing_text": frappe.render_template(letter_text.closing_text, doc),
"language": letter_text.language,
}
letter_text = frappe.db.get_value(
DOCTYPE, {"parent": dunning_type, "language": language}, FIELDS, as_dict=1
)

if not letter_text:
letter_text = frappe.db.get_value(
DOCTYPE, {"parent": dunning_type, "is_default_language": 1}, FIELDS, as_dict=1
)

if not letter_text:
return {}

return {
"body_text": frappe.render_template(letter_text.body_text, doc),
"closing_text": frappe.render_template(letter_text.closing_text, doc),
"language": letter_text.language,
}
18 changes: 18 additions & 0 deletions erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
Original file line number Diff line number Diff line change
Expand Up @@ -2292,6 +2292,24 @@ def test_adjust_incoming_rate_from_pi_with_multi_currency(self):

frappe.db.set_single_value("Buying Settings", "maintain_same_rate", 1)

def test_last_purchase_rate(self):
item = create_item("_Test Item For Last Purchase Rate from PI", is_stock_item=1)
pi1 = make_purchase_invoice(item_code=item.item_code, qty=10, rate=100)
item.reload()
self.assertEqual(item.last_purchase_rate, 100)

pi2 = make_purchase_invoice(item_code=item.item_code, qty=10, rate=200)
item.reload()
self.assertEqual(item.last_purchase_rate, 200)

pi2.cancel()
item.reload()
self.assertEqual(item.last_purchase_rate, 100)

pi1.cancel()
item.reload()
self.assertEqual(item.last_purchase_rate, 0)


def set_advance_flag(company, flag, default_account):
frappe.db.set_value(
Expand Down
23 changes: 9 additions & 14 deletions erpnext/controllers/accounts_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -3309,7 +3309,6 @@ def validate_fg_item_for_subcontracting(new_data, is_new):
items_added_or_removed = False # updated to true if any new item is added or removed
any_conversion_factor_changed = False

sales_doctypes = ["Sales Order", "Sales Invoice", "Delivery Note", "Quotation"]
parent = frappe.get_doc(parent_doctype, parent_doctype_name)

check_doc_permissions(parent, "write")
Expand Down Expand Up @@ -3425,25 +3424,21 @@ def validate_fg_item_for_subcontracting(new_data, is_new):
# if rate is greater than price_list_rate, set margin
# or set discount
child_item.discount_percentage = 0

if parent_doctype in sales_doctypes:
child_item.margin_type = "Amount"
child_item.margin_rate_or_amount = flt(
child_item.rate - child_item.price_list_rate,
child_item.precision("margin_rate_or_amount"),
)
child_item.rate_with_margin = child_item.rate
child_item.margin_type = "Amount"
child_item.margin_rate_or_amount = flt(
child_item.rate - child_item.price_list_rate,
child_item.precision("margin_rate_or_amount"),
)
child_item.rate_with_margin = child_item.rate
else:
child_item.discount_percentage = flt(
(1 - flt(child_item.rate) / flt(child_item.price_list_rate)) * 100.0,
child_item.precision("discount_percentage"),
)
child_item.discount_amount = flt(child_item.price_list_rate) - flt(child_item.rate)

if parent_doctype in sales_doctypes:
child_item.margin_type = ""
child_item.margin_rate_or_amount = 0
child_item.rate_with_margin = 0
child_item.margin_type = ""
child_item.margin_rate_or_amount = 0
child_item.rate_with_margin = 0

child_item.flags.ignore_validate_update_after_submit = True
if new_child_flag:
Expand Down
8 changes: 5 additions & 3 deletions erpnext/controllers/buying_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -702,9 +702,11 @@ def on_cancel(self):
if self.get("is_return"):
return

if self.doctype in ["Purchase Order", "Purchase Receipt"] and not frappe.db.get_single_value(
"Buying Settings", "disable_last_purchase_rate"
):
if self.doctype in [
"Purchase Order",
"Purchase Receipt",
"Purchase Invoice",
] and not frappe.db.get_single_value("Buying Settings", "disable_last_purchase_rate"):
update_last_purchase_rate(self, is_submit=0)

if self.doctype in ["Purchase Receipt", "Purchase Invoice"]:
Expand Down
12 changes: 12 additions & 0 deletions erpnext/controllers/stock_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,18 @@ def validate(self):
self.validate_internal_transfer()
self.validate_putaway_capacity()

def validate_items_exist(self):
if not self.get("items"):
return

items = [d.item_code for d in self.get("items")]

exists_items = frappe.get_all("Item", filters={"name": ("in", items)}, pluck="name")
non_exists_items = set(items) - set(exists_items)

if non_exists_items:
frappe.throw(_("Items {0} do not exist in the Item master.").format(", ".join(non_exists_items)))

def validate_duplicate_serial_and_batch_bundle(self, table_name):
if not self.get(table_name):
return
Expand Down
8 changes: 4 additions & 4 deletions erpnext/controllers/taxes_and_totals.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def filter_rows(self):
return items

def calculate(self):
if not len(self._items):
if not len(self.doc.items):
return

self.discount_amount_applied = False
Expand Down Expand Up @@ -95,7 +95,7 @@ def validate_item_tax_template(self):
if self.doc.get("is_return") and self.doc.get("return_against"):
return

for item in self._items:
for item in self.doc.items:
if item.item_code and item.get("item_tax_template"):
item_doc = frappe.get_cached_doc("Item", item.item_code)
args = {
Expand Down Expand Up @@ -154,7 +154,7 @@ def calculate_item_values(self):
return

if not self.discount_amount_applied:
for item in self._items:
for item in self.doc.items:
self.doc.round_floats_in(item)

if item.discount_percentage == 100:
Expand Down Expand Up @@ -258,7 +258,7 @@ def determine_exclusive_rate(self):
if not any(cint(tax.included_in_print_rate) for tax in self.doc.get("taxes")):
return

for item in self._items:
for item in self.doc.items:
item_tax_map = self._load_item_tax_rate(item.item_tax_rate)
cumulated_tax_fraction = 0
total_inclusive_tax_amount_per_qty = 0
Expand Down
Loading

0 comments on commit 5a9522e

Please sign in to comment.