diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js index 969027dd97c..cc72c313238 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.js +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js @@ -905,7 +905,7 @@ frappe.ui.form.on('Payment Entry', { function(d) { return flt(d.amount) })); frm.set_value("difference_amount", difference_amount - total_deductions + - frm.doc.base_total_taxes_and_charges); + flt(frm.doc.base_total_taxes_and_charges)); frm.events.hide_unhide_fields(frm); }, diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py index ad3477ef3d3..1f2d9803739 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py +++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py @@ -302,7 +302,7 @@ def get_invoice_vouchers(parties, tax_details, company, party_type="Supplier"): "docstatus": 1, } - if not tax_details.get("consider_party_ledger_amount") and doctype != "Sales Invoice": + if doctype != "Sales Invoice": filters.update( {"apply_tds": 1, "tax_withholding_category": tax_details.get("tax_withholding_category")} ) diff --git a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py index 1e86cf5d2ef..bc4f6709fca 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py +++ b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py @@ -110,9 +110,9 @@ class TestTaxWithholdingCategory(unittest.TestCase): invoices.append(pi1) # Cumulative threshold is 30000 - # Threshold calculation should be on both the invoices - # TDS should be applied only on 1000 - self.assertEqual(pi1.taxes[0].tax_amount, 1000) + # Threshold calculation should be only on the Second invoice + # Second didn't breach, no TDS should be applied + self.assertEqual(pi1.taxes, []) for d in reversed(invoices): d.cancel() diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index fe1fd98aa09..39e65a7b97b 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -425,7 +425,7 @@ class Asset(AccountsController): depreciation_amount += value_after_depreciation - finance_book.expected_value_after_useful_life skip_row = True - if depreciation_amount > 0: + if flt(depreciation_amount, self.precision("gross_purchase_amount")) > 0: self._add_depreciation_row( schedule_date, depreciation_amount, @@ -1287,9 +1287,11 @@ def get_straight_line_or_manual_depr_amount(asset, row): ) # if the Depreciation Schedule is being prepared for the first time else: - return (flt(asset.gross_purchase_amount) - flt(row.expected_value_after_useful_life)) / flt( - row.total_number_of_depreciations - ) + return ( + flt(asset.gross_purchase_amount) + - flt(asset.opening_accumulated_depreciation) + - flt(row.expected_value_after_useful_life) + ) / flt(row.total_number_of_depreciations - asset.number_of_depreciations_booked) def get_wdv_or_dd_depr_amount( diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py index 8a1df6f71ce..1968154383d 100644 --- a/erpnext/assets/doctype/asset/test_asset.py +++ b/erpnext/assets/doctype/asset/test_asset.py @@ -649,7 +649,7 @@ class TestDepreciationMethods(AssetSetup): ) self.assertEqual(asset.status, "Draft") - expected_schedules = [["2032-12-31", 30000.0, 77095.89], ["2033-06-06", 12904.11, 90000.0]] + expected_schedules = [["2032-12-31", 42904.11, 90000.0]] schedules = [ [cstr(d.schedule_date), flt(d.depreciation_amount, 2), d.accumulated_depreciation_amount] for d in asset.get("schedules") diff --git a/erpnext/controllers/subcontracting_controller.py b/erpnext/controllers/subcontracting_controller.py index c3fa894e895..1e9c4dc8478 100644 --- a/erpnext/controllers/subcontracting_controller.py +++ b/erpnext/controllers/subcontracting_controller.py @@ -689,7 +689,6 @@ class SubcontractingController(StockController): "actual_qty": flt(item.rejected_qty) * flt(item.conversion_factor), "serial_no": cstr(item.rejected_serial_no).strip(), "incoming_rate": 0.0, - "recalculate_rate": 1, }, ) ) diff --git a/erpnext/patches/v13_0/update_amt_in_work_order_required_items.py b/erpnext/patches/v13_0/update_amt_in_work_order_required_items.py index e37f291233e..64170edb718 100644 --- a/erpnext/patches/v13_0/update_amt_in_work_order_required_items.py +++ b/erpnext/patches/v13_0/update_amt_in_work_order_required_items.py @@ -7,4 +7,6 @@ def execute(): frappe.reload_doc("manufacturing", "doctype", "work_order") frappe.reload_doc("manufacturing", "doctype", "work_order_item") - frappe.db.sql("""UPDATE `tabWork Order Item` SET amount = rate * required_qty""") + frappe.db.sql( + """UPDATE `tabWork Order Item` SET amount = ifnull(rate, 0.0) * ifnull(required_qty, 0.0)""" + ) diff --git a/erpnext/public/js/controllers/accounts.js b/erpnext/public/js/controllers/accounts.js index d943126018a..47b88a002bc 100644 --- a/erpnext/public/js/controllers/accounts.js +++ b/erpnext/public/js/controllers/accounts.js @@ -91,6 +91,12 @@ frappe.ui.form.on("Sales Invoice", { }); frappe.ui.form.on('Purchase Invoice', { + setup: (frm) => { + frm.make_methods = { + 'Landed Cost Voucher': function () { frm.trigger('create_landedcost_voucher') }, + } + }, + mode_of_payment: function(frm) { get_payment_mode_account(frm, frm.doc.mode_of_payment, function(account){ frm.set_value('cash_bank_account', account); @@ -99,6 +105,20 @@ frappe.ui.form.on('Purchase Invoice', { payment_terms_template: function() { cur_frm.trigger("disable_due_date"); + }, + + create_landedcost_voucher: function (frm) { + let lcv = frappe.model.get_new_doc('Landed Cost Voucher'); + lcv.company = frm.doc.company; + + let lcv_receipt = frappe.model.get_new_doc('Landed Cost Purchase Invoice'); + lcv_receipt.receipt_document_type = 'Purchase Invoice'; + lcv_receipt.receipt_document = frm.doc.name; + lcv_receipt.supplier = frm.doc.supplier; + lcv_receipt.grand_total = frm.doc.grand_total; + lcv.purchase_receipts = [lcv_receipt]; + + frappe.set_route("Form", lcv.doctype, lcv.name); } }); diff --git a/erpnext/selling/doctype/quotation/quotation.py b/erpnext/selling/doctype/quotation/quotation.py index 693fc92ce93..61969fe8a91 100644 --- a/erpnext/selling/doctype/quotation/quotation.py +++ b/erpnext/selling/doctype/quotation/quotation.py @@ -288,7 +288,7 @@ def _make_sales_order(source_name, target_doc=None, ignore_permissions=False): ) # sales team - for d in customer.get("sales_team"): + for d in customer.get("sales_team") or []: target.append( "sales_team", { diff --git a/erpnext/setup/module_onboarding/home/home.json b/erpnext/setup/module_onboarding/home/home.json index 516f12229c5..1fd96796cb2 100644 --- a/erpnext/setup/module_onboarding/home/home.json +++ b/erpnext/setup/module_onboarding/home/home.json @@ -25,15 +25,12 @@ "documentation_url": "https://docs.erpnext.com/docs/v14/user/manual/en/setting-up/company-setup", "idx": 0, "is_complete": 0, - "modified": "2023-05-16 13:13:24.043792", + "modified": "2023-05-20 19:45:03.936741", "modified_by": "Administrator", "module": "Setup", "name": "Home", "owner": "Administrator", "steps": [ - { - "step": "Navigation Help" - }, { "step": "Create an Item" }, @@ -47,7 +44,7 @@ "step": "Create a Quotation" } ], - "subtitle": "Item, Customer, Supplier, Navigation Help and Quotation", + "subtitle": "Item, Customer, Supplier and Quotation", "success_message": "You're ready to start your journey with ERPNext", "title": "Let's begin your journey with ERPNext" } \ No newline at end of file diff --git a/erpnext/setup/onboarding_step/create_a_customer/create_a_customer.json b/erpnext/setup/onboarding_step/create_a_customer/create_a_customer.json index e1a8f908663..5b0fd419c25 100644 --- a/erpnext/setup/onboarding_step/create_a_customer/create_a_customer.json +++ b/erpnext/setup/onboarding_step/create_a_customer/create_a_customer.json @@ -9,7 +9,7 @@ "is_complete": 0, "is_single": 0, "is_skipped": 0, - "modified": "2023-05-16 12:54:54.112364", + "modified": "2023-05-16 20:01:34.202622", "modified_by": "Administrator", "name": "Create a Customer", "owner": "Administrator", diff --git a/erpnext/setup/onboarding_step/create_a_supplier/create_a_supplier.json b/erpnext/setup/onboarding_step/create_a_supplier/create_a_supplier.json index ef493fe00d1..4ac26e2879c 100644 --- a/erpnext/setup/onboarding_step/create_a_supplier/create_a_supplier.json +++ b/erpnext/setup/onboarding_step/create_a_supplier/create_a_supplier.json @@ -9,7 +9,7 @@ "is_complete": 0, "is_single": 0, "is_skipped": 0, - "modified": "2023-05-16 12:55:08.610113", + "modified": "2023-05-19 15:32:55.069257", "modified_by": "Administrator", "name": "Create a Supplier", "owner": "Administrator", diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py index 46d6e9e7578..74927c779cc 100644 --- a/erpnext/stock/doctype/pick_list/pick_list.py +++ b/erpnext/stock/doctype/pick_list/pick_list.py @@ -29,6 +29,7 @@ class PickList(Document): self.validate_for_qty() def before_save(self): + self.update_status() self.set_item_locations() # set percentage picked in SO @@ -89,20 +90,20 @@ class PickList(Document): self.update_reference_qty() self.update_sales_order_picking_status() - def update_status(self, status=None, update_modified=True): + def update_status(self, status=None): if not status: if self.docstatus == 0: status = "Draft" elif self.docstatus == 1: - if self.status == "Draft": - status = "Open" - elif target_document_exists(self.name, self.purpose): + if target_document_exists(self.name, self.purpose): status = "Completed" + else: + status = "Open" elif self.docstatus == 2: status = "Cancelled" if status: - frappe.db.set_value("Pick List", self.name, "status", status, update_modified=update_modified) + self.db_set("status", status) def update_reference_qty(self): packed_items = [] diff --git a/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.js b/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.js index 7a170beec37..50a78a82588 100644 --- a/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.js +++ b/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.js @@ -33,5 +33,40 @@ frappe.query_reports["Stock and Account Value Comparison"] = { "fieldtype": "Date", "default": frappe.datetime.get_today(), }, - ] + ], + + get_datatable_options(options) { + return Object.assign(options, { + checkboxColumn: true, + }); + }, + + onload(report) { + report.page.add_inner_button(__("Create Reposting Entries"), function() { + let message = `
+

+ Reposting Entries will change the value of + accounts Stock In Hand, and Stock Expenses + in the Trial Balance report and will also change + the Balance Value in the Stock Balance report. +

+

Are you sure you want to create Reposting Entries?

+
+ `; + + frappe.confirm(__(message), () => { + let indexes = frappe.query_report.datatable.rowmanager.getCheckedRows(); + let selected_rows = indexes.map(i => frappe.query_report.data[i]); + + frappe.call({ + method: "erpnext.stock.report.stock_and_account_value_comparison.stock_and_account_value_comparison.create_reposting_entries", + args: { + rows: selected_rows, + company: frappe.query_report.get_filter_values().company + } + }); + + }); + }); + } }; diff --git a/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py b/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py index 106e877c4cd..b1da3ec1bd1 100644 --- a/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py +++ b/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py @@ -4,6 +4,7 @@ import frappe from frappe import _ +from frappe.utils import get_link_to_form, parse_json import erpnext from erpnext.accounts.utils import get_currency_precision, get_stock_accounts @@ -134,3 +135,35 @@ def get_columns(filters): "width": "120", }, ] + + +@frappe.whitelist() +def create_reposting_entries(rows, company): + if isinstance(rows, str): + rows = parse_json(rows) + + entries = [] + for row in rows: + row = frappe._dict(row) + + try: + doc = frappe.get_doc( + { + "doctype": "Repost Item Valuation", + "based_on": "Transaction", + "status": "Queued", + "voucher_type": row.voucher_type, + "voucher_no": row.voucher_no, + "posting_date": row.posting_date, + "company": company, + "allow_nagative_stock": 1, + } + ).submit() + + entries.append(get_link_to_form("Repost Item Valuation", doc.name)) + except frappe.DuplicateEntryError: + pass + + if entries: + entries = ", ".join(entries) + frappe.msgprint(_(f"Reposting entries created: {entries}")) diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js index 45289b1dab5..4bf008ac406 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js +++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js @@ -76,26 +76,14 @@ frappe.ui.form.on('Subcontracting Receipt', { } }); - let batch_no_field = frm.get_docfield("items", "batch_no"); + let batch_no_field = frm.get_docfield('items', 'batch_no'); if (batch_no_field) { batch_no_field.get_route_options_for_new_doc = function(row) { return { - "item": row.doc.item_code + 'item': row.doc.item_code } }; } - - frappe.db.get_single_value('Buying Settings', 'backflush_raw_materials_of_subcontract_based_on').then(val => { - if (val == 'Material Transferred for Subcontract') { - frm.fields_dict['supplied_items'].grid.grid_rows.forEach((grid_row) => { - grid_row.docfields.forEach((df) => { - if (df.fieldname == 'consumed_qty') { - df.read_only = 0; - } - }); - }); - } - }); }, refresh: (frm) => { @@ -157,6 +145,8 @@ frappe.ui.form.on('Subcontracting Receipt', { } }); }, __('Get Items From')); + + frm.fields_dict.supplied_items.grid.update_docfield_property('consumed_qty', 'read_only', frm.doc.__onload && frm.doc.__onload.backflush_based_on === 'BOM'); } }, diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py index 2c842622730..416f4f80a21 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py +++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py @@ -28,6 +28,14 @@ class SubcontractingReceipt(SubcontractingController): }, ] + def onload(self): + self.set_onload( + "backflush_based_on", + frappe.db.get_single_value( + "Buying Settings", "backflush_raw_materials_of_subcontract_based_on" + ), + ) + def update_status_updater_args(self): if cint(self.is_return): self.status_updater.extend(