diff --git a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json index c0afa7fe6910..ae91d795bb62 100644 --- a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json +++ b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json @@ -176,6 +176,7 @@ "fieldname": "received_qty", "fieldtype": "Float", "label": "Received Qty", + "no_copy": 1, "read_only": 1 }, { @@ -872,7 +873,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2022-10-12 03:37:29.032732", + "modified": "2023-07-02 18:39:41.495723", "modified_by": "Administrator", "module": "Accounts", "name": "Purchase Invoice Item", diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 451b405e00c4..7019621893ae 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -653,19 +653,6 @@ frappe.ui.form.on('Sales Invoice', { } } - // expense account - frm.fields_dict['items'].grid.get_field('expense_account').get_query = function(doc) { - if (erpnext.is_perpetual_inventory_enabled(doc.company)) { - return { - filters: { - 'report_type': 'Profit and Loss', - 'company': doc.company, - "is_group": 0 - } - } - } - } - // discount account frm.fields_dict['items'].grid.get_field('discount_account').get_query = function(doc) { return { diff --git a/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.py b/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.py index a5c464910de5..6a18cd958816 100644 --- a/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.py +++ b/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.py @@ -84,7 +84,7 @@ def get_data(conditions, filters): and po.docstatus = 1 {0} GROUP BY poi.name - ORDER BY po.transaction_date ASC + ORDER BY po.transaction_date ASC, poi.item_code ASC """.format( conditions ), diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index b05db329639b..a00911540ab7 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -173,7 +173,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ this.frm.set_query("expense_account", "items", function(doc) { return { filters: { - "company": doc.company + "company": doc.company, + "report_type": "Profit and Loss", + "is_group": 0 } }; }); diff --git a/erpnext/regional/doctype/datev_settings/datev_settings.json b/erpnext/regional/doctype/datev_settings/datev_settings.json index f60de4c8af42..e6a0005c66d5 100644 --- a/erpnext/regional/doctype/datev_settings/datev_settings.json +++ b/erpnext/regional/doctype/datev_settings/datev_settings.json @@ -14,7 +14,8 @@ "section_break_4", "account_number_length", "column_break_6", - "temporary_against_account_number" + "temporary_against_account_number", + "opening_against_account_number" ], "fields": [ { @@ -70,14 +71,23 @@ }, { "allow_in_quick_entry": 1, + "default": "9999", + "description": "Will be used as against account for all normal ledger entries", "fieldname": "temporary_against_account_number", "fieldtype": "Data", "label": "Temporary Against Account Number", "reqd": 1 + }, + { + "default": "9000", + "description": "Will be used as against account for opening ledger entries", + "fieldname": "opening_against_account_number", + "fieldtype": "Data", + "label": "Opening Against Account Number" } ], "links": [], - "modified": "2020-11-19 19:00:09.088816", + "modified": "2023-06-30 00:56:59.556731", "modified_by": "Administrator", "module": "Regional", "name": "DATEV Settings", diff --git a/erpnext/regional/doctype/datev_settings/datev_settings.py b/erpnext/regional/doctype/datev_settings/datev_settings.py index 686a93e529d8..7b33dc78deca 100644 --- a/erpnext/regional/doctype/datev_settings/datev_settings.py +++ b/erpnext/regional/doctype/datev_settings/datev_settings.py @@ -1,10 +1,26 @@ # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt - -# import frappe +from frappe import _, throw from frappe.model.document import Document class DATEVSettings(Document): - pass + def validate(self): + if ( + self.temporary_against_account_number + and len(self.temporary_against_account_number) != self.account_number_length + ): + throw( + _("Temporary Against Account Number must be {0} digits long").format( + self.account_number_length + ) + ) + + if ( + self.opening_against_account_number + and len(self.opening_against_account_number) != self.account_number_length + ): + throw( + _("Opening Against Account Number must be {0} digits long").format(self.account_number_length) + ) diff --git a/erpnext/regional/report/datev/datev.py b/erpnext/regional/report/datev/datev.py index fb2f1cdcf055..c97c609a856d 100644 --- a/erpnext/regional/report/datev/datev.py +++ b/erpnext/regional/report/datev/datev.py @@ -132,8 +132,12 @@ def execute(filters=None): """Entry point for frappe.""" data = [] if filters and validate(filters): - fn = "temporary_against_account_number" - filters[fn] = frappe.get_value("DATEV Settings", filters.get("company"), fn) + temp, opening = frappe.get_value( + "DATEV Settings", + filters.get("company"), + ["temporary_against_account_number", "opening_against_account_number"], + ) + filters.update({"against_account": temp, "opening_account": opening or temp}) data = get_transactions(filters, as_dict=0) return COLUMNS, data @@ -315,7 +319,7 @@ def run_query(filters, extra_fields, extra_joins, extra_filters, as_dict=1): acc.account_number as 'Konto', /* against number or, if empty, party against number */ - %(temporary_against_account_number)s as 'Gegenkonto (ohne BU-Schlüssel)', + CASE gl.is_opening when 'Yes' then %(opening_account)s else %(against_account)s end as 'Gegenkonto (ohne BU-Schlüssel)', '' as 'BU-Schlüssel', @@ -530,18 +534,22 @@ def download_datev_csv(filters): filters = json.loads(filters) validate(filters) - company = filters.get("company") + company = filters.get("company") fiscal_year = get_fiscal_year(date=filters.get("from_date"), company=company) - filters["fiscal_year_start"] = fiscal_year[1] - - # set chart of accounts used coa = frappe.get_value("Company", company, "chart_of_accounts") - filters["skr"] = "04" if "SKR04" in coa else ("03" if "SKR03" in coa else "") - datev_settings = frappe.get_doc("DATEV Settings", company) - filters["account_number_length"] = datev_settings.account_number_length - filters["temporary_against_account_number"] = datev_settings.temporary_against_account_number + + filters.update( + { + "fiscal_year_start": fiscal_year[1], + "skr": "04" if "SKR04" in coa else ("03" if "SKR03" in coa else ""), + "account_number_length": datev_settings.account_number_length, + "against_account": datev_settings.temporary_against_account_number, + "opening_account": datev_settings.opening_against_account_number + or datev_settings.temporary_against_account_number, + } + ) transactions = get_transactions(filters) account_names = get_account_names(filters) diff --git a/erpnext/regional/report/datev/test_datev.py b/erpnext/regional/report/datev/test_datev.py index 6e6847b896b9..0f3b529a6b3b 100644 --- a/erpnext/regional/report/datev/test_datev.py +++ b/erpnext/regional/report/datev/test_datev.py @@ -139,7 +139,9 @@ def make_datev_settings(company): "client": company.name, "client_number": "12345", "consultant_number": "67890", + "account_number_length": 4, "temporary_against_account_number": "9999", + "opening_against_account_number": "9000", } ).insert() @@ -152,7 +154,8 @@ def setUp(self): "company": self.company.name, "from_date": today(), "to_date": today(), - "temporary_against_account_number": "9999", + "against_account": "9999", + "opening_account": "9000", } make_datev_settings(self.company) diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index 197d4278e940..ba28b6302f3e 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -1849,6 +1849,121 @@ def test_internal_pr_reference(self): pr.items[0].delivery_note_item = delivery_note_item pr.save() + def test_purchase_receipt_with_backdated_landed_cost_voucher(self): + from erpnext.controllers.sales_and_purchase_return import make_return_doc + from erpnext.stock.doctype.landed_cost_voucher.test_landed_cost_voucher import ( + create_landed_cost_voucher, + ) + from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry + + item_code = "_Test Purchase Item With Landed Cost" + create_item(item_code) + + warehouse = create_warehouse("_Test Purchase Warehouse With Landed Cost") + warehouse1 = create_warehouse("_Test Purchase Warehouse With Landed Cost 1") + warehouse2 = create_warehouse("_Test Purchase Warehouse With Landed Cost 2") + warehouse3 = create_warehouse("_Test Purchase Warehouse With Landed Cost 3") + + pr = make_purchase_receipt( + item_code=item_code, + warehouse=warehouse, + posting_date=add_days(today(), -10), + posting_time="10:59:59", + qty=100, + rate=275.00, + ) + + pr_return = make_return_doc("Purchase Receipt", pr.name) + pr_return.posting_date = add_days(today(), -9) + pr_return.items[0].qty = 2 * -1 + pr_return.items[0].received_qty = 2 * -1 + pr_return.submit() + + ste1 = make_stock_entry( + purpose="Material Transfer", + posting_date=add_days(today(), -8), + source=warehouse, + target=warehouse1, + item_code=item_code, + qty=20, + company=pr.company, + ) + + ste1.reload() + self.assertEqual(ste1.items[0].valuation_rate, 275.00) + + ste2 = make_stock_entry( + purpose="Material Transfer", + posting_date=add_days(today(), -7), + source=warehouse, + target=warehouse2, + item_code=item_code, + qty=20, + company=pr.company, + ) + + ste2.reload() + self.assertEqual(ste2.items[0].valuation_rate, 275.00) + + ste3 = make_stock_entry( + purpose="Material Transfer", + posting_date=add_days(today(), -6), + source=warehouse, + target=warehouse3, + item_code=item_code, + qty=20, + company=pr.company, + ) + + ste3.reload() + self.assertEqual(ste3.items[0].valuation_rate, 275.00) + + ste4 = make_stock_entry( + purpose="Material Transfer", + posting_date=add_days(today(), -5), + source=warehouse1, + target=warehouse, + item_code=item_code, + qty=20, + company=pr.company, + ) + + ste4.reload() + self.assertEqual(ste4.items[0].valuation_rate, 275.00) + + ste5 = make_stock_entry( + purpose="Material Transfer", + posting_date=add_days(today(), -4), + source=warehouse, + target=warehouse1, + item_code=item_code, + qty=20, + company=pr.company, + ) + + ste5.reload() + self.assertEqual(ste5.items[0].valuation_rate, 275.00) + + create_landed_cost_voucher("Purchase Receipt", pr.name, pr.company, charges=2500 * -1) + + pr.reload() + valuation_rate = pr.items[0].valuation_rate + + ste1.reload() + self.assertEqual(ste1.items[0].valuation_rate, valuation_rate) + + ste2.reload() + self.assertEqual(ste2.items[0].valuation_rate, valuation_rate) + + ste3.reload() + self.assertEqual(ste3.items[0].valuation_rate, valuation_rate) + + ste4.reload() + self.assertEqual(ste4.items[0].valuation_rate, valuation_rate) + + ste5.reload() + self.assertEqual(ste5.items[0].valuation_rate, valuation_rate) + def prepare_data_for_internal_transfer(): from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json index 3d30533a5e70..50bbc380594a 100644 --- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json +++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json @@ -204,6 +204,7 @@ "fieldname": "received_qty", "fieldtype": "Float", "label": "Received Quantity", + "no_copy": 1, "oldfieldname": "received_qty", "oldfieldtype": "Currency", "print_hide": 1, @@ -993,7 +994,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2022-10-12 03:37:59.516609", + "modified": "2023-07-02 18:40:48.152637", "modified_by": "Administrator", "module": "Stock", "name": "Purchase Receipt Item", @@ -1004,4 +1005,4 @@ "sort_field": "modified", "sort_order": "DESC", "states": [] -} \ No newline at end of file +} diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index 2f876cddac8d..3ca513a46443 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -502,6 +502,7 @@ def get_dependent_entries_to_fix(self, entries_to_fix, sle): def update_distinct_item_warehouses(self, dependant_sle): key = (dependant_sle.item_code, dependant_sle.warehouse) val = frappe._dict({"sle": dependant_sle}) + if key not in self.distinct_item_warehouses: self.distinct_item_warehouses[key] = val self.new_items_found = True @@ -513,6 +514,9 @@ def update_distinct_item_warehouses(self, dependant_sle): val.sle_changed = True self.distinct_item_warehouses[key] = val self.new_items_found = True + elif self.distinct_item_warehouses[key].get("reposting_status"): + self.distinct_item_warehouses[key] = val + self.new_items_found = True def process_sle(self, sle): from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos @@ -1154,6 +1158,8 @@ def get_sle_by_voucher_detail_no(voucher_detail_no, excluded_sle=None): [ "item_code", "warehouse", + "actual_qty", + "qty_after_transaction", "posting_date", "posting_time", "timestamp(posting_date, posting_time) as timestamp", diff --git a/erpnext/translations/de.csv b/erpnext/translations/de.csv index 552a968f9bbf..1400749a17fc 100644 --- a/erpnext/translations/de.csv +++ b/erpnext/translations/de.csv @@ -9896,3 +9896,11 @@ Total Equity,Eigenkapital, Warehouse wise Stock Value,Warenwert nach Lager, Discount Validity,Frist für den Rabatt, Discount Validity Based On,Frist für den Rabatt berechnet sich nach, +Account Number Length,Kontonummer Länge, +Temporary Against Account Number,Temporäre Gegenkontonummer, +Change DATEV Settings,DATEV-Einstellungen ändern, +Opening Against Account Number,Gegenkontonummer für Eröffnungsbuchungen, +Will be used as against account for all normal ledger entries,Wird als Gegenkonto für alle normalen Buchungen verwendet, +Will be used as against account for opening ledger entries,Wird als Gegenkonto für alle Eröffnungsbuchungen verwendet, +Temporary Against Account Number must be {0} digits long,Temporäre Gegenkontonummer muss {0} Ziffern lang sein, +Opening Against Account Number must be {0} digits long,Gegenkontonummer für Eröffnungsbuchungen muss {0} Ziffern lang sein, diff --git a/erpnext/translations/nl.csv b/erpnext/translations/nl.csv index fbadc02327fe..7d7722e2b0ed 100644 --- a/erpnext/translations/nl.csv +++ b/erpnext/translations/nl.csv @@ -875,7 +875,7 @@ Donor,schenker, Donor Type information.,Donor Type informatie., Donor information.,Donorinformatie., Download JSON,JSON downloaden, -Draft,Droogte, +Draft,Concept, Drop Ship,Drop Ship, Drug,drug, Due / Reference Date cannot be after {0},Verval- / Referentiedatum kan niet na {0} zijn, @@ -4280,7 +4280,7 @@ Failed to setup defaults for country {0}. Please contact support@erpnext.com,Kan Row #{0}: Item {1} is not a Serialized/Batched Item. It cannot have a Serial No/Batch No against it.,Rij # {0}: artikel {1} is geen geserialiseerd / batch artikel. Het kan geen serienummer / batchnummer hebben., Please set {0},Stel {0} in, Please set {0},Stel {0} in,supplier -Draft,Droogte,"docstatus,=,0" +Draft,Concept,"docstatus,=,0" Cancelled,Geannuleerd,"docstatus,=,2" Please setup Instructor Naming System in Education > Education Settings,Stel het instructeursysteem in onder onderwijs> onderwijsinstellingen, Please set Naming Series for {0} via Setup > Settings > Naming Series,Stel Naming Series in op {0} via Instellingen> Instellingen> Naming Series, @@ -8192,7 +8192,7 @@ Actual Batch Quantity,Werkelijke batchhoeveelheid, Prevdoc DocType,Prevdoc DocType, Parent Detail docname,Bovenliggende Detail docname, "Generate packing slips for packages to be delivered. Used to notify package number, package contents and its weight.","Genereren van pakbonnen voor pakketten te leveren. Gebruikt voor pakket nummer, inhoud van de verpakking en het gewicht te melden.", -Indicates that the package is a part of this delivery (Only Draft),Geeft aan dat het pakket een onderdeel is van deze levering (alleen ontwerp), +Indicates that the package is a part of this delivery (Only Draft),Geeft aan dat het pakket een onderdeel is van deze levering (alleen concept), MAT-PAC-.YYYY.-,MAT-PAC-.YYYY.-, From Package No.,Van Pakket No, Identification of the package for the delivery (for print),Identificatie van het pakket voor de levering (voor afdrukken), diff --git a/requirements.txt b/requirements.txt index 2531dec8ba18..4098462cd3b7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ # frappe # https://github.com/frappe/frappe is installed during bench-init gocardless-pro~=1.22.0 googlemaps # used in ERPNext, but dependency is defined in Frappe -pandas~=1.1.5 +pandas>=1.1.5,<2.0.0 plaid-python~=7.2.1 pycountry~=20.7.3 PyGithub~=1.54.1 @@ -10,4 +10,4 @@ python-youtube~=0.8.0 taxjar~=1.9.2 tweepy~=3.10.0 Unidecode~=1.2.0 -redisearch==2.0.0 \ No newline at end of file +redisearch==2.0.0