chore: merge upstream
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index d6455b2..957611f 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -3,6 +3,8 @@
frappe.provide("erpnext.accounts");
+cur_frm.cscript.tax_table = "Purchase Taxes and Charges";
+
erpnext.accounts.payment_triggers.setup("Purchase Invoice");
erpnext.accounts.taxes.setup_tax_filters("Purchase Taxes and Charges");
erpnext.accounts.taxes.setup_tax_validations("Purchase Invoice");
diff --git a/erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template.js b/erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template.js
index 66a9cbe..4c94503 100644
--- a/erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template.js
+++ b/erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template.js
@@ -1,6 +1,7 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
+cur_frm.cscript.tax_table = "Purchase Taxes and Charges";
erpnext.accounts.taxes.setup_tax_validations("Purchase Taxes and Charges Template");
erpnext.accounts.taxes.setup_tax_filters("Purchase Taxes and Charges");
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 17101cd..c7505ce 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -3,6 +3,8 @@
frappe.provide("erpnext.accounts");
+cur_frm.cscript.tax_table = "Sales Taxes and Charges";
+
erpnext.accounts.taxes.setup_tax_validations("Sales Invoice");
erpnext.accounts.payment_triggers.setup("Sales Invoice");
erpnext.accounts.pos.setup("Sales Invoice");
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index c8a35eb..85e9d16 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -1588,6 +1588,12 @@
self.assertEqual(frappe.db.get_value("Sales Invoice", si1.name, "outstanding_amount"), -1000)
self.assertEqual(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"), 2500)
+ def test_zero_qty_return_invoice_with_stock_effect(self):
+ cr_note = create_sales_invoice(qty=-1, rate=300, is_return=1, do_not_submit=True)
+ cr_note.update_stock = True
+ cr_note.items[0].qty = 0
+ self.assertRaises(frappe.ValidationError, cr_note.save)
+
def test_return_invoice_with_account_mismatch(self):
debtors2 = create_account(
parent_account="Accounts Receivable - _TC",
diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.js b/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.js
index 91d4d04..c42623a 100644
--- a/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.js
+++ b/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.js
@@ -1,5 +1,6 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
+cur_frm.cscript.tax_table = "Sales Taxes and Charges";
erpnext.accounts.taxes.setup_tax_validations("Sales Taxes and Charges Template");
erpnext.accounts.taxes.setup_tax_filters("Sales Taxes and Charges");
diff --git a/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py
index a0f8af5..de49139 100644
--- a/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py
@@ -182,8 +182,10 @@
}
# check invoice grand total and invoiced column's value for 3 payment terms
- si = self.create_sales_invoice(no_payment_schedule=True)
- name = si.name
+ si = self.create_sales_invoice(no_payment_schedule=True, do_not_submit=True)
+ si.set_posting_time = True
+ si.posting_date = add_days(today(), -1)
+ si.save().submit()
report = execute(filters)
@@ -207,30 +209,42 @@
# check invoice grand total, invoiced, paid and outstanding column's value after credit note
cr_note = self.create_credit_note(si.name, do_not_submit=True)
- cr_note.posting_date = add_days(today(), 1)
cr_note.update_outstanding_for_self = True
cr_note.save().submit()
report = execute(filters)
expected_data_after_credit_note = [
- [100.0, 100.0, 40.0, 0.0, 60.0, self.debit_to],
- [0, 0, 100.0, 0.0, -100.0, self.debit_to],
+ [100.0, 100.0, 40.0, 0.0, 60.0, si.name],
+ [0, 0, 100.0, 0.0, -100.0, cr_note.name],
]
self.assertEqual(len(report[1]), 2)
- for i in range(2):
- row = report[1][i - 1]
- # row = report[1][0]
- self.assertEqual(
- expected_data_after_credit_note[i - 1],
- [
- row.invoice_grand_total,
- row.invoiced,
- row.paid,
- row.credit_note,
- row.outstanding,
- row.party_account,
- ],
- )
+ si_row = [
+ [
+ row.invoice_grand_total,
+ row.invoiced,
+ row.paid,
+ row.credit_note,
+ row.outstanding,
+ row.voucher_no,
+ ]
+ for row in report[1]
+ if row.voucher_no == si.name
+ ][0]
+
+ cr_note_row = [
+ [
+ row.invoice_grand_total,
+ row.invoiced,
+ row.paid,
+ row.credit_note,
+ row.outstanding,
+ row.voucher_no,
+ ]
+ for row in report[1]
+ if row.voucher_no == cr_note.name
+ ][0]
+ self.assertEqual(expected_data_after_credit_note[0], si_row)
+ self.assertEqual(expected_data_after_credit_note[1], cr_note_row)
def test_payment_againt_po_in_receivable_report(self):
"""
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 166e8c4..385797f 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -152,6 +152,7 @@
def on_submit(self):
self.validate_in_use_date()
self.make_asset_movement()
+ self.reload()
if not self.booked_fixed_asset and self.validate_make_gl_entry():
self.make_gl_entries()
if self.calculate_depreciation and not self.split_from:
@@ -163,6 +164,7 @@
self.validate_cancellation()
self.cancel_movement_entries()
self.cancel_capitalization()
+ self.reload()
self.delete_depreciation_entries()
cancel_asset_depr_schedules(self)
self.set_status()
@@ -698,7 +700,9 @@
fixed_asset_account, cwip_account = self.get_fixed_asset_account(), self.get_cwip_account()
if (
- purchase_document and self.purchase_receipt_amount and self.available_for_use_date <= nowdate()
+ purchase_document
+ and self.purchase_receipt_amount
+ and getdate(self.available_for_use_date) <= getdate()
):
gl_entries.append(
diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py
index 191675c..205f4b9 100644
--- a/erpnext/assets/doctype/asset/depreciation.py
+++ b/erpnext/assets/doctype/asset/depreciation.py
@@ -242,9 +242,7 @@
debit_account,
accounting_dimensions,
)
- frappe.db.commit()
except Exception as e:
- frappe.db.rollback()
depreciation_posting_error = e
asset.set_status()
@@ -523,6 +521,7 @@
make_depreciation_entry_for_all_asset_depr_schedules(asset_doc, date)
+ asset_doc.reload()
cancel_depreciation_entries(asset_doc, date)
diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py
index 77469df..6e16508 100644
--- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py
+++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py
@@ -327,7 +327,7 @@
schedule_date = get_last_day(schedule_date)
# if asset is being sold or scrapped
- if date_of_disposal:
+ if date_of_disposal and getdate(schedule_date) >= getdate(date_of_disposal):
from_date = add_months(
getdate(asset_doc.available_for_use_date),
(asset_doc.number_of_depreciations_booked * row.frequency_of_depreciation),
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js
index 7875646..2bb602c 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.js
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.js
@@ -4,6 +4,8 @@
frappe.provide("erpnext.buying");
frappe.provide("erpnext.accounts.dimensions");
+cur_frm.cscript.tax_table = "Purchase Taxes and Charges";
+
erpnext.accounts.taxes.setup_tax_filters("Purchase Taxes and Charges");
erpnext.accounts.taxes.setup_tax_validations("Purchase Order");
erpnext.buying.setup_buying_controller();
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 250f21b..77a5ed4 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -89,6 +89,7 @@
"weight_per_unit",
"weight_uom",
"total_weight",
+ "valuation_rate",
)
@@ -168,6 +169,13 @@
if not self.get("is_return") and not self.get("is_debit_note"):
self.validate_qty_is_not_zero()
+ if (
+ self.doctype in ["Sales Invoice", "Purchase Invoice"]
+ and self.get("is_return")
+ and self.get("update_stock")
+ ):
+ self.validate_zero_qty_for_return_invoices_with_stock()
+
if self.get("_action") and self._action != "update_after_submit":
self.set_missing_values(for_validate=True)
@@ -1044,6 +1052,18 @@
else:
return flt(args.get(field, 0) / self.get("conversion_rate", 1))
+ def validate_zero_qty_for_return_invoices_with_stock(self):
+ rows = []
+ for item in self.items:
+ if not flt(item.qty):
+ rows.append(item)
+ if rows:
+ frappe.throw(
+ _(
+ "For Return Invoices with Stock effect, '0' qty Items are not allowed. Following rows are affected: {0}"
+ ).format(frappe.bold(comma_and(["#" + str(x.idx) for x in rows])))
+ )
+
def validate_qty_is_not_zero(self):
for item in self.items:
if self.doctype == "Purchase Receipt" and item.rejected_qty:
@@ -2708,14 +2728,20 @@
else:
q = q.where(journal_acc.debit_in_account_currency > 0)
+ reference_or_condition = []
+
if include_unallocated:
- q = q.where((journal_acc.reference_name.isnull()) | (journal_acc.reference_name == ""))
+ reference_or_condition.append(journal_acc.reference_name.isnull())
+ reference_or_condition.append(journal_acc.reference_name == "")
if order_list:
- q = q.where(
+ reference_or_condition.append(
(journal_acc.reference_type == order_doctype) & ((journal_acc.reference_name).isin(order_list))
)
+ if reference_or_condition:
+ q = q.where(Criterion.any(reference_or_condition))
+
q = q.orderby(journal_entry.posting_date)
journal_entries = q.run(as_dict=True)
diff --git a/erpnext/selling/doctype/quotation/quotation.js b/erpnext/selling/doctype/quotation/quotation.js
index 6e2b726..95cbfd0 100644
--- a/erpnext/selling/doctype/quotation/quotation.js
+++ b/erpnext/selling/doctype/quotation/quotation.js
@@ -1,6 +1,8 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
+cur_frm.cscript.tax_table = "Sales Taxes and Charges";
+
erpnext.accounts.taxes.setup_tax_validations("Sales Taxes and Charges Template");
erpnext.accounts.taxes.setup_tax_filters("Sales Taxes and Charges");
erpnext.pre_sales.set_as_lost("Quotation");
diff --git a/erpnext/selling/doctype/quotation/test_quotation.py b/erpnext/selling/doctype/quotation/test_quotation.py
index 0b0d6e7..a525942 100644
--- a/erpnext/selling/doctype/quotation/test_quotation.py
+++ b/erpnext/selling/doctype/quotation/test_quotation.py
@@ -42,6 +42,39 @@
self.assertTrue(sales_order.get("payment_schedule"))
+ def test_gross_profit(self):
+ from erpnext.stock.doctype.item.test_item import make_item
+ from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
+ from erpnext.stock.get_item_details import insert_item_price
+
+ item_doc = make_item("_Test Item for Gross Profit", {"is_stock_item": 1})
+ item_code = item_doc.name
+ make_stock_entry(item_code=item_code, qty=10, rate=100, target="_Test Warehouse - _TC")
+
+ selling_price_list = frappe.get_all("Price List", filters={"selling": 1}, limit=1)[0].name
+ frappe.db.set_single_value("Stock Settings", "auto_insert_price_list_rate_if_missing", 1)
+ insert_item_price(
+ frappe._dict(
+ {
+ "item_code": item_code,
+ "price_list": selling_price_list,
+ "price_list_rate": 300,
+ "rate": 300,
+ "conversion_factor": 1,
+ "discount_amount": 0.0,
+ "currency": frappe.db.get_value("Price List", selling_price_list, "currency"),
+ "uom": item_doc.stock_uom,
+ }
+ )
+ )
+
+ quotation = make_quotation(
+ item_code=item_code, qty=1, rate=300, selling_price_list=selling_price_list
+ )
+ self.assertEqual(quotation.items[0].valuation_rate, 100)
+ self.assertEqual(quotation.items[0].gross_profit, 200)
+ frappe.db.set_single_value("Stock Settings", "auto_insert_price_list_rate_if_missing", 0)
+
def test_maintain_rate_in_sales_cycle_is_enforced(self):
from erpnext.selling.doctype.quotation.quotation import make_sales_order
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index 28f6edf..715d4d1 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -1,6 +1,8 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
+cur_frm.cscript.tax_table = "Sales Taxes and Charges";
+
erpnext.accounts.taxes.setup_tax_filters("Sales Taxes and Charges");
erpnext.accounts.taxes.setup_tax_validations("Sales Order");
erpnext.sales_common.setup_selling_controller();
diff --git a/erpnext/stock/doctype/closing_stock_balance/closing_stock_balance.py b/erpnext/stock/doctype/closing_stock_balance/closing_stock_balance.py
index 1c70183..e99a0b1 100644
--- a/erpnext/stock/doctype/closing_stock_balance/closing_stock_balance.py
+++ b/erpnext/stock/doctype/closing_stock_balance/closing_stock_balance.py
@@ -123,7 +123,9 @@
)
)
- create_json_gz_file({"columns": columns, "data": data}, self.doctype, self.name)
+ create_json_gz_file(
+ {"columns": columns, "data": data}, self.doctype, self.name, "closing-stock-balance"
+ )
def get_prepared_data(self):
if attachments := get_attachments(self.doctype, self.name):
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.js b/erpnext/stock/doctype/delivery_note/delivery_note.js
index c04d5c1..23d0adc 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.js
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.js
@@ -3,6 +3,8 @@
cur_frm.add_fetch("customer", "tax_id", "tax_id");
+cur_frm.cscript.tax_table = "Sales Taxes and Charges";
+
frappe.provide("erpnext.stock");
frappe.provide("erpnext.stock.delivery_note");
frappe.provide("erpnext.accounts.dimensions");
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
index 997cdd0..bfac438 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
@@ -3,6 +3,8 @@
frappe.provide("erpnext.stock");
+cur_frm.cscript.tax_table = "Purchase Taxes and Charges";
+
erpnext.accounts.taxes.setup_tax_filters("Purchase Taxes and Charges");
erpnext.accounts.taxes.setup_tax_validations("Purchase Receipt");
erpnext.buying.setup_buying_controller();
diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json
index 3a094f1..e8e82af 100644
--- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json
+++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json
@@ -230,7 +230,7 @@
},
{
"fieldname": "stock_queue",
- "fieldtype": "Text",
+ "fieldtype": "Long Text",
"label": "FIFO Stock Queue (qty, rate)",
"oldfieldname": "fcfs_stack",
"oldfieldtype": "Text",
@@ -360,7 +360,7 @@
"in_create": 1,
"index_web_pages_for_search": 1,
"links": [],
- "modified": "2024-02-07 09:18:13.999231",
+ "modified": "2024-03-13 09:56:13.021696",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Ledger Entry",
diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
index a3e51ca..b49fe22 100644
--- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
+++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
@@ -58,7 +58,7 @@
recalculate_rate: DF.Check
serial_and_batch_bundle: DF.Link | None
serial_no: DF.LongText | None
- stock_queue: DF.Text | None
+ stock_queue: DF.LongText | None
stock_uom: DF.Link | None
stock_value: DF.Currency
stock_value_difference: DF.Currency