chore: merge upstream

This commit is contained in:
Gursheen Anand
2024-03-15 12:08:33 +05:30
19 changed files with 129 additions and 29 deletions

View File

@@ -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");

View File

@@ -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");

View File

@@ -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");

View File

@@ -1588,6 +1588,12 @@ class TestSalesInvoice(FrappeTestCase):
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",

View File

@@ -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");

View File

@@ -182,8 +182,10 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
}
# 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 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
# 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):
"""

View File

@@ -152,6 +152,7 @@ class Asset(AccountsController):
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 @@ class Asset(AccountsController):
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 @@ class Asset(AccountsController):
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(

View File

@@ -242,9 +242,7 @@ def make_depreciation_entry(
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 @@ def depreciate_asset(asset_doc, date, notes):
make_depreciation_entry_for_all_asset_depr_schedules(asset_doc, date)
asset_doc.reload()
cancel_depreciation_entries(asset_doc, date)

View File

@@ -327,7 +327,7 @@ class AssetDepreciationSchedule(Document):
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),

View File

@@ -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();

View File

@@ -89,6 +89,7 @@ force_item_fields = (
"weight_per_unit",
"weight_uom",
"total_weight",
"valuation_rate",
)
@@ -168,6 +169,13 @@ class AccountsController(TransactionBase):
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 @@ class AccountsController(TransactionBase):
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 @@ def get_advance_journal_entries(
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)

View File

@@ -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");

View File

@@ -42,6 +42,39 @@ class TestQuotation(FrappeTestCase):
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

View File

@@ -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();

View File

@@ -123,7 +123,9 @@ class ClosingStockBalance(Document):
)
)
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):

View File

@@ -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");

View File

@@ -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();

View File

@@ -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",

View File

@@ -58,7 +58,7 @@ class StockLedgerEntry(Document):
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